diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index 00b778feaba8..9fc942cc627d 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -401,6 +401,10 @@ Optional properties: - 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 @@ -619,6 +623,7 @@ Example: 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>, @@ -650,6 +655,19 @@ Example: 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 { 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; - - /* - * keep a ref count on clocks to prevent them from - * being disabled while switch happens - */ - 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); + /* + * Setup DSC conifg early, as DSI configuration during + * resolution switch would rely on DSC params for + * stream configs. + */ + 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; };