summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorVeera Sundaram Sankaran <veeras@codeaurora.org>2016-04-15 11:57:24 -0700
committerKyle Yan <kyan@codeaurora.org>2016-07-05 15:30:48 -0700
commitdf73dce85c64ff2897f23a6b03586e83ef7c5cab (patch)
tree2ba32c25b8f3e45c1a6c389b70f26646dcc5f9e7 /drivers/video/fbdev
parentdb2b74c45630ad8b40a30b165861a0732541fea6 (diff)
msm: mdss: add dynamic resolution switch support for DSC panels
Reconfigure the DSC parameters and DSI stream according to the new resolution. Mandate the first frame after dynamic resolution change for DSC panels to be full frame updates. Send PPS command based on the device tree entry before or after the switch commands. Fix device tree parsing of DSC parameters within the switch timing node. Add sub-nodes in target specific device tree to configure target specific timing and switch commands. Change-Id: I6aa5f8f972b16645b219bf6274036b6e5dac6dda Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c14
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c77
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c110
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h10
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c32
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c46
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c48
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h9
8 files changed, 215 insertions, 131 deletions
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 8f1ab774044d..1b46c17861b1 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2705,6 +2705,7 @@ static struct device_node *mdss_dsi_find_panel_of_node(
struct mdss_panel_info *pinfo = &ctrl_pdata->panel_data.panel_info;
len = strlen(panel_cfg);
+ ctrl_pdata->panel_data.dsc_cfg_np_name[0] = '\0';
if (!len) {
/* no panel cfg chg, parse dt */
pr_debug("%s:%d: no cmd line cfg present\n",
@@ -2788,18 +2789,11 @@ static struct device_node *mdss_dsi_find_panel_of_node(
strlcpy(cfg_np_name, str2,
MDSS_MAX_PANEL_LEN);
}
- }
-
- pr_debug("%s: cfg_np_name:%s\n", __func__, cfg_np_name);
- if (str2) {
- ctrl_pdata->panel_data.cfg_np =
- of_get_child_by_name(dsi_pan_node,
- cfg_np_name);
- if (!ctrl_pdata->panel_data.cfg_np)
- pr_warn("%s: can't find config node:%s. either no such node or bad name\n",
- __func__, cfg_np_name);
+ strlcpy(ctrl_pdata->panel_data.dsc_cfg_np_name,
+ cfg_np_name, MDSS_MAX_PANEL_LEN);
}
}
+
return dsi_pan_node;
}
end:
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index 707b1cbbd07b..ea706cb54228 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -630,12 +630,21 @@ static void mdss_dsi_panel_switch_mode(struct mdss_panel_data *pdata,
pr_debug("%s: sending switch commands\n", __func__);
pcmds = &pt->switch_cmds;
flags |= CMD_REQ_DMA_TPG;
+ flags |= CMD_REQ_COMMIT;
} else {
pr_warn("%s: Invalid mode switch attempted\n", __func__);
return;
}
+ if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) &&
+ (pdata->panel_info.send_pps_before_switch))
+ mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info);
+
mdss_dsi_panel_cmds_send(ctrl_pdata, pcmds, flags);
+
+ if ((pdata->panel_info.compression_mode == COMPRESSION_DSC) &&
+ (!pdata->panel_info.send_pps_before_switch))
+ mdss_dsi_panel_dsc_pps_send(ctrl_pdata, &pdata->panel_info);
}
static void mdss_dsi_panel_bl_ctrl(struct mdss_panel_data *pdata,
@@ -1268,8 +1277,39 @@ end:
return rc;
}
+static struct device_node *mdss_dsi_panel_get_dsc_cfg_np(
+ struct device_node *np, struct mdss_panel_data *panel_data,
+ bool default_timing)
+{
+ struct device_node *dsc_cfg_np = NULL;
+
+
+ /* Read the dsc config node specified by command line */
+ if (default_timing) {
+ dsc_cfg_np = of_get_child_by_name(np,
+ panel_data->dsc_cfg_np_name);
+ if (!dsc_cfg_np)
+ pr_warn_once("%s: cannot find dsc config node:%s\n",
+ __func__, panel_data->dsc_cfg_np_name);
+ }
+
+ /*
+ * Fall back to default from DT as nothing is specified
+ * in command line.
+ */
+ if (!dsc_cfg_np && of_find_property(np, "qcom,config-select", NULL)) {
+ dsc_cfg_np = of_parse_phandle(np, "qcom,config-select", 0);
+ if (!dsc_cfg_np)
+ pr_warn_once("%s:err parsing qcom,config-select\n",
+ __func__);
+ }
+
+ return dsc_cfg_np;
+}
+
static int mdss_dsi_parse_topology_config(struct device_node *np,
- struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data)
+ struct dsi_panel_timing *pt, struct mdss_panel_data *panel_data,
+ bool default_timing)
{
int rc = 0;
bool is_split_display = panel_data->panel_info.is_split_display;
@@ -1277,19 +1317,14 @@ static int mdss_dsi_parse_topology_config(struct device_node *np,
struct mdss_panel_timing *timing = &pt->timing;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
- struct device_node *cfg_np;
+ struct device_node *cfg_np = NULL;
ctrl_pdata = container_of(panel_data, struct mdss_dsi_ctrl_pdata,
panel_data);
- cfg_np = ctrl_pdata->panel_data.cfg_np;
pinfo = &ctrl_pdata->panel_data.panel_info;
- if (!cfg_np && of_find_property(np, "qcom,config-select", NULL)) {
- cfg_np = of_parse_phandle(np, "qcom,config-select", 0);
- if (!cfg_np)
- pr_err("%s:err parsing qcom,config-select\n", __func__);
- ctrl_pdata->panel_data.cfg_np = cfg_np;
- }
+ cfg_np = mdss_dsi_panel_get_dsc_cfg_np(np,
+ &ctrl_pdata->panel_data, default_timing);
if (cfg_np) {
if (!of_property_read_u32_array(cfg_np, "qcom,lm-split",
@@ -1331,6 +1366,10 @@ static int mdss_dsi_parse_topology_config(struct device_node *np,
if (rc)
goto end;
+ pinfo->send_pps_before_switch =
+ of_property_read_bool(np,
+ "qcom,mdss-dsi-send-pps-before-switch");
+
rc = mdss_dsi_parse_dsc_params(cfg_np, &pt->timing,
is_split_display);
} else if (!strcmp(data, "fbc")) {
@@ -2157,7 +2196,8 @@ static int mdss_dsi_panel_timing_from_dt(struct device_node *np,
static int mdss_dsi_panel_config_res_properties(struct device_node *np,
struct dsi_panel_timing *pt,
- struct mdss_panel_data *panel_data)
+ struct mdss_panel_data *panel_data,
+ bool default_timing)
{
int rc = 0;
@@ -2172,7 +2212,7 @@ static int mdss_dsi_panel_config_res_properties(struct device_node *np,
"qcom,mdss-dsi-timing-switch-command",
"qcom,mdss-dsi-timing-switch-command-state");
- rc = mdss_dsi_parse_topology_config(np, pt, panel_data);
+ rc = mdss_dsi_parse_topology_config(np, pt, panel_data, default_timing);
if (rc) {
pr_err("%s: parsing compression params failed. rc:%d\n",
__func__, rc);
@@ -2192,6 +2232,7 @@ static int mdss_panel_parse_display_timings(struct device_node *np,
struct device_node *entry;
int num_timings, rc;
int i = 0, active_ndx = 0;
+ bool default_timing = false;
ctrl = container_of(panel_data, struct mdss_dsi_ctrl_pdata, panel_data);
@@ -2210,7 +2251,7 @@ static int mdss_panel_parse_display_timings(struct device_node *np,
rc = mdss_dsi_panel_timing_from_dt(np, &pt, panel_data);
if (!rc) {
mdss_dsi_panel_config_res_properties(np, &pt,
- panel_data);
+ panel_data, true);
rc = mdss_dsi_panel_timing_switch(ctrl, &pt.timing);
}
return rc;
@@ -2237,14 +2278,14 @@ static int mdss_panel_parse_display_timings(struct device_node *np,
goto exit;
}
- mdss_dsi_panel_config_res_properties(entry, (modedb + i),
- panel_data);
-
- /* if default is set, use it otherwise use first as default */
- if (of_property_read_bool(entry,
- "qcom,mdss-dsi-timing-default"))
+ default_timing = of_property_read_bool(entry,
+ "qcom,mdss-dsi-timing-default");
+ if (default_timing)
active_ndx = i;
+ mdss_dsi_panel_config_res_properties(entry, (modedb + i),
+ panel_data, default_timing);
+
list_add(&modedb[i].timing.list,
&panel_data->timings_list);
i++;
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 893c07379e20..8f2a70df146d 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -983,6 +983,30 @@ static void mdss_fb_videomode_from_panel_timing(struct fb_videomode *videomode,
}
}
+static void mdss_fb_set_split_mode(struct msm_fb_data_type *mfd,
+ struct mdss_panel_data *pdata)
+{
+ if (pdata->panel_info.is_split_display) {
+ struct mdss_panel_data *pnext = pdata->next;
+
+ mfd->split_fb_left = pdata->panel_info.lm_widths[0];
+ if (pnext)
+ mfd->split_fb_right = pnext->panel_info.lm_widths[0];
+
+ if (pdata->panel_info.use_pingpong_split)
+ mfd->split_mode = MDP_PINGPONG_SPLIT;
+ else
+ mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY;
+ } else if ((pdata->panel_info.lm_widths[0] != 0)
+ && (pdata->panel_info.lm_widths[1] != 0)) {
+ mfd->split_fb_left = pdata->panel_info.lm_widths[0];
+ mfd->split_fb_right = pdata->panel_info.lm_widths[1];
+ mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY;
+ } else {
+ mfd->split_mode = MDP_SPLIT_MODE_NONE;
+ }
+}
+
static int mdss_fb_init_panel_modes(struct msm_fb_data_type *mfd,
struct mdss_panel_data *pdata)
{
@@ -1104,25 +1128,8 @@ static int mdss_fb_probe(struct platform_device *pdev)
mfd->pdev = pdev;
mfd->split_fb_left = mfd->split_fb_right = 0;
- mfd->split_mode = MDP_SPLIT_MODE_NONE;
- if (pdata->panel_info.is_split_display) {
- struct mdss_panel_data *pnext = pdata->next;
-
- mfd->split_fb_left = pdata->panel_info.lm_widths[0];
- if (pnext)
- mfd->split_fb_right = pnext->panel_info.lm_widths[0];
-
- if (pdata->panel_info.use_pingpong_split)
- mfd->split_mode = MDP_PINGPONG_SPLIT;
- else
- mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY;
- } else if ((pdata->panel_info.lm_widths[0] != 0) &&
- (pdata->panel_info.lm_widths[1] != 0)) {
- mfd->split_fb_left = pdata->panel_info.lm_widths[0];
- mfd->split_fb_right = pdata->panel_info.lm_widths[1];
- mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY;
- }
+ mdss_fb_set_split_mode(mfd, pdata);
pr_info("fb%d: split_mode:%d left:%d right:%d\n", mfd->index,
mfd->split_mode, mfd->split_fb_left, mfd->split_fb_right);
@@ -3103,38 +3110,27 @@ u32 mdss_fb_get_mode_switch(struct msm_fb_data_type *mfd)
* panel mode being switching into.
*/
static int __ioctl_transition_dyn_mode_state(struct msm_fb_data_type *mfd,
- unsigned int cmd, int validate)
+ unsigned int cmd, bool validate, bool null_commit)
{
if (mfd->switch_state == MDSS_MDP_NO_UPDATE_REQUESTED)
return 0;
mutex_lock(&mfd->switch_lock);
switch (cmd) {
- case MSMFB_BUFFER_SYNC:
- if (mfd->switch_state == MDSS_MDP_WAIT_FOR_SYNC) {
- if (mfd->switch_new_mode != SWITCH_RESOLUTION)
- mdss_fb_set_mdp_sync_pt_threshold(mfd,
- mfd->switch_new_mode);
- mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT;
- }
- break;
- case MSMFB_OVERLAY_PREPARE:
- if (mfd->switch_state == MDSS_MDP_WAIT_FOR_PREP) {
- if (mfd->switch_new_mode != SWITCH_RESOLUTION)
- mfd->pending_switch = true;
- mfd->switch_state = MDSS_MDP_WAIT_FOR_SYNC;
- }
- break;
case MSMFB_ATOMIC_COMMIT:
- if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_PREP) && validate) {
+ if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE)
+ && validate) {
if (mfd->switch_new_mode != SWITCH_RESOLUTION)
mfd->pending_switch = true;
- mfd->switch_state = MDSS_MDP_WAIT_FOR_SYNC;
- } else if (mfd->switch_state == MDSS_MDP_WAIT_FOR_SYNC) {
+ mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT;
+ } else if (mfd->switch_state == MDSS_MDP_WAIT_FOR_COMMIT) {
if (mfd->switch_new_mode != SWITCH_RESOLUTION)
mdss_fb_set_mdp_sync_pt_threshold(mfd,
mfd->switch_new_mode);
- mfd->switch_state = MDSS_MDP_WAIT_FOR_COMMIT;
+ mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF;
+ } else if ((mfd->switch_state == MDSS_MDP_WAIT_FOR_VALIDATE)
+ && null_commit) {
+ mfd->switch_state = MDSS_MDP_WAIT_FOR_KICKOFF;
}
break;
}
@@ -3228,7 +3224,7 @@ int mdss_fb_atomic_commit(struct fb_info *info,
pr_err("wait for kickoff failed\n");
} else {
__ioctl_transition_dyn_mode_state(mfd,
- MSMFB_ATOMIC_COMMIT, 1);
+ MSMFB_ATOMIC_COMMIT, true, false);
if (mfd->panel.type == WRITEBACK_PANEL) {
output_layer = commit_v1->output_layer;
wb_change = !mdss_fb_is_wb_config_same(mfd,
@@ -3254,6 +3250,9 @@ int mdss_fb_atomic_commit(struct fb_info *info,
pr_err("pan display idle call failed\n");
goto end;
}
+ __ioctl_transition_dyn_mode_state(mfd,
+ MSMFB_ATOMIC_COMMIT, false,
+ (commit_v1->input_layer_cnt ? 0 : 1));
ret = mfd->mdp.pre_commit(mfd, file, commit_v1);
if (ret) {
@@ -3450,7 +3449,7 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
sync_pt_data->flushed = false;
mutex_lock(&mfd->switch_lock);
- if (mfd->switch_state == MDSS_MDP_WAIT_FOR_COMMIT) {
+ if (mfd->switch_state == MDSS_MDP_WAIT_FOR_KICKOFF) {
dynamic_dsi_switch = 1;
new_dsi_mode = mfd->switch_new_mode;
} else if (mfd->switch_state != MDSS_MDP_NO_UPDATE_REQUESTED) {
@@ -3460,8 +3459,9 @@ static int __mdss_fb_perform_commit(struct msm_fb_data_type *mfd)
goto skip_commit;
}
mutex_unlock(&mfd->switch_lock);
-
if (dynamic_dsi_switch) {
+ MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode,
+ XLOG_FUNC_ENTRY);
pr_debug("Triggering dyn mode switch to %d\n", new_dsi_mode);
ret = mfd->mdp.mode_switch(mfd, new_dsi_mode);
if (ret)
@@ -3502,6 +3502,8 @@ skip_commit:
}
if (dynamic_dsi_switch) {
+ MDSS_XLOG(mfd->index, mfd->split_mode, new_dsi_mode,
+ XLOG_FUNC_EXIT);
mfd->mdp.mode_switch_post(mfd, new_dsi_mode);
mutex_lock(&mfd->switch_lock);
mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED;
@@ -3690,7 +3692,10 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd,
mdss_fb_wait_for_kickoff(mfd);
pr_debug("fb%d: changing display mode to %s\n", mfd->index, mode->name);
-
+ MDSS_XLOG(mfd->index, mode->name,
+ mdss_fb_get_panel_xres(mfd->panel_info),
+ mfd->panel_info->yres, mfd->split_mode,
+ XLOG_FUNC_ENTRY);
tmp = pdata;
do {
if (!tmp->event_handler) {
@@ -3705,13 +3710,16 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd,
tmp = tmp->next;
} while (tmp && !ret);
+ if (!ret)
+ mdss_fb_set_split_mode(mfd, pdata);
+
if (!ret && mfd->mdp.configure_panel) {
int dest_ctrl = 1;
/* todo: currently assumes no changes in video/cmd mode */
if (!mdss_fb_is_power_off(mfd)) {
mutex_lock(&mfd->switch_lock);
- mfd->switch_state = MDSS_MDP_WAIT_FOR_PREP;
+ mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE;
mfd->switch_new_mode = SWITCH_RESOLUTION;
mutex_unlock(&mfd->switch_lock);
dest_ctrl = 0;
@@ -3720,14 +3728,10 @@ static int mdss_fb_videomode_switch(struct msm_fb_data_type *mfd,
pdata->panel_info.mipi.mode, dest_ctrl);
}
- if (!ret) {
- if (pdata->next && pdata->next->active)
- mfd->split_mode = MDP_DUAL_LM_DUAL_DISPLAY;
- else
- mfd->split_mode = MDP_SPLIT_MODE_NONE;
- mdss_fb_validate_split(0, 0, mfd);
- }
-
+ MDSS_XLOG(mfd->index, mode->name,
+ mdss_fb_get_panel_xres(mfd->panel_info),
+ mfd->panel_info->yres, mfd->split_mode,
+ XLOG_FUNC_EXIT);
pr_debug("fb%d: %s mode change complete\n", mfd->index, mode->name);
return ret;
@@ -4608,7 +4612,7 @@ static int mdss_fb_immediate_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
ret = -EAGAIN;
goto exit;
}
- mfd->switch_state = MDSS_MDP_WAIT_FOR_PREP;
+ mfd->switch_state = MDSS_MDP_WAIT_FOR_VALIDATE;
mfd->switch_new_mode = tranlated_mode;
exit:
@@ -4712,8 +4716,6 @@ int mdss_fb_do_ioctl(struct fb_info *info, unsigned int cmd,
if (ret)
goto exit;
- __ioctl_transition_dyn_mode_state(mfd, cmd, 0);
-
switch (cmd) {
case MSMFB_CURSOR:
ret = mdss_fb_cursor(info, argp);
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index af670f607e54..56997e40d244 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -129,15 +129,15 @@ enum mdp_mmap_type {
* enum dyn_mode_switch_state - Lists next stage for dynamic mode switch work
*
* @MDSS_MDP_NO_UPDATE_REQUESTED: incoming frame is processed normally
- * @MDSS_MDP_WAIT_FOR_PREP: Waiting for OVERLAY_PREPARE to be called
- * @MDSS_MDP_WAIT_FOR_SYNC: Waiting for BUFFER_SYNC to be called
- * @MDSS_MDP_WAIT_FOR_COMMIT: Waiting for COMMIT to be called
+ * @MDSS_MDP_WAIT_FOR_VALIDATE: Waiting for ATOMIC_COMMIT-validate to be called
+ * @MDSS_MDP_WAIT_FOR_COMMIT: Waiting for ATOMIC_COMMIT-commit to be called
+ * @MDSS_MDP_WAIT_FOR_KICKOFF: Waiting for KICKOFF to be called
*/
enum dyn_mode_switch_state {
MDSS_MDP_NO_UPDATE_REQUESTED,
- MDSS_MDP_WAIT_FOR_PREP,
- MDSS_MDP_WAIT_FOR_SYNC,
+ MDSS_MDP_WAIT_FOR_VALIDATE,
MDSS_MDP_WAIT_FOR_COMMIT,
+ MDSS_MDP_WAIT_FOR_KICKOFF,
};
/**
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 96f2375a6f7d..f97a9f9a9adc 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -3621,10 +3621,28 @@ skip_intf_reconfig:
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;
+
+ if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) {
+ if (ctl->mixer_left) {
+ ctl->mixer_left->width = ctl->width / 2;
+ ctl->mixer_left->height = ctl->height;
+ }
+ if (ctl->mixer_right) {
+ ctl->mixer_right->width = ctl->width / 2;
+ ctl->mixer_right->height = ctl->height;
+ }
+ } else {
+ /*
+ * Handles MDP_SPLIT_MODE_NONE, MDP_DUAL_LM_DUAL_DISPLAY and
+ * MDP_PINGPONG_SPLIT case.
+ */
+ if (ctl->mixer_left) {
+ ctl->mixer_left->width = ctl->width;
+ ctl->mixer_left->height = ctl->height;
+ }
}
+ ctl->roi = (struct mdss_rect) {0, 0, ctl->width, ctl->height};
+
ctl->border_x_off = pdata->panel_info.lcdc.border_left;
ctl->border_y_off = pdata->panel_info.lcdc.border_top;
@@ -3960,7 +3978,13 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)
mdss_mdp_pp_resume(ctl->mfd);
if (is_dsc_compression(&ctl->panel_data->panel_info)) {
- mdss_mdp_ctl_dsc_setup(ctl,
+ /*
+ * Avoid redundant call to dsc_setup when mode switch
+ * is in progress. During the switch, dsc_setup is
+ * handled in mdss_mode_switch() function.
+ */
+ if (ctl->pending_mode_switch != SWITCH_RESOLUTION)
+ mdss_mdp_ctl_dsc_setup(ctl,
&ctl->panel_data->panel_info);
} else if (ctl->panel_data->panel_info.compression_mode ==
COMPRESSION_FBC) {
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 4874e055b274..e54898e8070f 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -2048,11 +2048,12 @@ static int mdss_mdp_cmd_panel_on(struct mdss_mdp_ctl *ctl,
WARN(rc, "intf %d panel on error (%d)\n",
ctl->intf_num, rc);
- rc = mdss_mdp_tearcheck_enable(ctl, true);
- WARN(rc, "intf %d tearcheck enable error (%d)\n",
- ctl->intf_num, rc);
}
+ rc = mdss_mdp_tearcheck_enable(ctl, true);
+ WARN(rc, "intf %d tearcheck enable error (%d)\n",
+ ctl->intf_num, rc);
+
ctx->panel_power_state = MDSS_PANEL_POWER_ON;
if (sctx)
sctx->panel_power_state = MDSS_PANEL_POWER_ON;
@@ -3340,9 +3341,6 @@ void mdss_mdp_switch_to_vid_mode(struct mdss_mdp_ctl *ctl, int prep)
static int mdss_mdp_cmd_reconfigure(struct mdss_mdp_ctl *ctl,
enum dynamic_switch_modes mode, bool prep)
{
- struct dsi_panel_clk_ctrl clk_ctrl;
- int ret, rc = 0;
-
if (mdss_mdp_ctl_is_power_off(ctl))
return 0;
@@ -3353,41 +3351,19 @@ static int mdss_mdp_cmd_reconfigure(struct mdss_mdp_ctl *ctl,
mdss_mdp_switch_to_vid_mode(ctl, prep);
} else if (mode == SWITCH_RESOLUTION) {
if (prep) {
- /* make sure any pending transfer is finished */
- ret = mdss_mdp_cmd_wait4pingpong(ctl, NULL);
- if (ret)
- return ret;
-
+ mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
/*
- * keep a ref count on clocks to prevent them from
- * being disabled while switch happens
+ * Setup DSC conifg early, as DSI configuration during
+ * resolution switch would rely on DSC params for
+ * stream configs.
*/
- mdss_bus_bandwidth_ctrl(true);
- rc = mdss_iommu_ctrl(1);
- if (IS_ERR_VALUE(rc))
- pr_err("IOMMU attach failed\n");
-
- clk_ctrl.state = MDSS_DSI_CLK_ON;
- clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
- mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
- mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)&clk_ctrl,
- CTL_INTF_EVENT_FLAG_DEFAULT);
+ mdss_mdp_cmd_dsc_reconfig(ctl);
mdss_mdp_ctl_stop(ctl, MDSS_PANEL_POWER_OFF);
mdss_mdp_ctl_intf_event(ctl,
- MDSS_EVENT_DSI_DYNAMIC_SWITCH,
- (void *) mode,
- CTL_INTF_EVENT_FLAG_DEFAULT);
+ MDSS_EVENT_DSI_DYNAMIC_SWITCH,
+ (void *) mode, CTL_INTF_EVENT_FLAG_DEFAULT);
} else {
- /* release ref count after switch is complete */
- clk_ctrl.state = MDSS_DSI_CLK_OFF;
- clk_ctrl.client = DSI_CLK_REQ_MDP_CLIENT;
- mdss_mdp_ctl_intf_event(ctl, MDSS_EVENT_PANEL_CLK_CTRL,
- (void *)&clk_ctrl,
- CTL_INTF_EVENT_FLAG_DEFAULT);
- mdss_iommu_ctrl(0);
- mdss_bus_bandwidth_ctrl(false);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 388e0057d746..78e448f2e207 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -1711,8 +1711,9 @@ int mdss_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
{
struct mdss_rect l_roi, r_roi;
struct mdss_mdp_ctl *ctl = mfd_to_ctl(mfd);
+ struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
struct mdss_mdp_ctl *sctl;
- int rc;
+ int rc = 0;
pr_debug("fb%d switch to mode=%x\n", mfd->index, mode);
ATRACE_FUNC();
@@ -1725,9 +1726,42 @@ int mdss_mode_switch(struct msm_fb_data_type *mfd, u32 mode)
/* No need for mode validation. It has been done in ioctl call */
if (mode == SWITCH_RESOLUTION) {
if (ctl->ops.reconfigure) {
- rc = ctl->ops.reconfigure(ctl, mode, 1);
- if (rc)
+ /* wait for previous frame to complete before switch */
+ if (ctl->ops.wait_pingpong)
+ rc = ctl->ops.wait_pingpong(ctl, NULL);
+ if (!rc && sctl && sctl->ops.wait_pingpong)
+ rc = sctl->ops.wait_pingpong(sctl, NULL);
+ if (rc) {
+ pr_err("wait for pp failed before resolution switch\n");
return rc;
+ }
+
+ /*
+ * Configure the mixer parameters before the switch as
+ * the DSC parameter calculation is based on the mixer
+ * ROI. And set it to full ROI as driver expects the
+ * first frame after the resolution switch to be a
+ * full frame update.
+ */
+ if (ctl->mixer_left) {
+ l_roi = (struct mdss_rect) {0, 0,
+ ctl->mixer_left->width,
+ ctl->mixer_left->height};
+ ctl->mixer_left->roi_changed = true;
+ ctl->mixer_left->valid_roi = true;
+ }
+ if (ctl->mixer_right) {
+ r_roi = (struct mdss_rect) {0, 0,
+ ctl->mixer_right->width,
+ ctl->mixer_right->height};
+ ctl->mixer_right->roi_changed = true;
+ ctl->mixer_right->valid_roi = true;
+ }
+ mdss_mdp_set_roi(ctl, &l_roi, &r_roi);
+
+ mutex_lock(&mdp5_data->ov_lock);
+ ctl->ops.reconfigure(ctl, mode, 1);
+ mutex_unlock(&mdp5_data->ov_lock);
/*
* For Video mode panels, reconfigure is not defined.
* So doing an explicit ctrl stop during resolution switch
@@ -1850,7 +1884,13 @@ static void __validate_and_set_roi(struct msm_fb_data_type *mfd,
l_roi.x, l_roi.y, l_roi.w, l_roi.h,
r_roi.x, r_roi.y, r_roi.w, r_roi.h);
- if (!ctl->panel_data->panel_info.partial_update_enabled)
+ /*
+ * Configure full ROI
+ * - If partial update is disabled
+ * - If it is the first frame update after dynamic resolution switch
+ */
+ if (!ctl->panel_data->panel_info.partial_update_enabled
+ || (ctl->pending_mode_switch == SWITCH_RESOLUTION))
goto set_roi;
skip_partial_update = false;
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index 1b4d7d8c5f82..8517a60af329 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -696,6 +696,12 @@ struct mdss_panel_info {
u8 dsc_enc_total; /* max 2 */
struct dsc_desc dsc;
+ /*
+ * To determine, if DSC panel requires the pps to be sent
+ * before or after the switch, during dynamic resolution switching
+ */
+ bool send_pps_before_switch;
+
struct lcd_panel_info lcdc;
struct fbc_panel_info fbc;
struct mipi_panel_info mipi;
@@ -771,7 +777,8 @@ struct mdss_panel_data {
struct mdss_panel_timing *current_timing;
bool active;
- struct device_node *cfg_np; /* NULL if config node is not present */
+ /* To store dsc cfg name passed by bootloader */
+ char dsc_cfg_np_name[MDSS_MAX_PANEL_LEN];
struct mdss_panel_data *next;
};