- qcom,cmd-to-video-mode-switch-commands: List of commands that need to be sent
to panel in order to switch from command mode to video mode dynamically.
Refer to "qcom,mdss-dsi-on-command" section for adding commands.
+- qcom,send-pps-before-switch: Boolean propety to indicate when PPS commands should be sent,
+ either before or after switch commands during dynamic resolution
+ switch in DSC panels. If the property is not present, the default
+ behavior is to send PPS commands after the switch commands.
- qcom,mdss-dsi-panel-orientation: String used to indicate orientation of panel
"180" = panel is flipped in both horizontal and vertical directions
"hflip" = panel is flipped in horizontal direction
qcom,video-to-cmd-mode-switch-commands = [15 01 00 00 00 00 02 C2 0B
15 01 00 00 00 00 02 C2 08];
qcom,cmd-to-video-mode-switch-commands = [15 01 00 00 00 00 02 C2 03];
+ qcom,send-pps-before-switch;
qcom,panel-ack-disabled;
qcom,mdss-dsi-horizontal-line-idle = <0 40 256>,
<40 120 128>,
29 00 00 00 00 00 02 B0 04
29 00 00 00 00 00 02 F1 00];
qcom,mdss-dsi-timing-switch-command-state = "dsi_lp_mode";
+
+ qcom,config-select = <&dsi_sim_vid_config0>;
+ dsi_sim_vid_config0: config0 {
+ qcom,lm-split = <360 360>;
+ qcom,mdss-dsc-encoders = <2>;
+ qcom,mdss-dsc-slice-height = <16>;
+ qcom,mdss-dsc-slice-width = <360>;
+ qcom,mdss-dsc-slice-per-pkt = <2>;
+ qcom,mdss-dsc-bit-per-component = <8>;
+ qcom,mdss-dsc-bit-per-pixel = <8>;
+ qcom,mdss-dsc-block-prediction-enable;
+ qcom,mdss-dsc-config-by-manufacture-cmd;
+ };
};
};
qcom,panel-supply-entries {
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",
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:
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,
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;
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",
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")) {
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;
"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);
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);
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;
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++;
}
}
+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)
{
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);
* 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;
}
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,
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) {
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) {
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)
}
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;
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) {
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;
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;
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:
if (ret)
goto exit;
- __ioctl_transition_dyn_mode_state(mfd, cmd, 0);
-
switch (cmd) {
case MSMFB_CURSOR:
ret = mdss_fb_cursor(info, argp);
* 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,
};
/**
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;
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) {
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;
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;
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);
}
}
{
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();
/* 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
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;
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;
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;
};