drm/msm/mdp5: Add optional 'right' Layer Mixer in CRTC state
authorArchit Taneja <architt@codeaurora.org>
Thu, 23 Mar 2017 10:28:08 +0000 (15:58 +0530)
committerRob Clark <robdclark@gmail.com>
Sat, 8 Apr 2017 10:59:34 +0000 (06:59 -0400)
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@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h

index 03a64bd39f22af518437712636e3b5b1f1d970ed..82827f3e2a473040034a345669d0956083b0e2a3 100644 (file)
@@ -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)
index 9a0109410974ec67dcbf7b8e2b540e3e4be3297e..1fdbb936877f5bc859d74c3783c6dc706dec09c0 100644 (file)
@@ -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;
 }
index 751dd861cfd831d652af9cb3b92e405f0934c6ad..b63120388dc67c8f1dec594c63465977c1a617c5 100644 (file)
@@ -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
index fcd067f65a933d422ec6c7d7439a6df61c3066ce..d68e92d71afef28eb6d86b00e441d4a55712d6b8 100644 (file)
@@ -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 {