OSDN Git Service

msm: mdss: add dynamic resolution switch support for DSC panels
authorVeera Sundaram Sankaran <veeras@codeaurora.org>
Fri, 15 Apr 2016 18:57:24 +0000 (11:57 -0700)
committerKyle Yan <kyan@codeaurora.org>
Tue, 5 Jul 2016 22:30:48 +0000 (15:30 -0700)
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>
Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt
drivers/video/fbdev/msm/mdss_dsi.c
drivers/video/fbdev/msm/mdss_dsi_panel.c
drivers/video/fbdev/msm/mdss_fb.c
drivers/video/fbdev/msm/mdss_fb.h
drivers/video/fbdev/msm/mdss_mdp_ctl.c
drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
drivers/video/fbdev/msm/mdss_mdp_overlay.c
drivers/video/fbdev/msm/mdss_panel.h

index 00b778f..9fc942c 100644 (file)
@@ -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 {
index 8f1ab77..1b46c17 100644 (file)
@@ -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:
index 707b1cb..ea706cb 100644 (file)
@@ -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++;
index 893c073..8f2a70d 100644 (file)
@@ -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);
index af670f6..56997e4 100644 (file)
@@ -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,
 };
 
 /**
index 96f2375..f97a9f9 100644 (file)
@@ -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) {
index 4874e05..e54898e 100644 (file)
@@ -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);
                }
        }
index 388e005..78e448f 100644 (file)
@@ -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;
index 1b4d7d8..8517a60 100644 (file)
@@ -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;
 };