diff options
| author | Ujwal Patel <ujwalp@codeaurora.org> | 2015-10-26 17:50:07 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:47:30 -0700 |
| commit | d287993820a94b404aef44c5a299ccbfa458cb97 (patch) | |
| tree | 79836db21486bf39c7084964e78bc597a13369e9 /drivers | |
| parent | c08198242326c200aeff7dbadb17856d7e58873b (diff) | |
msm: mdss: enable right-only update on DUAL_LM_SINGLE_DISPLAY split mode
Any smart panel with DUAL_LM_SINGLE_DISPLAY split mode with support for
partial update requires runtime topology changes when update is using
only one layer mixer. Specifically, when right-only partial update is
needed, MDP topology needs to switch to ping-pong associated with right
layer mixer and disable left layer mixer path. Add changes to support
these use-cases dynamically.
Now when Display Stream Compression (DSC) is used with this split mode,
there are certain restriction from HW when switching from left+right
update to right-only update. During such scenarios we cannot use right
layer mixer based data path and have to use left layer mixer based
data path. Add quirk based logic to use this mode.
Change-Id: Ic450cab4762337c94a5b1cb14b1d979a83fceee6
Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 5 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.c | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 34 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 235 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c | 120 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 4 |
7 files changed, 294 insertions, 106 deletions
diff --git a/drivers/video/fbdev/msm/mdss.h b/drivers/video/fbdev/msm/mdss.h index 783493c1cd99..2e07fc87701a 100644 --- a/drivers/video/fbdev/msm/mdss.h +++ b/drivers/video/fbdev/msm/mdss.h @@ -153,6 +153,7 @@ enum mdss_hw_quirk { MDSS_QUIRK_BWCPANIC, MDSS_QUIRK_ROTCDP, MDSS_QUIRK_DOWNSCALE_HANG, + MDSS_QUIRK_DSC_RIGHT_ONLY_PU, MDSS_QUIRK_MAX, }; diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 727ce4e7a644..9f27afd9e7fe 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -395,7 +395,10 @@ static inline bool is_pingpong_split(struct msm_fb_data_type *mfd) { return mfd && (mfd->split_mode == MDP_PINGPONG_SPLIT); } - +static inline bool is_dual_lm_single_display(struct msm_fb_data_type *mfd) +{ + return mfd && (mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY); +} static inline bool mdss_fb_is_power_off(struct msm_fb_data_type *mfd) { return mdss_panel_is_power_off(mfd->panel_power_state); diff --git a/drivers/video/fbdev/msm/mdss_mdp.c b/drivers/video/fbdev/msm/mdss_mdp.c index a8887dc41cd3..28216ab8222a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.c +++ b/drivers/video/fbdev/msm/mdss_mdp.c @@ -1248,6 +1248,7 @@ static void mdss_mdp_hw_rev_caps_init(struct mdss_data_type *mdata) set_bit(MDSS_CAPS_3D_MUX_UNDERRUN_RECOVERY_SUPPORTED, mdata->mdss_caps_map); mdss_mdp_init_default_prefill_factors(mdata); + mdss_set_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU); break; case MDSS_MDP_HW_REV_105: case MDSS_MDP_HW_REV_109: diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index d26926a16952..b782f77d4e3f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -1062,6 +1062,40 @@ static inline uint8_t pp_vig_csc_pipe_val(struct mdss_mdp_pipe *pipe) } } +/* + * when DUAL_LM_SINGLE_DISPLAY is used with 2 DSC encoders, DSC_MERGE is + * used during full frame updates. Now when we go from full frame update + * to right-only update, we need to disable DSC_MERGE. However, DSC_MERGE + * is controlled through DSC0_COMMON_MODE register which is double buffered, + * and this double buffer update is tied to LM0. Now for right-only update, + * LM0 will not get double buffer update signal. So DSC_MERGE is not disabled + * for right-only update which is wrong HW state and leads ping-pong timeout. + * Workaround for this is to use LM0->DSC0 pair for right-only update + * and disable DSC_MERGE. + * + * However using LM0->DSC0 pair for right-only update requires many changes + * at various levels of SW. To lower the SW impact and still support + * right-only partial update, keep SW state as it is but swap mixer register + * writes such that we instruct HW to use LM0->DSC0 pair. + * + * This function will return true if such a swap is needed or not. + */ +static inline bool mdss_mdp_is_lm_swap_needed(struct mdss_data_type *mdata, + struct mdss_mdp_ctl *mctl) +{ + if (!mdata || !mctl || !mctl->is_master || + !mctl->panel_data || !mctl->mfd) + return false; + + return (is_dual_lm_single_display(mctl->mfd)) && + (mctl->panel_data->panel_info.partial_update_enabled) && + (mdss_has_quirk(mdata, MDSS_QUIRK_DSC_RIGHT_ONLY_PU)) && + (is_dsc_compression(&mctl->panel_data->panel_info)) && + (mctl->panel_data->panel_info.dsc_enc_total == 2) && + (!mctl->mixer_left->valid_roi) && + (mctl->mixer_right->valid_roi); +} + irqreturn_t mdss_mdp_isr(int irq, void *ptr); void mdss_mdp_irq_clear(struct mdss_data_type *mdata, u32 intr_type, u32 intf_num); diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c index 57f9ca1ee71d..3a888597dcc3 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c +++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c @@ -2399,8 +2399,21 @@ static inline void mdss_mdp_ctl_dsc_enable(struct mdss_mdp_mixer *mixer) static inline void mdss_mdp_ctl_dsc_disable(struct mdss_mdp_mixer *mixer) { + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + char __iomem *offset = mdata->mdp_base; + mdss_mdp_pingpong_write(mixer->pingpong_base, MDSS_MDP_REG_PP_DSC_MODE, 0); + + if (mixer->num == MDSS_MDP_INTF_LAYERMIXER0) { + offset += MDSS_MDP_DSC_0_OFFSET; + } else if (mixer->num == MDSS_MDP_INTF_LAYERMIXER1) { + offset += MDSS_MDP_DSC_1_OFFSET; + } else { + pr_err("invalid mixer numer=%d\n", mixer->num); + return; + } + writel_relaxed(0, offset + MDSS_MDP_REG_DSC_COMMON_MODE); } static void mdss_mdp_ctl_dsc_config(struct mdss_mdp_mixer *mixer, @@ -2469,7 +2482,7 @@ static void mdss_mdp_ctl_dsc_config(struct mdss_mdp_mixer *mixer, data = dsc->chunk_size << 16; writel_relaxed(data, offset + MDSS_MDP_REG_DSC_CHUNK_SIZE); - pr_debug("mix%d pic_w=%d pic_h=%d, slice_h=%d slice_w=%d, chunk=%d\n", + pr_debug("mix%d pic_w=%d pic_h=%d, slice_w=%d slice_h=%d, chunk=%d\n", mixer->num, dsc->pic_width, dsc->pic_height, dsc->slice_width, dsc->slice_height, dsc->chunk_size); MDSS_XLOG(mixer->num, dsc->pic_width, dsc->pic_height, @@ -2566,10 +2579,10 @@ static void mdss_mdp_ctl_dsc_config_thresh(struct mdss_mdp_mixer *mixer, } } -/* called for each ctl */ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, struct mdss_panel_info *pinfo) { + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); struct mdss_mdp_mixer *mixer_left = ctl->mixer_left; struct mdss_mdp_mixer *mixer_right = NULL; struct dsc_desc *dsc = &pinfo->dsc; @@ -2577,56 +2590,63 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, u32 mode = 0; bool recalc_dsc_params = false; bool ich_reset_override = false; - bool dsc_merge = false; + bool dsc_merge = false, mux_3d = false; + bool left_valid = false, right_valid = false; + + if (!ctl->is_master) { + pr_debug("skip slave ctl because master will program for both\n"); + return; + } if (pinfo->type == MIPI_VIDEO_PANEL) mode = BIT(2); /* pingpong split with DSC needs to be handled */ if (is_split_lm(ctl->mfd)) { - struct mdss_mdp_ctl *main_ctl; - - if (ctl->is_master) - main_ctl = ctl; - else - main_ctl = mdss_mdp_get_main_ctl(ctl); - - if (!main_ctl) { - pr_err("%pS: invalid input\n", - __builtin_return_address(0)); - return; + mixer_right = ctl->mixer_right; + if (is_dual_lm_single_display(ctl->mfd)) { + if (pinfo->dsc_enc_total == 2) { + /* DSC Merge */ + if (mdss_mdp_is_both_lm_valid(ctl)) { + mode |= BIT(1); + dsc_merge = true; + } + } else { + mux_3d = true; + } } /* * two independent decoders on DDIC requires * split 2p2d mode but it is not supported yet. */ - if (mdss_mdp_is_both_lm_valid(main_ctl)) + if (mdss_mdp_is_both_lm_valid(ctl) && !mux_3d) mode |= BIT(0); /* assumming 1 decoder on panel side */ - - if (main_ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { - - mixer_right = main_ctl->mixer_right; - - /* DSC Merge */ - if ((pinfo->dsc_enc_total == 2) && - (mdss_mdp_is_both_lm_valid(main_ctl))) { - mode |= BIT(1); - dsc_merge = true; - } - } } - if (mixer_left->valid_roi) { + left_valid = mixer_left->valid_roi; + right_valid = mixer_right && mixer_right->valid_roi; + + if (left_valid) { pic_width = mixer_left->roi.w; pic_height = mixer_left->roi.h; recalc_dsc_params = true; } - if (mixer_right && mixer_right->valid_roi) { + if (mixer_right && right_valid) { pic_width += mixer_right->roi.w; pic_height = mixer_right->roi.h; /* height on both lm is same */ - recalc_dsc_params = true; + + if (is_dual_lm_single_display(ctl->mfd)) { + recalc_dsc_params = true; + } else { /* DUAL_LM_DUAL_DISPLAY */ + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + struct mdss_panel_info *spinfo = + &sctl->panel_data->panel_info; + + mdss_dsc_parameters_calc(&spinfo->dsc, + pic_width, pic_height); + } } /* re-calculate DSC params before configuring them to MDP */ @@ -2653,7 +2673,18 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, (dsc->slice_width == dsc->pic_width)) ich_reset_override = true; - if (mixer_left->valid_roi) { + /* + * From this point onwards, left_valid and right_valid variables + * will represent only DSC encoders and does not represent use of + * layer mixers. So if both are valid, both encoders are used. If + * left_valid is true then left DSC encoder is used, same for right. + */ + if (mdss_mdp_is_lm_swap_needed(mdata, ctl)) { + right_valid = false; + left_valid = true; + } + + if (left_valid) { mdss_mdp_ctl_dsc_config(mixer_left, dsc, mode, ich_reset_override); mdss_mdp_ctl_dsc_config_thresh(mixer_left, pinfo); @@ -2663,7 +2694,12 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, } if (mixer_right) { - if (mixer_right->valid_roi) { + bool enable_right_dsc = right_valid; + + if (mux_3d && left_valid) + enable_right_dsc = false; + + if (enable_right_dsc) { mdss_mdp_ctl_dsc_config(mixer_right, dsc, mode, ich_reset_override); mdss_mdp_ctl_dsc_config_thresh(mixer_right, pinfo); @@ -2673,13 +2709,11 @@ void mdss_mdp_ctl_dsc_setup(struct mdss_mdp_ctl *ctl, } } pr_debug("mix%d: valid_roi=%d mix%d: valid_roi=%d mode=%d, pic_dim:%dx%d\n", - mixer_left->num, mixer_left->valid_roi, - mixer_right ? mixer_right->num : -1, - mixer_right ? mixer_right->valid_roi : -1, + mixer_left->num, left_valid, + mixer_right ? mixer_right->num : -1, right_valid, mode, pic_width, pic_height); - MDSS_XLOG(mixer_left->num, mixer_left->valid_roi, - mixer_right ? mixer_right->num : -1, - mixer_right ? mixer_right->valid_roi : -1, + MDSS_XLOG(mixer_left->num, left_valid, + mixer_right ? mixer_right->num : -1, right_valid, mode, pic_width, pic_height); } @@ -2766,7 +2800,7 @@ int mdss_mdp_ctl_setup(struct mdss_mdp_ctl *ctl) max_mixer_width = ctl->mdata->max_mixer_width; - split_fb = (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY && + split_fb = ((is_dual_lm_single_display(ctl->mfd)) && (ctl->mfd->split_fb_left <= max_mixer_width) && (ctl->mfd->split_fb_right <= max_mixer_width)) ? 1 : 0; pr_debug("max=%d xres=%d left=%d right=%d\n", max_mixer_width, @@ -3571,8 +3605,7 @@ int mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl, bool is_recovery) if (mixer) { mdss_mdp_pipe_reset(mixer, is_recovery); - if (ctl->mfd && - (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY)) + if (is_dual_lm_single_display(ctl->mfd)) mdss_mdp_pipe_reset(ctl->mixer_right, is_recovery); } @@ -3654,7 +3687,7 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, mdss_mdp_set_mixer_roi(sctl->mixer_left, r_roi); sctl->roi = sctl->mixer_left->roi; - } else if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) { + } else if (is_dual_lm_single_display(ctl->mfd)) { mdss_mdp_set_mixer_roi(ctl->mixer_right, r_roi); @@ -3662,9 +3695,11 @@ void mdss_mdp_set_roi(struct mdss_mdp_ctl *ctl, ctl->roi.w += ctl->mixer_right->roi.w; /* right_only, update roi.x as per CTL ROI guidelines */ - if (!ctl->mixer_left->valid_roi) + if (!ctl->mixer_left->valid_roi) { + ctl->roi = ctl->mixer_right->roi; ctl->roi.x = left_lm_w_from_mfd(ctl->mfd) + ctl->mixer_right->roi.x; + } } /* @@ -3730,7 +3765,7 @@ u32 mdss_mdp_get_mixer_extn_mask(u32 pipe_num, u32 stage) } static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, - int mixer_mux) + int mixer_mux, bool lm_swap) { int i; int stage, screen_state, outsize; @@ -3741,47 +3776,59 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, struct mdss_mdp_pipe *pipe; struct mdss_mdp_ctl *ctl = NULL; struct mdss_data_type *mdata = mdss_mdp_get_mdata(); - struct mdss_mdp_mixer *mixer = mdss_mdp_mixer_get(master_ctl, + struct mdss_mdp_mixer *mixer_hw = mdss_mdp_mixer_get(master_ctl, mixer_mux); + struct mdss_mdp_mixer *mixer; - if (!mixer) + if (!mixer_hw) return; - ctl = mixer->ctl; + ctl = mixer_hw->ctl; if (!ctl) return; - mixer->params_changed = 0; + mixer_hw->params_changed = 0; /* check if mixer setup for rotator is needed */ - if (mixer->rotator_mode) { + if (mixer_hw->rotator_mode) { int nmixers = mdata->nmixers_intf + mdata->nmixers_wb; for (i = 0; i < nmixers; i++) mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_LAYER(i), 0); return; } + if (lm_swap) { + if (mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) + mixer = mdss_mdp_mixer_get(master_ctl, + MDSS_MDP_MIXER_MUX_LEFT); + else + mixer = mdss_mdp_mixer_get(master_ctl, + MDSS_MDP_MIXER_MUX_RIGHT); + } else { + mixer = mixer_hw; + } + if (!mixer->valid_roi) { /* * resetting mixer config is specifically needed when split * mode is MDP_DUAL_LM_SINGLE_DISPLAY but update is only on * one side. */ - off = __mdss_mdp_ctl_get_mixer_off(mixer); + off = __mdss_mdp_ctl_get_mixer_off(mixer_hw); mdss_mdp_ctl_write(ctl, off, 0); /* Program ctl layer extension bits */ mdss_mdp_ctl_write(ctl, off + MDSS_MDP_REG_CTL_LAYER_EXTN_OFFSET, 0); - MDSS_XLOG(mixer->num, XLOG_FUNC_EXIT); + MDSS_XLOG(mixer->num, mixer_hw->num, XLOG_FUNC_EXIT); return; } - trace_mdp_mixer_update(mixer->num); - pr_debug("setup mixer=%d\n", mixer->num); + trace_mdp_mixer_update(mixer_hw->num); + pr_debug("setup mixer=%d hw=%d\n", mixer->num, mixer_hw->num); screen_state = ctl->force_screen_state; outsize = (mixer->roi.h << 16) | mixer->roi.w; - mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OUT_SIZE, outsize); + mdp_mixer_write(mixer_hw, MDSS_MDP_REG_LM_OUT_SIZE, outsize); if (screen_state == MDSS_SCREEN_FORCE_BLANK) { mixercfg = MDSS_MDP_LM_BORDER_COLOR; @@ -3810,8 +3857,9 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, stage = i / MAX_PIPES_PER_STAGE; if (stage != pipe->mixer_stage) { - pr_err("pipe%d mixer:%d stage mismatch. pipe->mixer_stage=%d, mixer->stage_pipe=%d. skip staging it\n", - pipe->num, mixer->num, pipe->mixer_stage, stage); + pr_err("pipe%d mixer:%d mixer:%d stage mismatch. pipe->mixer_stage=%d, mixer->stage_pipe=%d. skip staging it\n", + pipe->num, mixer->num, mixer->num, + pipe->mixer_stage, stage); mixer->stage_pipe[i] = NULL; continue; } @@ -3907,51 +3955,52 @@ static void mdss_mdp_mixer_setup(struct mdss_mdp_ctl *master_ctl, pr_debug("stg=%d op=%x fg_alpha=%x bg_alpha=%x\n", stage, blend_op, fg_alpha, bg_alpha); - mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_OP_MODE, blend_op); - mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA, - fg_alpha); - mdp_mixer_write(mixer, off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA, - bg_alpha); + mdp_mixer_write(mixer_hw, + off + MDSS_MDP_REG_LM_OP_MODE, blend_op); + mdp_mixer_write(mixer_hw, + off + MDSS_MDP_REG_LM_BLEND_FG_ALPHA, fg_alpha); + mdp_mixer_write(mixer_hw, + off + MDSS_MDP_REG_LM_BLEND_BG_ALPHA, bg_alpha); } if (mixer->cursor_enabled) mixercfg |= MDSS_MDP_LM_CURSOR_OUT; update_mixer: - if (mixer->num == MDSS_MDP_INTF_LAYERMIXER3) + if (mixer_hw->num == MDSS_MDP_INTF_LAYERMIXER3) ctl->flush_bits |= BIT(20); - else if (mixer->type == MDSS_MDP_MIXER_TYPE_WRITEBACK) - ctl->flush_bits |= BIT(9) << mixer->num; + else if (mixer_hw->type == MDSS_MDP_MIXER_TYPE_WRITEBACK) + ctl->flush_bits |= BIT(9) << mixer_hw->num; else - ctl->flush_bits |= BIT(6) << mixer->num; + ctl->flush_bits |= BIT(6) << mixer_hw->num; /* Read GC enable/disable status on LM */ mixer_op_mode |= - (mdp_mixer_read(mixer, MDSS_MDP_REG_LM_OP_MODE) & BIT(0)); + (mdp_mixer_read(mixer_hw, MDSS_MDP_REG_LM_OP_MODE) & BIT(0)); if (mixer->src_split_req && mixer_mux == MDSS_MDP_MIXER_MUX_RIGHT) mixer_op_mode |= BIT(31); - mdp_mixer_write(mixer, MDSS_MDP_REG_LM_OP_MODE, mixer_op_mode); + mdp_mixer_write(mixer_hw, MDSS_MDP_REG_LM_OP_MODE, mixer_op_mode); - mdp_mixer_write(mixer, MDSS_MDP_REG_LM_BORDER_COLOR_0, + mdp_mixer_write(mixer_hw, MDSS_MDP_REG_LM_BORDER_COLOR_0, (mdata->bcolor0 & 0xFFF) | ((mdata->bcolor1 & 0xFFF) << 16)); - mdp_mixer_write(mixer, MDSS_MDP_REG_LM_BORDER_COLOR_1, + mdp_mixer_write(mixer_hw, MDSS_MDP_REG_LM_BORDER_COLOR_1, mdata->bcolor2 & 0xFFF); - off = __mdss_mdp_ctl_get_mixer_off(mixer); + off = __mdss_mdp_ctl_get_mixer_off(mixer_hw); mdss_mdp_ctl_write(ctl, off, mixercfg); /* Program ctl layer extension bits */ mdss_mdp_ctl_write(ctl, off + MDSS_MDP_REG_CTL_LAYER_EXTN_OFFSET, mixercfg_extn); - pr_debug("mixer=%d cfg=0%08x cfg_extn=0x%08x op_mode=0x%08x w=%d h=%d bc0=0x%x bc1=0x%x\n", - mixer->num, mixercfg, mixercfg_extn, + pr_debug("mixer=%d hw=%d cfg=0%08x cfg_extn=0x%08x op_mode=0x%08x w=%d h=%d bc0=0x%x bc1=0x%x\n", + mixer->num, mixer_hw->num, mixercfg, mixercfg_extn, mixer_op_mode, mixer->roi.w, mixer->roi.h, (mdata->bcolor0 & 0xFFF) | ((mdata->bcolor1 & 0xFFF) << 16), mdata->bcolor2 & 0xFFF); - MDSS_XLOG(mixer->num, mixercfg, mixercfg_extn, mixer_op_mode, - mixer->roi.h, mixer->roi.w); + MDSS_XLOG(mixer->num, mixer_hw->num, mixercfg, mixercfg_extn, + mixer_op_mode, mixer->roi.h, mixer->roi.w); } int mdss_mdp_mixer_addr_setup(struct mdss_data_type *mdata, @@ -4532,14 +4581,16 @@ int mdss_mdp_display_wait4pingpong(struct mdss_mdp_ctl *ctl, bool use_lock) static void mdss_mdp_force_border_color(struct mdss_mdp_ctl *ctl) { struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); + bool lm_swap = mdss_mdp_is_lm_swap_needed(mdata, ctl); ctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK; if (sctl) sctl->force_screen_state = MDSS_SCREEN_FORCE_BLANK; - mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_LEFT); - mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_RIGHT); + mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_LEFT, lm_swap); + mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_RIGHT, lm_swap); ctl->force_screen_state = MDSS_SCREEN_DEFAULT; if (sctl) @@ -4595,12 +4646,17 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, !mdss_mdp_ctl_perf_get_transaction_status(sctl); } - /* left update */ - if (ctl->mixer_left->valid_roi) + /* + * left update on any topology or + * any update on MDP_DUAL_LM_SINGLE_DISPLAY topology. + */ + if (ctl->mixer_left->valid_roi || + (is_dual_lm_single_display(ctl->mfd) && + ctl->mixer_right->valid_roi)) mdss_mdp_ctl_perf_set_transaction_status(ctl, PERF_SW_COMMIT_STATE, PERF_STATUS_BUSY); - /* right update */ + /* right update on MDP_DUAL_LM_DUAL_DISPLAY */ if (sctl && sctl->mixer_left->valid_roi) mdss_mdp_ctl_perf_set_transaction_status(sctl, PERF_SW_COMMIT_STATE, PERF_STATUS_BUSY); @@ -4612,6 +4668,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, if (is_bw_released || ctl->force_screen_state || (ctl->mixer_left->params_changed) || (ctl->mixer_right && ctl->mixer_right->params_changed)) { + bool lm_swap = mdss_mdp_is_lm_swap_needed(mdata, ctl); + ATRACE_BEGIN("prepare_fnc"); if (ctl->ops.prepare_fnc) ret = ctl->ops.prepare_fnc(ctl, arg); @@ -4625,8 +4683,8 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, ATRACE_BEGIN("mixer_programming"); mdss_mdp_ctl_perf_update(ctl, 1, false); - mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_LEFT); - mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_RIGHT); + mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_LEFT, lm_swap); + mdss_mdp_mixer_setup(ctl, MDSS_MDP_MIXER_MUX_RIGHT, lm_swap); mdss_mdp_ctl_write(ctl, MDSS_MDP_REG_CTL_TOP, ctl->opmode); ctl->flush_bits |= BIT(17); /* CTL */ @@ -4748,6 +4806,21 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg, mdss_mdp_ctl_pp_split_display_enable(pp_split, ctl); } else { + /* + * if single lm update on 3D mux topology, clear it. + */ + if ((is_dual_lm_single_display(ctl->mfd)) && + (ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE) && + (!mdss_mdp_is_both_lm_valid(ctl))) { + + u32 opmode = mdss_mdp_ctl_read(ctl, + MDSS_MDP_REG_CTL_TOP); + opmode &= ~(0xF << 19); /* clear 3D Mux */ + + mdss_mdp_ctl_write(ctl, + MDSS_MDP_REG_CTL_TOP, opmode); + } + ctl->panel_data->panel_info.roi = ctl->roi; if (sctl && sctl->panel_data) sctl->panel_data->panel_info.roi = sctl->roi; diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c index e39c4c5daab0..b69c14c9b80a 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c +++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c @@ -35,6 +35,10 @@ static DEFINE_MUTEX(cmd_clk_mtx); struct mdss_mdp_cmd_ctx { struct mdss_mdp_ctl *ctl; u32 pp_num; + + bool right_only_update; /* set only if DUAL_LM_SINGLE_DISPLAY + PU */ + u32 right_only_pp_num; /* used only if DUAL_LM_SINGLE_DISPLAY + PU */ + u8 ref_cnt; struct completion stop_comp; struct completion readptr_done; @@ -175,6 +179,22 @@ static int mdss_mdp_tearcheck_enable(struct mdss_mdp_ctl *ctl, bool enable) mdss_mdp_pingpong_write(mdata->slave_pingpong_base, MDSS_MDP_REG_PP_TEAR_CHECK_EN, (te ? te->tear_check_en : 0) && enable); + + /* + * In case of DUAL_LM_SINGLE_DISPLAY, always keep right PP enabled + * if partial update is enabled. So when right-only update comes then + * by changing CTL topology, HW switches directly to right PP. + */ + if (ctl->panel_data->panel_info.partial_update_enabled && + is_dual_lm_single_display(ctl->mfd)) { + + mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT); + mdss_mdp_pingpong_write(mixer->pingpong_base, + MDSS_MDP_REG_PP_TEAR_CHECK_EN, + (te ? te->tear_check_en : 0) && enable); + + } + return 0; } @@ -264,7 +284,6 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, int rc = 0; struct mdss_mdp_mixer *mixer; struct mdss_mdp_ctl *ctl = ctx->ctl; - struct mdss_panel_info *pinfo = &ctl->panel_data->panel_info; mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT); if (mixer) { @@ -273,8 +292,14 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx, goto err; } - if (!(ctl->opmode & MDSS_MDP_CTL_OP_PACK_3D_ENABLE) && - !is_dsc_compression(pinfo)) { + /* + * In case of DUAL_LM_SINGLE_DISPLAY, always keep right PP enabled + * if partial update is enabled. So when right-only update comes then + * by changing CTL topology, HW switches directly to right PP. + */ + if (ctl->panel_data->panel_info.partial_update_enabled && + is_dual_lm_single_display(ctl->mfd)) { + mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT); if (mixer) rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked); @@ -913,11 +938,14 @@ static void mdss_mdp_cmd_intf_recovery(void *data, int event) spin_lock_irqsave(&ctx->koff_lock, flags); if (reset_done && atomic_read(&ctx->koff_cnt)) { - pr_debug("%s: intf_num=%d\n", __func__, - ctx->ctl->intf_num); + u32 pp_num = ctx->right_only_update ? ctx->right_only_pp_num : + ctx->pp_num; + + pr_debug("%s: intf_num=%d\n", __func__, ctx->ctl->intf_num); atomic_dec(&ctx->koff_cnt); + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, - ctx->pp_num); + pp_num); } spin_unlock_irqrestore(&ctx->koff_lock, flags); } @@ -928,6 +956,7 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) struct mdss_mdp_cmd_ctx *ctx = ctl->intf_ctx[MASTER_CTX]; struct mdss_mdp_vsync_handler *tmp; ktime_t vsync_time; + u32 pp_num; if (!ctx) { pr_err("%s: invalid ctx\n", __func__); @@ -945,8 +974,12 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) spin_unlock(&ctx->clk_lock); spin_lock(&ctx->koff_lock); - mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num); - MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); + + pp_num = ctx->right_only_update ? ctx->right_only_pp_num : + ctx->pp_num; + mdss_mdp_irq_disable_nosync(MDSS_MDP_IRQ_PING_PONG_COMP, pp_num); + + MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt), pp_num); if (atomic_add_unless(&ctx->koff_cnt, -1, 0)) { if (atomic_read(&ctx->koff_cnt)) @@ -964,11 +997,11 @@ static void mdss_mdp_cmd_pingpong_done(void *arg) pr_err("%s: should not have pingpong interrupt!\n", __func__); } - trace_mdp_cmd_pingpong_done(ctl, ctx->pp_num, - atomic_read(&ctx->koff_cnt)); - pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d kcnt=%d\n", __func__, - ctl->num, ctl->intf_num, ctx->pp_num, - atomic_read(&ctx->koff_cnt)); + pr_debug("%s: ctl_num=%d intf_num=%d ctx=%d cnt=%d\n", __func__, + ctl->num, ctl->intf_num, pp_num, + atomic_read(&ctx->koff_cnt)); + + trace_mdp_cmd_pingpong_done(ctl, pp_num, atomic_read(&ctx->koff_cnt)); spin_unlock(&ctx->koff_lock); } @@ -1419,16 +1452,19 @@ static int mdss_mdp_cmd_wait4pingpong(struct mdss_mdp_ctl *ctl, void *arg) atomic_read(&ctx->koff_cnt)); if (rc <= 0) { - u32 status, mask; + u32 status, mask, pp_num; - mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + ctx->pp_num); + pp_num = ctx->right_only_update ? + ctx->right_only_pp_num : ctx->pp_num; + + mask = BIT(MDSS_MDP_IRQ_PING_PONG_COMP + pp_num); status = mask & readl_relaxed(ctl->mdata->mdp_base + MDSS_MDP_REG_INTR_STATUS); + if (status) { pr_warn("pp done but irq not triggered\n"); mdss_mdp_irq_clear(ctl->mdata, - MDSS_MDP_IRQ_PING_PONG_COMP, - ctx->pp_num); + MDSS_MDP_IRQ_PING_PONG_COMP, pp_num); local_irq_save(flags); mdss_mdp_cmd_pingpong_done(ctl); local_irq_restore(flags); @@ -1527,7 +1563,7 @@ static void mdss_mdp_cmd_dsc_reconfig(struct mdss_mdp_ctl *ctl) sctl = mdss_mdp_get_split_ctl(ctl); changed = ctl->mixer_left->roi_changed; - if (ctl->mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY) + if (is_dual_lm_single_display(ctl->mfd)) changed |= ctl->mixer_right->roi_changed; if (changed) @@ -1733,6 +1769,8 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) { struct mdss_mdp_ctl *sctl = NULL; struct mdss_mdp_cmd_ctx *ctx, *sctx = NULL; + u32 pp_num; + struct mdss_data_type *mdata = mdss_mdp_get_mdata(); ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX]; if (!ctx) { @@ -1771,8 +1809,18 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) if (__mdss_mdp_cmd_is_panel_power_off(ctx)) mdss_mdp_cmd_panel_on(ctl, sctl); - MDSS_XLOG(ctl->num, ctl->roi.x, ctl->roi.y, ctl->roi.w, - ctl->roi.h); + pp_num = ctx->pp_num; + if (is_dual_lm_single_display(ctl->mfd) && + !ctl->mixer_left->valid_roi && + !mdss_mdp_is_lm_swap_needed(mdata, ctl)) { + ctx->right_only_update = true; + pp_num = ctx->right_only_pp_num; + } else { + ctx->right_only_update = false; + } + + MDSS_XLOG(ctl->num, pp_num, + ctl->roi.x, ctl->roi.y, ctl->roi.w, ctl->roi.h); atomic_inc(&ctx->koff_cnt); if (sctx) @@ -1815,7 +1863,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) wait_for_completion(&ctx->readptr_done); } - mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num); + mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, pp_num); if (sctx) mdss_mdp_irq_enable(MDSS_MDP_IRQ_PING_PONG_COMP, sctx->pp_num); @@ -1837,7 +1885,7 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg) } mb(); - MDSS_XLOG(ctl->num, atomic_read(&ctx->koff_cnt)); + MDSS_XLOG(ctl->num, pp_num, atomic_read(&ctx->koff_cnt)); return 0; } @@ -1923,6 +1971,16 @@ int mdss_mdp_cmd_ctx_stop(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num, NULL, NULL); + /* + * In case of DUAL_LM_SINGLE_DISPLAY, right PP is always enabled + * if partial update is enabled. So disable interrupt callback + * when not needed. + */ + if (ctl->panel_data->panel_info.partial_update_enabled && + is_dual_lm_single_display(ctl->mfd)) + mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, + ctx->right_only_pp_num, NULL, NULL); + memset(ctx, 0, sizeof(*ctx)); return 0; @@ -2241,6 +2299,24 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl, mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num, mdss_mdp_cmd_pingpong_done, ctl); + /* + * In case of DUAL_LM_SINGLE_DISPLAY with partial update enabled, right + * PP is used when right-only update is committed. For such use-case, + * separate corresponding interrupt callback needs to be registered. + */ + if (ctl->panel_data->panel_info.partial_update_enabled && + is_dual_lm_single_display(ctl->mfd)) { + + ctx->right_only_pp_num = ctl->mixer_right->num; + + pr_debug("%s: left_pp=%d right_pp=%d\n", __func__, + ctx->pp_num, ctx->right_only_pp_num); + + mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, + ctx->right_only_pp_num, + mdss_mdp_cmd_pingpong_done, ctl); + } + ret = mdss_mdp_cmd_tearcheck_setup(ctx, false); if (ret) pr_err("tearcheck setup failed\n"); diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index f8c41c4dc97b..d042bb3ff409 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -4538,8 +4538,8 @@ static void mdss_mdp_set_lm_flag(struct msm_fb_data_type *mfd) mfd->split_mode = MDP_DUAL_LM_SINGLE_DISPLAY; mfd->split_fb_left = width; mfd->split_fb_right = width; - } else if (mfd->split_mode == MDP_DUAL_LM_SINGLE_DISPLAY && - width <= mdata->max_mixer_width) { + } else if (is_dual_lm_single_display(mfd) && + (width <= mdata->max_mixer_width)) { mfd->split_mode = MDP_SPLIT_MODE_NONE; mfd->split_fb_left = 0; mfd->split_fb_right = 0; |
