Add another mdp5_hw_mixer pointer (r_mixer) in mdp5_crtc_state. This mixer will be used to generate the right half of the scanout. With Source Split, a SSPP can now be connected to 2 Layer Mixers, but has to be at the same blend level (stage #) on both Layer Mixers. A drm_plane that has a lesser width than the max width supported, will comprise of a single SSPP/hwpipe, staged on both the Layer Mixers at the same blend level. A plane that is greater than max width will comprise of 2 SSPPs, with the 'left' SSPP staged on the left LM, and the 'right' SSPP staged on the right LM at the same blend level. For now, the drm_plane consists of only one SSPP, therefore, it needs to be staged on both the LMs in blend_setup() and mdp5_ctl_blend(). We'll extend this logic to support 2 hwpipes per plane later. The crtc cursor ops (using the LM cursors, not SSPP cursors) simply return an error if they're called when the right mixer is assigned to the CRTC state. With source split is enabled, we're expected to only SSPP cursors. This commit adds code that configures the right mixer, but the r_mixer itself isn't assigned at the moment. Signed-off-by: Archit Taneja <architt@xxxxxxxxxxxxxx> --- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 62 ++++++++++++++++++++++++++++---- drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c | 44 +++++++++++++++++++++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h | 7 ++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h | 1 + 4 files changed, 103 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index f382c3405786..5bffef6ec9dc 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); } @@ -151,7 +155,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; */ } @@ -193,6 +197,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 * * If no base layer is available, border will be enabled as the base layer. @@ -211,10 +221,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; @@ -233,7 +246,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++; } @@ -299,12 +320,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); } @@ -315,6 +347,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; @@ -337,6 +370,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); } @@ -618,6 +655,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; @@ -691,6 +732,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; @@ -720,12 +765,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 7c899cc7388a..759cf069f2ab 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -125,6 +125,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 { -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html