diff options
Diffstat (limited to 'drivers/video/fbdev')
| -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; |
