msm: mdss: Adding support for destination scaler
Destination scaling is a new hardware feature in MSM mdss 3xx hw. When user mode enabled the destination upscaling, framebuffer will get upscaled and then transmitted to the primary panel. CRs-Fixed: 988990 Change-Id: I19aa5983316bec4a87811c8aa8b54f770001c45f Signed-off-by: Benjamin Chan <bkchan@codeaurora.org> Signed-off-by: Naseer Ahmed <naseer@codeaurora.org>
This commit is contained in:
parent
e215162bb2
commit
687db9c75e
9 changed files with 713 additions and 68 deletions
|
@ -396,6 +396,10 @@ Optional properties:
|
|||
to mdp block. Xin id property is not valid for mdp
|
||||
internal blocks like ctl, lm, dspp. It should set
|
||||
to 0xff for such blocks.
|
||||
- qcom,max-dest-scaler-input-width: This 32 bit value provides
|
||||
maximum width to the input of destination scaler.
|
||||
- qcom,max-dest-scaler-output-width: This 32 bit value provides
|
||||
maximum width to the output of destination scaler.
|
||||
|
||||
Fudge Factors: Fudge factors are used to boost demand for
|
||||
resources like bus bandswidth, clk rate etc. to
|
||||
|
@ -691,6 +695,8 @@ Example:
|
|||
|
||||
qcom,max-mixer-width = <2048>;
|
||||
qcom,max-pipe-width = <2048>;
|
||||
qcom,max-dest-scaler-input-width = <2048>;
|
||||
qcom,max-dest-scaler-output-width = <2560>;
|
||||
qcom,max-clk-rate = <320000000>;
|
||||
qcom,vbif-settings = <0x0004 0x00000001>,
|
||||
<0x00D8 0x00000707>;
|
||||
|
|
|
@ -503,6 +503,10 @@ struct mdss_data_type {
|
|||
u32 bcolor1;
|
||||
u32 bcolor2;
|
||||
struct mdss_scaler_block *scaler_off;
|
||||
|
||||
u32 max_dest_scaler_input_width;
|
||||
u32 max_dest_scaler_output_width;
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
};
|
||||
|
||||
extern struct mdss_data_type *mdss_res;
|
||||
|
|
|
@ -116,6 +116,17 @@ static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
|
|||
int event, void *arg);
|
||||
static void mdss_fb_set_mdp_sync_pt_threshold(struct msm_fb_data_type *mfd,
|
||||
int type);
|
||||
|
||||
static inline void __user *to_user_ptr(uint64_t address)
|
||||
{
|
||||
return (void __user *)(uintptr_t)address;
|
||||
}
|
||||
|
||||
static inline uint64_t __user to_user_u64(void *ptr)
|
||||
{
|
||||
return (uint64_t)((uintptr_t)ptr);
|
||||
}
|
||||
|
||||
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
|
||||
{
|
||||
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)data;
|
||||
|
@ -4269,6 +4280,101 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int __mdss_fb_copy_destscaler_data(struct fb_info *info,
|
||||
struct mdp_layer_commit *commit)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
u32 data_size;
|
||||
struct mdp_destination_scaler_data __user *ds_data_user;
|
||||
struct mdp_destination_scaler_data *ds_data = NULL;
|
||||
void __user *scale_data_user;
|
||||
struct mdp_scale_data_v2 *scale_data = NULL;
|
||||
struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
|
||||
struct mdss_data_type *mdata;
|
||||
|
||||
if (!mfd || !mfd->mdp.private1) {
|
||||
pr_err("mfd is NULL or operation not permitted\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
mdata = mfd_to_mdata(mfd);
|
||||
if (!mdata) {
|
||||
pr_err("mdata is NULL or not initialized\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (commit->commit_v1.dest_scaler_cnt >
|
||||
mdata->scaler_off->ndest_scalers) {
|
||||
pr_err("Commit destination scaler cnt larger than HW setting, commit cnt=%d\n",
|
||||
commit->commit_v1.dest_scaler_cnt);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ds_data_user = (struct mdp_destination_scaler_data *)
|
||||
commit->commit_v1.dest_scaler;
|
||||
data_size = commit->commit_v1.dest_scaler_cnt *
|
||||
sizeof(struct mdp_destination_scaler_data);
|
||||
ds_data = kzalloc(data_size, GFP_KERNEL);
|
||||
if (!ds_data) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = copy_from_user(ds_data, ds_data_user, data_size);
|
||||
if (ret) {
|
||||
pr_err("dest scaler data copy from user failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
commit->commit_v1.dest_scaler = ds_data;
|
||||
|
||||
for (i = 0; i < commit->commit_v1.dest_scaler_cnt; i++) {
|
||||
scale_data = NULL;
|
||||
|
||||
if (ds_data[i].scale) {
|
||||
scale_data_user = to_user_ptr(ds_data[i].scale);
|
||||
data_size = sizeof(struct mdp_scale_data_v2);
|
||||
|
||||
scale_data = kzalloc(data_size, GFP_KERNEL);
|
||||
if (!scale_data) {
|
||||
ds_data[i].scale = 0;
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ds_data[i].scale = to_user_u64(scale_data);
|
||||
}
|
||||
|
||||
if (scale_data && (ds_data[i].flags &
|
||||
(MDP_DESTSCALER_SCALE_UPDATE |
|
||||
MDP_DESTSCALER_ENHANCER_UPDATE))) {
|
||||
ret = copy_from_user(scale_data, scale_data_user,
|
||||
data_size);
|
||||
if (ret) {
|
||||
pr_err("scale data copy from user failed\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
err:
|
||||
if (ds_data) {
|
||||
for (i = 0; i < commit->commit_v1.dest_scaler_cnt; i++) {
|
||||
scale_data = to_user_ptr(ds_data[i].scale);
|
||||
kfree(scale_data);
|
||||
}
|
||||
kfree(ds_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mdss_fb_atomic_commit_ioctl(struct fb_info *info,
|
||||
unsigned long *argp, struct file *file)
|
||||
{
|
||||
|
@ -4279,6 +4385,8 @@ static int mdss_fb_atomic_commit_ioctl(struct fb_info *info,
|
|||
struct mdp_input_layer __user *input_layer_list;
|
||||
struct mdp_output_layer *output_layer = NULL;
|
||||
struct mdp_output_layer __user *output_layer_user;
|
||||
struct mdp_destination_scaler_data *ds_data = NULL;
|
||||
struct mdp_destination_scaler_data __user *ds_data_user;
|
||||
|
||||
ret = copy_from_user(&commit, argp, sizeof(struct mdp_layer_commit));
|
||||
if (ret) {
|
||||
|
@ -4356,6 +4464,16 @@ static int mdss_fb_atomic_commit_ioctl(struct fb_info *info,
|
|||
}
|
||||
}
|
||||
|
||||
ds_data_user = commit.commit_v1.dest_scaler;
|
||||
if (ds_data_user) {
|
||||
ret = __mdss_fb_copy_destscaler_data(info, &commit);
|
||||
if (ret) {
|
||||
pr_err("copy dest scaler failed\n");
|
||||
goto err;
|
||||
}
|
||||
ds_data = commit.commit_v1.dest_scaler;
|
||||
}
|
||||
|
||||
ATRACE_BEGIN("ATOMIC_COMMIT");
|
||||
ret = mdss_fb_atomic_commit(info, &commit, file);
|
||||
if (ret)
|
||||
|
@ -4372,6 +4490,7 @@ static int mdss_fb_atomic_commit_ioctl(struct fb_info *info,
|
|||
|
||||
commit.commit_v1.input_layers = input_layer_list;
|
||||
commit.commit_v1.output_layer = output_layer_user;
|
||||
commit.commit_v1.dest_scaler = ds_data_user;
|
||||
rc = copy_to_user(argp, &commit,
|
||||
sizeof(struct mdp_layer_commit));
|
||||
if (rc) {
|
||||
|
@ -4397,6 +4516,11 @@ err:
|
|||
}
|
||||
kfree(layer_list);
|
||||
kfree(output_layer);
|
||||
if (ds_data) {
|
||||
for (i = 0; i < commit.commit_v1.dest_scaler_cnt; i++)
|
||||
kfree(to_user_ptr(ds_data[i].scale));
|
||||
kfree(ds_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -1940,9 +1940,10 @@ static u32 mdss_mdp_res_init(struct mdss_data_type *mdata)
|
|||
static u32 mdss_mdp_scaler_init(struct mdss_data_type *mdata,
|
||||
struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
int ret = -EINVAL;
|
||||
struct device_node *node;
|
||||
u32 prop_val;
|
||||
int len = 0;
|
||||
|
||||
if (!dev)
|
||||
return -EPERM;
|
||||
|
@ -1978,8 +1979,7 @@ static u32 mdss_mdp_scaler_init(struct mdss_data_type *mdata,
|
|||
}
|
||||
mdata->scaler_off->vig_scaler_lut_off = prop_val;
|
||||
mdata->scaler_off->has_dest_scaler =
|
||||
of_property_read_bool(mdata->pdev->dev.of_node,
|
||||
"qcom,mdss-has-dest-scaler");
|
||||
of_property_read_bool(node, "qcom,mdss-has-dest-scaler");
|
||||
if (mdata->scaler_off->has_dest_scaler) {
|
||||
ret = of_property_read_u32(node,
|
||||
"qcom,mdss-dest-block-off",
|
||||
|
@ -1991,40 +1991,65 @@ static u32 mdss_mdp_scaler_init(struct mdss_data_type *mdata,
|
|||
}
|
||||
mdata->scaler_off->dest_base = mdata->mdss_io.base +
|
||||
prop_val;
|
||||
mdata->scaler_off->ndest_scalers =
|
||||
mdss_mdp_parse_dt_prop_len(mdata->pdev,
|
||||
"qcom,mdss-dest-scalers-off");
|
||||
|
||||
if (!of_find_property(node, "qcom,mdss-dest-scaler-off", &len)
|
||||
|| (len < 1)) {
|
||||
pr_err("find property %s failed ret %d\n",
|
||||
"qcom,mdss-dest-scaler-off", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
mdata->scaler_off->ndest_scalers = len/sizeof(u32);
|
||||
|
||||
mdata->scaler_off->dest_scaler_off =
|
||||
devm_kzalloc(&mdata->pdev->dev, sizeof(u32) *
|
||||
devm_kzalloc(dev, sizeof(u32) *
|
||||
mdata->scaler_off->ndest_scalers,
|
||||
GFP_KERNEL);
|
||||
if (!mdata->scaler_off->dest_scaler_off) {
|
||||
kfree(mdata->scaler_off->dest_scaler_off);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = mdss_mdp_parse_dt_handler(mdata->pdev,
|
||||
ret = of_property_read_u32_array(node,
|
||||
"qcom,mdss-dest-scaler-off",
|
||||
mdata->scaler_off->dest_scaler_off,
|
||||
mdata->scaler_off->ndest_scalers);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
|
||||
mdata->scaler_off->dest_scaler_lut_off =
|
||||
devm_kzalloc(&mdata->pdev->dev, sizeof(u32) *
|
||||
devm_kzalloc(dev, sizeof(u32) *
|
||||
mdata->scaler_off->ndest_scalers,
|
||||
GFP_KERNEL);
|
||||
if (!mdata->scaler_off->dest_scaler_lut_off) {
|
||||
kfree(mdata->scaler_off->dest_scaler_lut_off);
|
||||
return -ENOMEM;
|
||||
}
|
||||
ret = mdss_mdp_parse_dt_handler(mdata->pdev,
|
||||
"qcom,mdss-dest-scalers-lut-off",
|
||||
ret = of_property_read_u32_array(node,
|
||||
"qcom,mdss-dest-scaler-lut-off",
|
||||
mdata->scaler_off->dest_scaler_lut_off,
|
||||
mdata->scaler_off->ndest_scalers);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
return ret;
|
||||
|
||||
ret = of_property_read_u32(dev->of_node,
|
||||
"qcom,max-dest-scaler-input-width",
|
||||
&mdata->max_dest_scaler_input_width);
|
||||
if (ret) {
|
||||
pr_debug("read property %s failed ret %d\n",
|
||||
"qcom,max-dest-scaler-input-width",
|
||||
ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
ret = of_property_read_u32(dev->of_node,
|
||||
"qcom,max-dest-scaler-output-width",
|
||||
&mdata->max_dest_scaler_output_width);
|
||||
if (ret) {
|
||||
pr_debug("read property %s failed ret %d\n",
|
||||
"qcom,max-dest-scaler-output-width",
|
||||
ret);
|
||||
}
|
||||
|
||||
ret = mdss_mdp_ds_addr_setup(mdata);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2322,6 +2347,16 @@ ssize_t mdss_mdp_show_capabilities(struct device *dev,
|
|||
if (mdata->clk_factor.numer)
|
||||
SPRINT("clk_fudge_factor=%u,%u\n", mdata->clk_factor.numer,
|
||||
mdata->clk_factor.denom);
|
||||
if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map)) {
|
||||
SPRINT("max_dest_scaler_input_width=%u\n",
|
||||
mdata->max_dest_scaler_input_width);
|
||||
SPRINT("max_dest_scaler_output_width=%u\n",
|
||||
mdata->max_dest_scaler_output_width);
|
||||
SPRINT("dest_scaler_count=%u\n",
|
||||
mdata->scaler_off->ndest_scalers);
|
||||
SPRINT("max_dest_scale_up=%u\n", MAX_UPSCALE_RATIO);
|
||||
}
|
||||
|
||||
SPRINT("features=");
|
||||
if (mdata->has_bwc)
|
||||
SPRINT(" bwc");
|
||||
|
|
|
@ -86,6 +86,36 @@
|
|||
|
||||
#define MAX_LAYER_COUNT 0xC
|
||||
|
||||
/**
|
||||
* Destination Scaler control flags setting
|
||||
*
|
||||
* @DS_ENABLE: Setting the bit indicates Destination Scaler is enabled. Unset
|
||||
* the bit indicates Destination Scaler is disable.
|
||||
* @DS_DUAL_MODE: Setting the bit indicates Left and Right Destination Scaler
|
||||
* are operated in Dual mode.
|
||||
* @DS_LEFT: Setting the bit indicates current Destination Scaler is assigned
|
||||
* with the Left LM. DS_LEFT and DS_DUAL_MODE can be used
|
||||
* together.
|
||||
* @DS_RIGHT: Setting the bit indicates current Destination Scaler is assigned
|
||||
* with the Right LM. DS_RIGHT and DS_DUAL_MODE can be used
|
||||
* together.
|
||||
* @DS_SCALE_UPDATE: Setting the bit indicates current Destination Scaler
|
||||
* QSEED3 parameters needs to be updated.
|
||||
* @DS_ENHANCER_UPDATE: Setting this bit indicates current Desitnation Scaler
|
||||
* QSEED3 Detial enhancer parameters need to be updated.
|
||||
*/
|
||||
#define DS_ENABLE BIT(0)
|
||||
#define DS_DUAL_MODE BIT(1)
|
||||
#define DS_LEFT BIT(2)
|
||||
#define DS_RIGHT BIT(3)
|
||||
#define DS_SCALE_UPDATE BIT(4)
|
||||
#define DS_ENHANCER_UPDATE BIT(5)
|
||||
|
||||
/**
|
||||
* Destination Scaler DUAL mode overfetch pixel count
|
||||
*/
|
||||
#define MDSS_MDP_DS_OVERFETCH_SIZE 5
|
||||
|
||||
/* hw cursor can only be setup in highest mixer stage */
|
||||
#define HW_CURSOR_STAGE(mdata) \
|
||||
(((mdata)->max_target_zorder + MDSS_MDP_STAGE_0) - 1)
|
||||
|
@ -310,6 +340,25 @@ struct mdss_mdp_writeback {
|
|||
u8 supported_output_formats[BITS_TO_BYTES(MDP_IMGTYPE_LIMIT1)];
|
||||
};
|
||||
|
||||
/*
|
||||
* Destination scaler info
|
||||
* destination scaler is hard wired to DSPP0/1 and LM0/1
|
||||
* Input dimension is always matching to LM output dimension
|
||||
* Output dimension is the Panel/WB dimension
|
||||
* In bypass mode (off), input and output dimension is the same
|
||||
*/
|
||||
struct mdss_mdp_destination_scaler {
|
||||
u32 num;
|
||||
char __iomem *ds_base;
|
||||
char __iomem *scaler_base;
|
||||
char __iomem *lut_base;
|
||||
u16 src_width;
|
||||
u16 src_height;
|
||||
u32 flags;
|
||||
struct mdp_scale_data_v2 scaler;
|
||||
};
|
||||
|
||||
|
||||
struct mdss_mdp_ctl_intfs_ops {
|
||||
int (*start_fnc)(struct mdss_mdp_ctl *ctl);
|
||||
int (*stop_fnc)(struct mdss_mdp_ctl *ctl, int panel_power_state);
|
||||
|
@ -462,6 +511,8 @@ struct mdss_mdp_mixer {
|
|||
char __iomem *base;
|
||||
char __iomem *dspp_base;
|
||||
char __iomem *pingpong_base;
|
||||
/* Destination Scaler is hard wired to each mixer */
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
u8 type;
|
||||
u8 params_changed;
|
||||
u16 width;
|
||||
|
@ -1049,12 +1100,63 @@ static inline int mdss_mdp_line_buffer_width(void)
|
|||
return MAX_LINE_BUFFER_WIDTH;
|
||||
}
|
||||
|
||||
static inline int is_dest_scaling_enable(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
return (test_bit(MDSS_CAPS_DEST_SCALER, mdss_res->mdss_caps_map) &&
|
||||
mixer && mixer->ds && (mixer->ds->flags & DS_ENABLE));
|
||||
}
|
||||
|
||||
static inline u32 get_ds_input_width(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
|
||||
ds = mixer->ds;
|
||||
if (ds)
|
||||
return ds->src_width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 get_ds_input_height(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
|
||||
ds = mixer->ds;
|
||||
if (ds)
|
||||
return ds->src_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 get_ds_output_width(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
|
||||
ds = mixer->ds;
|
||||
if (ds)
|
||||
return ds->scaler.dst_width;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 get_ds_output_height(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
|
||||
ds = mixer->ds;
|
||||
if (ds)
|
||||
return ds->scaler.dst_height;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 get_panel_yres(struct mdss_panel_info *pinfo)
|
||||
{
|
||||
u32 yres;
|
||||
|
||||
yres = pinfo->yres + pinfo->lcdc.border_top +
|
||||
pinfo->lcdc.border_bottom;
|
||||
|
||||
return yres;
|
||||
}
|
||||
|
||||
|
@ -1064,6 +1166,7 @@ static inline u32 get_panel_xres(struct mdss_panel_info *pinfo)
|
|||
|
||||
xres = pinfo->xres + pinfo->lcdc.border_left +
|
||||
pinfo->lcdc.border_right;
|
||||
|
||||
return xres;
|
||||
}
|
||||
|
||||
|
@ -1653,6 +1756,7 @@ int mdss_mdp_ctl_addr_setup(struct mdss_data_type *mdata, u32 *ctl_offsets,
|
|||
u32 len);
|
||||
int mdss_mdp_wb_addr_setup(struct mdss_data_type *mdata,
|
||||
u32 num_wb, u32 num_intf_wb);
|
||||
int mdss_mdp_ds_addr_setup(struct mdss_data_type *mdata);
|
||||
|
||||
void mdss_mdp_pipe_clk_force_off(struct mdss_mdp_pipe *pipe);
|
||||
int mdss_mdp_pipe_fetch_halt(struct mdss_mdp_pipe *pipe, bool is_recovery);
|
||||
|
|
|
@ -1205,6 +1205,7 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
|
|||
struct mdss_panel_info *pinfo = NULL;
|
||||
int fps = DEFAULT_FRAME_RATE;
|
||||
u32 v_total = 0, bpp = MDSS_MDP_WB_OUTPUT_BPP;
|
||||
u32 h_total = 0;
|
||||
int i;
|
||||
u32 max_clk_rate = 0;
|
||||
u64 bw_overlap_max = 0;
|
||||
|
@ -1235,6 +1236,10 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
|
|||
fps = mdss_panel_get_framerate(pinfo);
|
||||
v_total = mdss_panel_get_vtotal(pinfo);
|
||||
}
|
||||
if (is_dest_scaling_enable(mixer))
|
||||
h_total = get_ds_output_width(mixer);
|
||||
else
|
||||
h_total = mixer->width;
|
||||
} else {
|
||||
v_total = mixer->height;
|
||||
}
|
||||
|
@ -1248,7 +1253,11 @@ static void mdss_mdp_perf_calc_mixer(struct mdss_mdp_mixer *mixer,
|
|||
pinfo = NULL;
|
||||
}
|
||||
|
||||
perf->mdp_clk_rate = mixer->width * v_total * fps;
|
||||
/*
|
||||
* with destination scaling, the increase of clock
|
||||
* calculation should depends on output of size of DS setting.
|
||||
*/
|
||||
perf->mdp_clk_rate = h_total * v_total * fps;
|
||||
perf->mdp_clk_rate =
|
||||
mdss_mdp_clk_fudge_factor(mixer, perf->mdp_clk_rate);
|
||||
|
||||
|
@ -3429,8 +3438,15 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl)
|
|||
|
||||
split_ctl = mdss_mdp_get_split_ctl(ctl);
|
||||
|
||||
if (is_dest_scaling_enable(ctl->mixer_left)) {
|
||||
width = get_ds_input_width(ctl->mixer_left);
|
||||
height = get_ds_input_height(ctl->mixer_left);
|
||||
if (ctl->panel_data->next && is_pingpong_split(ctl->mfd))
|
||||
width *= 2;
|
||||
} else {
|
||||
width = get_panel_width(ctl);
|
||||
height = get_panel_yres(pinfo);
|
||||
}
|
||||
|
||||
max_mixer_width = ctl->mdata->max_mixer_width;
|
||||
|
||||
|
@ -3593,8 +3609,13 @@ int mdss_mdp_ctl_reconfig(struct mdss_mdp_ctl *ctl,
|
|||
ctl->opmode |= (ctl->intf_num << 4);
|
||||
|
||||
skip_intf_reconfig:
|
||||
if (is_dest_scaling_enable(ctl->mixer_left)) {
|
||||
ctl->width = get_ds_input_width(ctl->mixer_left);
|
||||
ctl->height = get_ds_input_height(ctl->mixer_left);
|
||||
} else {
|
||||
ctl->width = get_panel_xres(&pdata->panel_info);
|
||||
ctl->height = get_panel_yres(&pdata->panel_info);
|
||||
}
|
||||
if (ctl->mixer_left) {
|
||||
ctl->mixer_left->width = ctl->width;
|
||||
ctl->mixer_left->height = ctl->height;
|
||||
|
@ -3741,11 +3762,6 @@ int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
sctl->width = get_panel_xres(&pdata->panel_info);
|
||||
sctl->height = get_panel_yres(&pdata->panel_info);
|
||||
|
||||
sctl->roi = (struct mdss_rect){0, 0, sctl->width, sctl->height};
|
||||
|
||||
if (!ctl->mixer_left) {
|
||||
ctl->mixer_left = mdss_mdp_mixer_alloc(ctl,
|
||||
MDSS_MDP_MIXER_TYPE_INTF,
|
||||
|
@ -3764,6 +3780,16 @@ int mdss_mdp_ctl_split_display_setup(struct mdss_mdp_ctl *ctl,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (is_dest_scaling_enable(mixer)) {
|
||||
sctl->width = get_ds_input_width(mixer);
|
||||
sctl->height = get_ds_input_height(mixer);
|
||||
} else {
|
||||
sctl->width = get_panel_xres(&pdata->panel_info);
|
||||
sctl->height = get_panel_yres(&pdata->panel_info);
|
||||
}
|
||||
|
||||
sctl->roi = (struct mdss_rect){0, 0, sctl->width, sctl->height};
|
||||
|
||||
mixer->is_right_mixer = true;
|
||||
mixer->width = sctl->width;
|
||||
mixer->height = sctl->height;
|
||||
|
@ -4942,6 +4968,43 @@ int mdss_mdp_wb_addr_setup(struct mdss_data_type *mdata,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_ds_addr_setup(struct mdss_data_type *mdata)
|
||||
{
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
struct mdss_mdp_mixer *mixer = mdata->mixer_intf;
|
||||
u32 num_ds_block;
|
||||
int i;
|
||||
|
||||
num_ds_block = mdata->scaler_off->ndest_scalers;
|
||||
ds = devm_kcalloc(&mdata->pdev->dev, num_ds_block,
|
||||
sizeof(struct mdss_mdp_destination_scaler),
|
||||
GFP_KERNEL);
|
||||
if (!ds) {
|
||||
pr_err("unable to setup ds: kzalloc failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ds_block; i++) {
|
||||
ds[i].num = i;
|
||||
ds[i].ds_base = mdata->scaler_off->dest_base;
|
||||
ds[i].scaler_base = mdata->scaler_off->dest_base +
|
||||
mdata->scaler_off->dest_scaler_off[i];
|
||||
ds[i].lut_base = mdata->scaler_off->dest_base +
|
||||
mdata->scaler_off->dest_scaler_lut_off[i];
|
||||
|
||||
/*
|
||||
* Assigning destination scaler to each LM. There is no dynamic
|
||||
* assignment because destination scaler and LM are hard wired.
|
||||
*/
|
||||
if (i < mdata->nmixers_intf)
|
||||
mixer[i].ds = &ds[i];
|
||||
}
|
||||
|
||||
mdata->ds = ds;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct mdss_mdp_mixer *mdss_mdp_mixer_get(struct mdss_mdp_ctl *ctl, int mux)
|
||||
{
|
||||
struct mdss_mdp_mixer *mixer = NULL;
|
||||
|
|
|
@ -346,6 +346,10 @@ enum mdss_mdp_sspp_chroma_samp_type {
|
|||
#define MDSS_MDP_REG_SCALER_MISR_SIGNATURE_0 0x74
|
||||
#define MDSS_MDP_REG_SCALER_MISR_SIGNATURE_1 0x78
|
||||
|
||||
/* Destination scaler TOP registers */
|
||||
#define MDSS_MDP_REG_DEST_SCALER_OP_MODE 0x00
|
||||
#define MDSS_MDP_REG_DEST_SCALER_HW_VERSION 0x10
|
||||
|
||||
#define SCALER_EN BIT(0)
|
||||
#define SCALER_DIR_EN BIT(4)
|
||||
#define SCALER_DE_EN BIT(8)
|
||||
|
|
|
@ -62,6 +62,208 @@ struct mdss_mdp_validate_info_t {
|
|||
struct mdss_mdp_pipe_multirect_params multirect;
|
||||
};
|
||||
|
||||
static inline void *u64_to_ptr(uint64_t address)
|
||||
{
|
||||
return (void *)(uintptr_t)address;
|
||||
}
|
||||
|
||||
static int __dest_scaler_data_setup(struct mdp_destination_scaler_data *ds_data,
|
||||
struct mdss_mdp_destination_scaler *ds,
|
||||
u32 max_input_width, u32 max_output_width)
|
||||
{
|
||||
struct mdp_scale_data_v2 *scale;
|
||||
|
||||
ds->flags = (ds_data->flags & MDP_DESTSCALER_ENABLE) ? DS_ENABLE : 0;
|
||||
|
||||
if (ds_data->flags & (MDP_DESTSCALER_SCALE_UPDATE |
|
||||
MDP_DESTSCALER_ENHANCER_UPDATE)) {
|
||||
if (!ds_data->scale) {
|
||||
pr_err("NULL scale data\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
scale = u64_to_ptr(ds_data->scale);
|
||||
|
||||
if (scale->src_width[0] > max_input_width) {
|
||||
pr_err("Exceed max input width for dest scaler-%d: %d\n",
|
||||
ds_data->dest_scaler_ndx,
|
||||
scale->src_width[0]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (scale->dst_width > max_output_width) {
|
||||
pr_err("Exceed max output width for dest scaler-%d: %d\n",
|
||||
ds_data->dest_scaler_ndx,
|
||||
scale->dst_width);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(&ds->scaler, scale, sizeof(*scale));
|
||||
if (ds_data->flags & MDP_DESTSCALER_SCALE_UPDATE)
|
||||
ds->flags |= DS_SCALE_UPDATE;
|
||||
if (ds_data->flags & MDP_DESTSCALER_ENHANCER_UPDATE)
|
||||
ds->flags |= DS_ENHANCER_UPDATE;
|
||||
ds->src_width = scale->src_width[0];
|
||||
ds->src_height = scale->src_height[0];
|
||||
}
|
||||
|
||||
if (ds_data->flags == 0) {
|
||||
pr_debug("Disabling destination scaler-%d\n",
|
||||
ds_data->dest_scaler_ndx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_destination_scaler_pre_validate(struct mdss_mdp_ctl *ctl,
|
||||
struct mdp_destination_scaler_data *ds_data)
|
||||
{
|
||||
struct mdss_data_type *mdata;
|
||||
struct mdss_panel_info *pinfo;
|
||||
|
||||
mdata = ctl->mdata;
|
||||
|
||||
/*
|
||||
* we need to quickly check for any scale update, and adjust the mixer
|
||||
* width and height accordingly. Otherwise, layer validate will fail
|
||||
* when we switch between scaling factor or disabling scaling.
|
||||
*/
|
||||
if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) && ds_data) {
|
||||
if (ctl->mixer_left) {
|
||||
/*
|
||||
* Any scale update from usermode, we will update the
|
||||
* mixer width and height with the given LM width and
|
||||
* height.
|
||||
*/
|
||||
pinfo = &ctl->panel_data->panel_info;
|
||||
if ((ds_data->lm_width > get_panel_xres(pinfo)) ||
|
||||
(ds_data->lm_height > get_panel_yres(pinfo)) ||
|
||||
(ds_data->lm_width == 0) ||
|
||||
(ds_data->lm_height == 0)) {
|
||||
pr_err("Invalid LM width / height setting\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctl->width = ds_data->lm_width;
|
||||
ctl->height = ds_data->lm_height;
|
||||
|
||||
ctl->mixer_left->width = ds_data->lm_width;
|
||||
ctl->mixer_left->height = ds_data->lm_height;
|
||||
pr_debug("Update mixer-left width/height: %dx%d\n",
|
||||
ds_data->lm_width, ds_data->lm_width);
|
||||
|
||||
}
|
||||
|
||||
if (ctl->mixer_right) {
|
||||
/*
|
||||
* Split display both left and right should have the
|
||||
* same width and height
|
||||
*/
|
||||
ctl->mixer_right->width = ds_data->lm_width;
|
||||
ctl->mixer_right->height = ds_data->lm_height;
|
||||
pr_info("Update mixer-right width/height: %dx%d\n",
|
||||
ds_data->lm_width, ds_data->lm_height);
|
||||
|
||||
/*
|
||||
* For split display, CTL width should be equal to
|
||||
* whole panel size
|
||||
*/
|
||||
ctl->width += ds_data->lm_width;
|
||||
}
|
||||
|
||||
pr_debug("Updated CTL width:%d, height:%d\n",
|
||||
ctl->width, ctl->height);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mdss_mdp_validate_destination_scaler(struct msm_fb_data_type *mfd,
|
||||
struct mdp_destination_scaler_data *ds_data,
|
||||
u32 ds_mode)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mdss_data_type *mdata;
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_mdp_destination_scaler *ds_left = NULL;
|
||||
struct mdss_mdp_destination_scaler *ds_right = NULL;
|
||||
|
||||
if (ds_data) {
|
||||
mdata = mfd_to_mdata(mfd);
|
||||
ctl = mfd_to_ctl(mfd);
|
||||
|
||||
if (ctl->mixer_left)
|
||||
ds_left = ctl->mixer_left->ds;
|
||||
|
||||
if (ctl->mixer_right)
|
||||
ds_right = ctl->mixer_right->ds;
|
||||
|
||||
switch (ds_mode) {
|
||||
case DS_DUAL_MODE:
|
||||
if (!ds_left || !ds_right) {
|
||||
pr_err("Cannot support DUAL mode dest scaling\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = __dest_scaler_data_setup(&ds_data[0], ds_left,
|
||||
mdata->max_dest_scaler_input_width -
|
||||
MDSS_MDP_DS_OVERFETCH_SIZE,
|
||||
mdata->max_dest_scaler_output_width);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = __dest_scaler_data_setup(&ds_data[1], ds_right,
|
||||
mdata->max_dest_scaler_input_width -
|
||||
MDSS_MDP_DS_OVERFETCH_SIZE,
|
||||
mdata->max_dest_scaler_output_width);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ds_left->flags &= ~(DS_LEFT|DS_RIGHT);
|
||||
ds_left->flags |= DS_DUAL_MODE;
|
||||
ds_right->flags &= ~(DS_LEFT|DS_RIGHT);
|
||||
ds_right->flags |= DS_DUAL_MODE;
|
||||
break;
|
||||
|
||||
case DS_LEFT:
|
||||
if (!ds_left) {
|
||||
pr_err("LM in ctl does not support Destination Scaler\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ds_left->flags &= ~(DS_DUAL_MODE|DS_RIGHT);
|
||||
ds_left->flags |= DS_LEFT;
|
||||
|
||||
ret = __dest_scaler_data_setup(&ds_data[0], ds_left,
|
||||
mdata->max_dest_scaler_input_width,
|
||||
mdata->max_dest_scaler_output_width);
|
||||
break;
|
||||
|
||||
case DS_RIGHT:
|
||||
if (!ds_right) {
|
||||
pr_err("Cannot setup DS_RIGHT because only single DS assigned to ctl\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ds_right->flags &= ~(DS_DUAL_MODE|DS_LEFT);
|
||||
ds_right->flags |= DS_RIGHT;
|
||||
|
||||
ret = __dest_scaler_data_setup(&ds_data[0], ds_right,
|
||||
mdata->max_dest_scaler_input_width,
|
||||
mdata->max_dest_scaler_output_width);
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
pr_err("NULL destionation scaler data\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (ds_left)
|
||||
pr_debug("DS_LEFT: flags=0x%X\n", ds_left->flags);
|
||||
if (ds_right)
|
||||
pr_debug("DS_RIGHT: flags=0x%X\n", ds_right->flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* __layer_needs_src_split() - check needs source split configuration
|
||||
* @layer: input layer
|
||||
|
@ -1605,11 +1807,13 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
|
|||
u32 left_lm_w = left_lm_w_from_mfd(mfd);
|
||||
u32 mixer_mux, dst_x;
|
||||
int layer_count = commit->input_layer_cnt;
|
||||
u32 ds_mode = 0;
|
||||
|
||||
struct mdss_mdp_pipe *pipe, *tmp, *left_blend_pipe;
|
||||
struct mdss_mdp_pipe *right_plist[MAX_PIPES_PER_LM] = {0};
|
||||
struct mdss_mdp_pipe *left_plist[MAX_PIPES_PER_LM] = {0};
|
||||
struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
|
||||
struct mdss_data_type *mdata = mfd_to_mdata(mfd);
|
||||
|
||||
struct mdss_mdp_mixer *mixer = NULL;
|
||||
struct mdp_input_layer *layer, *prev_layer, *layer_list;
|
||||
|
@ -1863,6 +2067,37 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
|
|||
layer->z_order -= MDSS_MDP_STAGE_0;
|
||||
}
|
||||
|
||||
if (test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) &&
|
||||
commit->dest_scaler) {
|
||||
/*
|
||||
* Find out which DS block to use based on LM assignment
|
||||
*/
|
||||
if ((left_cnt > 0) && (right_cnt > 0) &&
|
||||
(commit->dest_scaler_cnt == 2))
|
||||
ds_mode = DS_DUAL_MODE;
|
||||
else if ((left_cnt > 0) && (right_cnt == 0) &&
|
||||
(commit->dest_scaler_cnt == 1))
|
||||
ds_mode = DS_LEFT;
|
||||
else if ((left_cnt == 0) && (right_cnt > 0) &&
|
||||
(commit->dest_scaler_cnt == 1))
|
||||
ds_mode = DS_RIGHT;
|
||||
else {
|
||||
pr_err("Commit destination scaler count not matching with LM assignment, DS-cnt:%d\n",
|
||||
commit->dest_scaler_cnt);
|
||||
ret = -EINVAL;
|
||||
goto validate_exit;
|
||||
}
|
||||
|
||||
ret = mdss_mdp_validate_destination_scaler(mfd,
|
||||
commit->dest_scaler,
|
||||
ds_mode);
|
||||
if (ret) {
|
||||
pr_err("fail to validate destination scaler\n");
|
||||
layer->error_code = ret;
|
||||
goto validate_exit;
|
||||
}
|
||||
}
|
||||
|
||||
ret = mdss_mdp_perf_bw_check(mdp5_data->ctl, left_plist, left_cnt,
|
||||
right_plist, right_cnt);
|
||||
if (ret) {
|
||||
|
@ -2130,6 +2365,12 @@ int mdss_mdp_layer_atomic_validate(struct msm_fb_data_type *mfd,
|
|||
}
|
||||
}
|
||||
|
||||
if (mdss_mdp_destination_scaler_pre_validate(mdp5_data->ctl,
|
||||
commit->dest_scaler)) {
|
||||
pr_err("Destination scaler pre-validate failed\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return __validate_layers(mfd, file, commit);
|
||||
}
|
||||
|
||||
|
|
|
@ -221,6 +221,26 @@ struct mdp_csc_cfg mdp_csc_10bit_convert[MDSS_MDP_MAX_CSC] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct mdss_mdp_format_params dest_scaler_fmt = {
|
||||
.format = MDP_XBGR_2101010,
|
||||
.flag = 0,
|
||||
.fetch_planes = MDSS_MDP_PLANE_INTERLEAVED,
|
||||
.unpack_tight = 1,
|
||||
.unpack_align_msb = 0,
|
||||
.alpha_enable = 0,
|
||||
.unpack_count = 4,
|
||||
.bpp = 4,
|
||||
.fetch_mode = MDSS_MDP_FETCH_LINEAR,
|
||||
.element = { C3_ALPHA, C1_B_Cb, C0_G_Y, C2_R_Cr },
|
||||
.bits = {
|
||||
[C3_ALPHA] = 3,
|
||||
[C2_R_Cr] = 3,
|
||||
[C0_G_Y] = 3,
|
||||
[C1_B_Cb] = 3,
|
||||
},
|
||||
.unpack_dx_format = 1,
|
||||
};
|
||||
|
||||
#define CSC_MV_OFF 0x0
|
||||
#define CSC_BV_OFF 0x2C
|
||||
#define CSC_LV_OFF 0x14
|
||||
|
@ -1589,48 +1609,15 @@ static void mdss_mdp_scaler_detail_enhance_cfg(
|
|||
}
|
||||
}
|
||||
|
||||
int mdss_mdp_qseed3_setup(struct mdss_mdp_pipe *pipe,
|
||||
int location, int id)
|
||||
int mdss_mdp_qseed3_setup(struct mdp_scale_data_v2 *scaler,
|
||||
char __iomem *offset,
|
||||
char __iomem *lut_offset,
|
||||
struct mdss_mdp_format_params *fmt)
|
||||
{
|
||||
int rc = 0;
|
||||
struct mdp_scale_data_v2 *scaler;
|
||||
struct mdss_data_type *mdata;
|
||||
char __iomem *offset, *lut_offset;
|
||||
struct mdss_mdp_format_params *fmt;
|
||||
uint32_t op_mode = 0;
|
||||
uint32_t phase_init, preload, src_y_rgb, src_uv, dst;
|
||||
|
||||
mdata = mdss_mdp_get_mdata();
|
||||
/* SRC pipe QSEED3 Configuration */
|
||||
if (location == SSPP_VIG) {
|
||||
scaler = &pipe->scaler;
|
||||
offset = pipe->base + mdata->scaler_off->vig_scaler_off;
|
||||
lut_offset = pipe->base + mdata->scaler_off->vig_scaler_lut_off;
|
||||
fmt = pipe->src_fmt;
|
||||
} else if (location == DSPP) {
|
||||
/* Destination scaler QSEED3 Configuration */
|
||||
if ((mdata->scaler_off->has_dest_scaler) &&
|
||||
(id < mdata->scaler_off->ndest_scalers)) {
|
||||
/* TODO :point to the destination params */
|
||||
scaler = NULL;
|
||||
offset = mdata->scaler_off->dest_base +
|
||||
mdata->scaler_off->dest_scaler_off[id];
|
||||
lut_offset = mdata->scaler_off->dest_base +
|
||||
mdata->scaler_off->dest_scaler_lut_off[id];
|
||||
/*TODO : set pixel fmt to RGB101010 */
|
||||
return -ENOSYS;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!scaler) {
|
||||
pr_debug("scaler pointer is NULL\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_debug("scaler->enable=%d", scaler->enable);
|
||||
|
||||
if (scaler->enable) {
|
||||
|
@ -1650,8 +1637,6 @@ int mdss_mdp_qseed3_setup(struct mdss_mdp_pipe *pipe,
|
|||
ALPHA_FILTER_CFG;
|
||||
}
|
||||
|
||||
/* TODO:if src_fmt is 10 bits program the bitwidth
|
||||
* accordingly */
|
||||
if (!fmt->unpack_dx_format)
|
||||
op_mode |= 0x1 << SCALER_BIT_WIDTH;
|
||||
|
||||
|
@ -1750,12 +1735,24 @@ static int mdss_mdp_scale_setup(struct mdss_mdp_pipe *pipe,
|
|||
{
|
||||
struct mdss_data_type *mdata;
|
||||
int rc = 0;
|
||||
char __iomem *offset, *lut_offset;
|
||||
|
||||
mdata = mdss_mdp_get_mdata();
|
||||
if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map))
|
||||
rc = mdss_mdp_qseed3_setup(pipe, pp_blk, 0);
|
||||
else
|
||||
|
||||
if (test_bit(MDSS_CAPS_QSEED3, mdata->mdss_caps_map)) {
|
||||
if (pp_blk == SSPP_VIG) {
|
||||
offset = pipe->base + mdata->scaler_off->vig_scaler_off;
|
||||
lut_offset = pipe->base +
|
||||
mdata->scaler_off->vig_scaler_lut_off;
|
||||
|
||||
rc = mdss_mdp_qseed3_setup(&pipe->scaler, offset,
|
||||
lut_offset, pipe->src_fmt);
|
||||
} else {
|
||||
rc = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
rc = mdss_mdp_qseed2_setup(pipe);
|
||||
}
|
||||
|
||||
if (rc)
|
||||
pr_err("scale setup on pipe %d type %d failed ret %d\n",
|
||||
|
@ -2432,6 +2429,71 @@ dspp_exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int pp_dest_scaler_setup(struct mdss_mdp_mixer *mixer)
|
||||
{
|
||||
struct mdss_mdp_ctl *ctl;
|
||||
struct mdss_data_type *mdata;
|
||||
struct mdss_mdp_destination_scaler *ds;
|
||||
int ret = 0;
|
||||
u32 op_mode;
|
||||
u32 mask;
|
||||
char *ds_offset;
|
||||
|
||||
if (!mixer || !mixer->ctl || !mixer->ctl->mdata)
|
||||
return -EINVAL;
|
||||
|
||||
ctl = mixer->ctl;
|
||||
mdata = ctl->mdata;
|
||||
ds = mixer->ds;
|
||||
|
||||
if (!test_bit(MDSS_CAPS_DEST_SCALER, mdata->mdss_caps_map) || !ds)
|
||||
return 0;
|
||||
|
||||
ds_offset = ds->ds_base;
|
||||
op_mode = readl_relaxed(MDSS_MDP_REG_DEST_SCALER_OP_MODE +
|
||||
ds_offset);
|
||||
|
||||
mask = BIT(ds->num);
|
||||
if (ds->flags & DS_ENABLE)
|
||||
op_mode |= mask;
|
||||
else
|
||||
op_mode &= ~mask;
|
||||
|
||||
if (ds->flags & DS_DUAL_MODE)
|
||||
op_mode |= BIT(16);
|
||||
else
|
||||
op_mode &= ~BIT(16);
|
||||
|
||||
writel_relaxed(op_mode, MDSS_MDP_REG_DEST_SCALER_OP_MODE + ds_offset);
|
||||
|
||||
if (ds->flags & DS_SCALE_UPDATE) {
|
||||
ret = mdss_mdp_qseed3_setup(&ds->scaler,
|
||||
ds->scaler_base, ds->lut_base,
|
||||
&dest_scaler_fmt);
|
||||
if (ret) {
|
||||
pr_err("Failed setup destination scaler\n");
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Clearing the flag because we don't need to program the block
|
||||
* for each commit if there is no change.
|
||||
*/
|
||||
ds->flags &= ~DS_SCALE_UPDATE;
|
||||
}
|
||||
|
||||
if (ds->flags & DS_ENHANCER_UPDATE) {
|
||||
mdss_mdp_scaler_detail_enhance_cfg(&ds->scaler.detail_enhance,
|
||||
ds->scaler_base);
|
||||
ds->flags &= ~DS_ENHANCER_UPDATE;
|
||||
}
|
||||
|
||||
/* Destinations scaler shared the flush with DSPP in control */
|
||||
if (ds->flags & DS_ENABLE)
|
||||
ctl->flush_bits |= BIT(13 + ds->num);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mdss_mdp_pp_setup(struct mdss_mdp_ctl *ctl)
|
||||
{
|
||||
int ret = 0;
|
||||
|
@ -2521,11 +2583,13 @@ int mdss_mdp_pp_setup_locked(struct mdss_mdp_ctl *ctl)
|
|||
}
|
||||
|
||||
if (ctl->mixer_left) {
|
||||
pp_dest_scaler_setup(ctl->mixer_left);
|
||||
pp_mixer_setup(ctl->mixer_left);
|
||||
pp_dspp_setup(disp_num, ctl->mixer_left);
|
||||
pp_ppb_setup(ctl->mixer_left);
|
||||
}
|
||||
if (ctl->mixer_right) {
|
||||
pp_dest_scaler_setup(ctl->mixer_right);
|
||||
pp_mixer_setup(ctl->mixer_right);
|
||||
pp_dspp_setup(disp_num, ctl->mixer_right);
|
||||
pp_ppb_setup(ctl->mixer_right);
|
||||
|
|
Loading…
Add table
Reference in a new issue