diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 03a64bd39f22..82827f3e2a47 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -105,7 +105,7 @@ static u32 crtc_flush(struct drm_crtc *crtc, u32 flush_mask) static u32 crtc_flush_all(struct drm_crtc *crtc) { struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); - struct mdp5_hw_mixer *mixer; + struct mdp5_hw_mixer *mixer, *r_mixer; struct drm_plane *plane; uint32_t flush_mask = 0; @@ -120,6 +120,10 @@ static u32 crtc_flush_all(struct drm_crtc *crtc) mixer = mdp5_cstate->pipeline.mixer; flush_mask |= mdp_ctl_flush_mask_lm(mixer->lm); + r_mixer = mdp5_cstate->pipeline.r_mixer; + if (r_mixer) + flush_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); + return crtc_flush(crtc, flush_mask); } @@ -145,7 +149,7 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) if (ctl && !crtc->state->enable) { /* set STAGE_UNUSED for all layers */ - mdp5_ctl_blend(ctl, pipeline, NULL, 0, 0); + mdp5_ctl_blend(ctl, pipeline, NULL, NULL, 0, 0); /* XXX: What to do here? */ /* mdp5_crtc->ctl = NULL; */ } @@ -186,6 +190,12 @@ static inline u32 mdp5_lm_use_fg_alpha_mask(enum mdp_mixer_stage_id stage) } } +/* + * left/right pipe offsets for the stage array used in blend_setup() + */ +#define PIPE_LEFT 0 +#define PIPE_RIGHT 1 + /* * blend_setup() - blend all the planes of a CRTC * @@ -205,10 +215,13 @@ static void blend_setup(struct drm_crtc *crtc) const struct mdp_format *format; struct mdp5_hw_mixer *mixer = pipeline->mixer; uint32_t lm = mixer->lm; + struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; + uint32_t r_lm = r_mixer ? r_mixer->lm : 0; struct mdp5_ctl *ctl = mdp5_cstate->ctl; uint32_t blend_op, fg_alpha, bg_alpha, ctl_blend_flags = 0; unsigned long flags; - enum mdp5_pipe stage[STAGE_MAX + 1] = { SSPP_NONE }; + enum mdp5_pipe stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE }; + enum mdp5_pipe r_stage[STAGE_MAX + 1][MAX_PIPE_STAGE] = { SSPP_NONE }; int i, plane_cnt = 0; bool bg_alpha_enabled = false; u32 mixer_op_mode = 0; @@ -227,7 +240,15 @@ static void blend_setup(struct drm_crtc *crtc) drm_atomic_crtc_for_each_plane(plane, crtc) { pstate = to_mdp5_plane_state(plane->state); pstates[pstate->stage] = pstate; - stage[pstate->stage] = mdp5_plane_pipe(plane); + stage[pstate->stage][PIPE_LEFT] = mdp5_plane_pipe(plane); + /* + * if we have a right mixer, stage the same pipe as we + * have on the left mixer + */ + if (r_mixer) + r_stage[pstate->stage][PIPE_LEFT] = + mdp5_plane_pipe(plane); + plane_cnt++; } @@ -293,12 +314,23 @@ static void blend_setup(struct drm_crtc *crtc) blender(i)), fg_alpha); mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(lm, blender(i)), bg_alpha); + if (r_mixer) { + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(r_lm, + blender(i)), blend_op); + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(r_lm, + blender(i)), fg_alpha); + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(r_lm, + blender(i)), bg_alpha); + } } mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(lm), mixer_op_mode); + if (r_mixer) + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(r_lm), + mixer_op_mode); - mdp5_ctl_blend(ctl, pipeline, stage, plane_cnt, ctl_blend_flags); - + mdp5_ctl_blend(ctl, pipeline, stage, r_stage, plane_cnt, + ctl_blend_flags); out: spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags); } @@ -309,6 +341,7 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc) struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); struct mdp5_kms *mdp5_kms = get_kms(crtc); struct mdp5_hw_mixer *mixer = mdp5_cstate->pipeline.mixer; + struct mdp5_hw_mixer *r_mixer = mdp5_cstate->pipeline.r_mixer; uint32_t lm = mixer->lm; unsigned long flags; struct drm_display_mode *mode; @@ -331,6 +364,10 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc) mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(lm), MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) | MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay)); + if (r_mixer) + mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(r_mixer->lm), + MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) | + MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay)); spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags); } @@ -612,6 +649,10 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc, if (!ctl) return -EINVAL; + /* don't support LM cursors when we we have source split enabled */ + if (mdp5_cstate->pipeline.r_mixer) + return -EINVAL; + if (!handle) { DBG("Cursor off"); cursor_enable = false; @@ -685,6 +726,10 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) uint32_t roi_h; unsigned long flags; + /* don't support LM cursors when we we have source split enabled */ + if (mdp5_cstate->pipeline.r_mixer) + return -EINVAL; + /* In case the CRTC is disabled, just drop the cursor update */ if (unlikely(!crtc->state->enable)) return 0; @@ -714,12 +759,17 @@ mdp5_crtc_atomic_print_state(struct drm_printer *p, { struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(state); struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; + struct mdp5_kms *mdp5_kms = get_kms(state->crtc); if (WARN_ON(!pipeline)) return; drm_printf(p, "\thwmixer=%s\n", pipeline->mixer ? pipeline->mixer->name : "(null)"); + + if (mdp5_kms->caps & MDP_CAP_SRC_SPLIT) + drm_printf(p, "\tright hwmixer=%s\n", pipeline->r_mixer ? + pipeline->r_mixer->name : "(null)"); } static void mdp5_crtc_reset(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c index 9a0109410974..1fdbb936877f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c @@ -172,9 +172,12 @@ int mdp5_ctl_set_pipeline(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline) struct mdp5_kms *mdp5_kms = get_kms(ctl_mgr); struct mdp5_interface *intf = pipeline->intf; struct mdp5_hw_mixer *mixer = pipeline->mixer; + struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm) | mdp_ctl_flush_mask_encoder(intf); + if (r_mixer) + ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); /* Virtual interfaces need not set a display intf (e.g.: Writeback) */ if (!mdp5_cfg_intf_is_virtual(intf->type)) @@ -224,8 +227,11 @@ static void refill_start_mask(struct mdp5_ctl *ctl, { struct mdp5_interface *intf = pipeline->intf; struct mdp5_hw_mixer *mixer = pipeline->mixer; + struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; ctl->start_mask = mdp_ctl_flush_mask_lm(mixer->lm); + if (r_mixer) + ctl->start_mask |= mdp_ctl_flush_mask_lm(r_mixer->lm); /* * Writeback encoder needs to program & flush @@ -282,6 +288,11 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, return -EINVAL; } + if (pipeline->r_mixer) { + dev_err(ctl_mgr->dev->dev, "unsupported configuration"); + return -EINVAL; + } + spin_lock_irqsave(&ctl->hw_lock, flags); blend_cfg = ctl_read(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm)); @@ -344,24 +355,40 @@ static u32 mdp_ctl_blend_ext_mask(enum mdp5_pipe pipe, } } +#define PIPE_LEFT 0 +#define PIPE_RIGHT 1 int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, - enum mdp5_pipe *stage, u32 stage_cnt, u32 ctl_blend_op_flags) + enum mdp5_pipe stage[][MAX_PIPE_STAGE], + enum mdp5_pipe r_stage[][MAX_PIPE_STAGE], + u32 stage_cnt, u32 ctl_blend_op_flags) { struct mdp5_hw_mixer *mixer = pipeline->mixer; + struct mdp5_hw_mixer *r_mixer = pipeline->r_mixer; unsigned long flags; u32 blend_cfg = 0, blend_ext_cfg = 0; + u32 r_blend_cfg = 0, r_blend_ext_cfg = 0; int i, start_stage; if (ctl_blend_op_flags & MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT) { start_stage = STAGE0; blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR; + if (r_mixer) + r_blend_cfg |= MDP5_CTL_LAYER_REG_BORDER_COLOR; } else { start_stage = STAGE_BASE; } for (i = start_stage; stage_cnt && i <= STAGE_MAX; i++) { - blend_cfg |= mdp_ctl_blend_mask(stage[i], i); - blend_ext_cfg |= mdp_ctl_blend_ext_mask(stage[i], i); + blend_cfg |= + mdp_ctl_blend_mask(stage[i][PIPE_LEFT], i); + blend_ext_cfg |= + mdp_ctl_blend_ext_mask(stage[i][PIPE_LEFT], i); + if (r_mixer) { + r_blend_cfg |= + mdp_ctl_blend_mask(r_stage[i][PIPE_LEFT], i); + r_blend_ext_cfg |= + mdp_ctl_blend_ext_mask(r_stage[i][PIPE_LEFT], i); + } } spin_lock_irqsave(&ctl->hw_lock, flags); @@ -371,12 +398,23 @@ int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, mixer->lm), blend_cfg); ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, mixer->lm), blend_ext_cfg); + if (r_mixer) { + ctl_write(ctl, REG_MDP5_CTL_LAYER_REG(ctl->id, r_mixer->lm), + r_blend_cfg); + ctl_write(ctl, REG_MDP5_CTL_LAYER_EXT_REG(ctl->id, r_mixer->lm), + r_blend_ext_cfg); + } spin_unlock_irqrestore(&ctl->hw_lock, flags); ctl->pending_ctl_trigger = mdp_ctl_flush_mask_lm(mixer->lm); + if (r_mixer) + ctl->pending_ctl_trigger |= mdp_ctl_flush_mask_lm(r_mixer->lm); DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", mixer->lm, blend_cfg, blend_ext_cfg); + if (r_mixer) + DBG("lm%d: blend config = 0x%08x. ext_cfg = 0x%08x", + r_mixer->lm, r_blend_cfg, r_blend_ext_cfg); return 0; } diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h index 751dd861cfd8..b63120388dc6 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h @@ -46,6 +46,8 @@ int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, int cursor_id, bool enable); int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable); +#define MAX_PIPE_STAGE 2 + /* * mdp5_ctl_blend() - Blend multiple layers on a Layer Mixer (LM) * @@ -59,8 +61,9 @@ int mdp5_ctl_pair(struct mdp5_ctl *ctlx, struct mdp5_ctl *ctly, bool enable); */ #define MDP5_CTL_BLEND_OP_FLAG_BORDER_OUT BIT(0) int mdp5_ctl_blend(struct mdp5_ctl *ctl, struct mdp5_pipeline *pipeline, - enum mdp5_pipe *stage, u32 stage_cnt, - u32 ctl_blend_op_flags); + enum mdp5_pipe stage[][MAX_PIPE_STAGE], + enum mdp5_pipe r_stage[][MAX_PIPE_STAGE], + u32 stage_cnt, u32 ctl_blend_op_flags); /** * mdp_ctl_flush_mask...() - Register FLUSH masks diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h index fcd067f65a93..d68e92d71afe 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -119,6 +119,7 @@ struct mdp5_plane_state { struct mdp5_pipeline { struct mdp5_interface *intf; struct mdp5_hw_mixer *mixer; + struct mdp5_hw_mixer *r_mixer; /* right mixer */ }; struct mdp5_crtc_state {