From 6489c0aef1e0d776ea5fc0620cb58ec439fb6bb2 Mon Sep 17 00:00:00 2001 From: Ujwal Patel Date: Tue, 22 Sep 2015 19:02:49 -0700 Subject: [PATCH] msm: mdss: fix dsi underflow during partial updates on DSC based panels When 2 soft slices per DSC encoder without merge is used, HW expects certain DSI pixel clock to MDP clock ratio. If not maintained, DSI can underflow. This happens if full-frame is split into 4 slices, thus requiring 2 DSC encoders, 2 soft slices per encoder. Now if partial update frame is left-only or right-only with 2 slices then normal topology would dictate using 1 DSC encoder with 2 soft slices. However during partial update, we don't change the pixel clock, but mdp clock is reduced because less number of pixels needs to be processed. This changes the ratio mentioned earlier and DSI underflows. To fix this, either we increase the MDP clock rate or change the topology such a way that we use 2 DSC encoders with 1 slice each. Implement later option to avoid increasing MDP clock. Change-Id: Ia37d8045baefcd1e680902446b4725d279db6a89 Signed-off-by: Ujwal Patel --- drivers/video/fbdev/msm/mdss.h | 1 + drivers/video/fbdev/msm/mdss_mdp.c | 1 + drivers/video/fbdev/msm/mdss_mdp_ctl.c | 46 ++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 2e07fc87701a..212b752016de 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -154,6 +154,7 @@ enum mdss_hw_quirk { MDSS_QUIRK_ROTCDP, MDSS_QUIRK_DOWNSCALE_HANG, MDSS_QUIRK_DSC_RIGHT_ONLY_PU, + MDSS_QUIRK_DSC_2SLICE_PU_THRPUT, MDSS_QUIRK_MAX, }; diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index 28216ab8222a..fee51562bad5 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1249,6 +1249,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) mdata->mdss_caps_map); mdss_mdp_init_default_prefill_factors(mdata); mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); + mdss_set_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT); break; case MDSS_MDP_HW_REV_105: case MDSS_MDP_HW_REV_109: diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 3a888597dcc3..9611a4e6e41f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -2430,9 +2430,6 @@ static void mdss_mdp_ctl_dsc_config(struct mdss_mdp_mixer *mixer, mdss_mdp_pingpong_write(mixer->pingpong_base, MDSS_MDP_REG_PP_DCE_DATA_OUT_SWAP, data); - /* dce0_sel->pp0, dce1_sel->pp1 */ - writel_relaxed(0x0, offset + MDSS_MDP_REG_DCE_SEL); - if (mixer->num == MDSS_MDP_INTF_LAYERMIXER0) { offset += MDSS_MDP_DSC_0_OFFSET; } else if (mixer->num == MDSS_MDP_INTF_LAYERMIXER1) { @@ -2684,6 +2681,49 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, left_valid = true; } + if ((is_dual_lm_single_display(ctl->mfd)) && + (pinfo->partial_update_enabled) && + (pinfo->dsc_enc_total == 2) && (dsc->full_frame_slices == 4) && + (mdss_has_quirk(mdata, MDSS_QUIRK_DSC_2SLICE_PU_THRPUT))) { + + if (mdss_mdp_is_both_lm_valid(ctl)) { + /* left + right */ + + pr_debug("full line (4 slices) or middle 2 slice partial update\n"); + writel_relaxed(0x0, + mdata->mdp_base + mdata->ppb[0].ctl_off); + writel_relaxed(0x0, + mdata->mdp_base + MDSS_MDP_REG_DCE_SEL); + } else if (mixer_left->valid_roi || mixer_right->valid_roi) { + /* left-only or right-only */ + + u32 this_frame_slices = + dsc->pic_width / dsc->slice_width; + + if (this_frame_slices == 2) { + pr_debug("2 slice parital update, use merge\n"); + + /* tandem + merge */ + mode = BIT(1) | BIT(0); + + right_valid = true; + left_valid = true; + + writel_relaxed(0x2 << 4, mdata->mdp_base + + mdata->ppb[0].ctl_off); + writel_relaxed(BIT(0), + mdata->mdp_base + MDSS_MDP_REG_DCE_SEL); + } else { + pr_debug("only one slice partial update\n"); + writel_relaxed(0x0, + mdata->mdp_base + + mdata->ppb[0].ctl_off); + writel_relaxed(0x0, + mdata->mdp_base + MDSS_MDP_REG_DCE_SEL); + } + } + } + if (left_valid) { mdss_mdp_ctl_dsc_config(mixer_left, dsc, mode, ich_reset_override);