summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h5
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h34
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c235
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c120
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c4
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;