drm/msm: add plane support
authorRob Clark <robdclark@gmail.com>
Tue, 8 Oct 2013 16:57:48 +0000 (12:57 -0400)
committerRob Clark <robdclark@gmail.com>
Fri, 1 Nov 2013 16:39:44 +0000 (12:39 -0400)
Enable using VG1 and VG2 for planes.  Currently YUV/CSC or scaling is
not enabled, but ARGB and xRGB blending is.

Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: David Brown <davidb@codeaurora.org>
drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp4/mdp4_format.c
drivers/gpu/drm/msm/mdp4/mdp4_kms.c
drivers/gpu/drm/msm/mdp4/mdp4_kms.h
drivers/gpu/drm/msm/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/msm_drv.h

index de6bea2..5a68aab 100644 (file)
@@ -26,6 +26,7 @@ struct mdp4_crtc {
        struct drm_crtc base;
        char name[8];
        struct drm_plane *plane;
+       struct drm_plane *planes[8];
        int id;
        int ovlp;
        enum mdp4_dma dma;
@@ -115,9 +116,15 @@ static void crtc_flush(struct drm_crtc *crtc)
 {
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
-       uint32_t flush = 0;
+       uint32_t i, flush = 0;
 
-       flush |= pipe2flush(mdp4_plane_pipe(mdp4_crtc->plane));
+       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+               struct drm_plane *plane = mdp4_crtc->planes[i];
+               if (plane) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       flush |= pipe2flush(pipe_id);
+               }
+       }
        flush |= ovlp2flush(mdp4_crtc->ovlp);
 
        DBG("%s: flush=%08x", mdp4_crtc->name, flush);
@@ -205,67 +212,69 @@ static void blend_setup(struct drm_crtc *crtc)
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
        int i, ovlp = mdp4_crtc->ovlp;
        uint32_t mixer_cfg = 0;
-
-       /*
-        * This probably would also need to be triggered by any attached
-        * plane when it changes.. for now since we are only using a single
-        * private plane, the configuration is hard-coded:
-        */
+       static const enum mdp4_mixer_stage_id stages[] = {
+                       STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
+       };
+       /* statically (for now) map planes to mixer stage (z-order): */
+       static const int idxs[] = {
+                       [VG1]  = 1,
+                       [VG2]  = 2,
+                       [RGB1] = 0,
+                       [RGB2] = 0,
+                       [RGB3] = 0,
+                       [VG3]  = 3,
+                       [VG4]  = 4,
+
+       };
+       bool alpha[4]= { false, false, false, false };
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_LOW1(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH0(ovlp), 0);
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_TRANSP_HIGH1(ovlp), 0);
 
+       /* TODO single register for all CRTCs, so this won't work properly
+        * when multiple CRTCs are active..
+        */
+       for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) {
+               struct drm_plane *plane = mdp4_crtc->planes[i];
+               if (plane) {
+                       enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
+                       int idx = idxs[pipe_id];
+                       if (idx > 0) {
+                               const struct mdp4_format *format =
+                                       to_mdp4_format(msm_framebuffer_format(plane->fb));
+                               alpha[idx-1] = format->alpha_enable;
+                       }
+                       mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
+               }
+       }
+
+       /* this shouldn't happen.. and seems to cause underflow: */
+       WARN_ON(!mixer_cfg);
+
        for (i = 0; i < 4; i++) {
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0);
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0);
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i),
-                               MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
-                               MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST));
-               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 0);
+               uint32_t op;
+
+               if (alpha[i]) {
+                       op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_PIXEL) |
+                                       MDP4_OVLP_STAGE_OP_BG_ALPHA(FG_PIXEL) |
+                                       MDP4_OVLP_STAGE_OP_BG_INV_ALPHA;
+               } else {
+                       op = MDP4_OVLP_STAGE_OP_FG_ALPHA(FG_CONST) |
+                                       MDP4_OVLP_STAGE_OP_BG_ALPHA(BG_CONST);
+               }
+
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_FG_ALPHA(ovlp, i), 0xff);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_BG_ALPHA(ovlp, i), 0x00);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_OP(ovlp, i), op);
+               mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_CO3(ovlp, i), 1);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW0(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_LOW1(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH0(ovlp, i), 0);
                mdp4_write(mdp4_kms, REG_MDP4_OVLP_STAGE_TRANSP_HIGH1(ovlp, i), 0);
        }
 
-       /* TODO single register for all CRTCs, so this won't work properly
-        * when multiple CRTCs are active..
-        */
-       switch (mdp4_plane_pipe(mdp4_crtc->plane)) {
-       case VG1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
-               break;
-       case VG2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
-               break;
-       case RGB1:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
-               break;
-       case RGB2:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
-               break;
-       case RGB3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
-               break;
-       case VG3:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
-               break;
-       case VG4:
-               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(STAGE_BASE) |
-                       COND(mdp4_crtc->mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
-               break;
-       default:
-               WARN_ON("invalid pipe");
-               break;
-       }
        mdp4_write(mdp4_kms, REG_MDP4_LAYERMIXER_IN_CFG, mixer_cfg);
 }
 
@@ -622,6 +631,32 @@ void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf)
        mdp4_write(mdp4_kms, REG_MDP4_DISP_INTF_SEL, intf_sel);
 }
 
+static void set_attach(struct drm_crtc *crtc, enum mdp4_pipe pipe_id,
+               struct drm_plane *plane)
+{
+       struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+
+       BUG_ON(pipe_id >= ARRAY_SIZE(mdp4_crtc->planes));
+
+       if (mdp4_crtc->planes[pipe_id] == plane)
+               return;
+
+       mdp4_crtc->planes[pipe_id] = plane;
+       blend_setup(crtc);
+       if (mdp4_crtc->enabled && (plane != mdp4_crtc->plane))
+               crtc_flush(crtc);
+}
+
+void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp4_plane_pipe(plane), plane);
+}
+
+void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp4_plane_pipe(plane), NULL);
+}
+
 static const char *dma_names[] = {
                "DMA_P", "DMA_S", "DMA_E",
 };
@@ -644,7 +679,6 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
        crtc = &mdp4_crtc->base;
 
        mdp4_crtc->plane = plane;
-       mdp4_crtc->plane->crtc = crtc;
 
        mdp4_crtc->ovlp = ovlp_id;
        mdp4_crtc->dma = dma_id;
index 7b645f2..17330b0 100644 (file)
@@ -44,6 +44,22 @@ static const struct mdp4_format formats[] = {
        FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3),
 };
 
+uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
+               uint32_t max_formats)
+{
+       uint32_t i;
+       for (i = 0; i < ARRAY_SIZE(formats); i++) {
+               const struct mdp4_format *f = &formats[i];
+
+               if (i == max_formats)
+                       break;
+
+               pixel_formats[i] = f->base.pixel_format;
+       }
+
+       return i;
+}
+
 const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format)
 {
        int i;
index bc7fd11..c2485a7 100644 (file)
@@ -196,6 +196,23 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
         * for more than just RGB1->DMA_E->DTV->HDMI
         */
 
+       /* construct non-private planes: */
+       plane = mdp4_plane_init(dev, VG1, false);
+       if (IS_ERR(plane)) {
+               dev_err(dev->dev, "failed to construct plane for VG1\n");
+               ret = PTR_ERR(plane);
+               goto fail;
+       }
+       priv->planes[priv->num_planes++] = plane;
+
+       plane = mdp4_plane_init(dev, VG2, false);
+       if (IS_ERR(plane)) {
+               dev_err(dev->dev, "failed to construct plane for VG2\n");
+               ret = PTR_ERR(plane);
+               goto fail;
+       }
+       priv->planes[priv->num_planes++] = plane;
+
        /* the CRTCs get constructed with a private plane: */
        plane = mdp4_plane_init(dev, RGB1, true);
        if (IS_ERR(plane)) {
index 35ed3ab..11c3438 100644 (file)
@@ -133,6 +133,48 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
        }
 }
 
+static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
+               enum mdp4_mixer_stage_id stage)
+{
+       uint32_t mixer_cfg = 0;
+
+       switch (pipe) {
+       case VG1:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE0(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1);
+               break;
+       case VG2:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE1(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1);
+               break;
+       case RGB1:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE2(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1);
+               break;
+       case RGB2:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE3(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1);
+               break;
+       case RGB3:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE4(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1);
+               break;
+       case VG3:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE5(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1);
+               break;
+       case VG4:
+               mixer_cfg = MDP4_LAYERMIXER_IN_CFG_PIPE6(stage) |
+                       COND(mixer == 1, MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1);
+               break;
+       default:
+               WARN_ON("invalid pipe");
+               break;
+       }
+
+       return mixer_cfg;
+}
+
 int mdp4_disable(struct mdp4_kms *mdp4_kms);
 int mdp4_enable(struct mdp4_kms *mdp4_kms);
 
@@ -146,6 +188,8 @@ void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq);
 int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 
+uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *formats,
+               uint32_t max_formats);
 const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format);
 
 void mdp4_plane_install_properties(struct drm_plane *plane,
@@ -166,6 +210,8 @@ uint32_t mdp4_crtc_vblank(struct drm_crtc *crtc);
 void mdp4_crtc_cancel_pending_flip(struct drm_crtc *crtc);
 void mdp4_crtc_set_config(struct drm_crtc *crtc, uint32_t config);
 void mdp4_crtc_set_intf(struct drm_crtc *crtc, enum mdp4_intf intf);
+void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
+void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
 struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, int id, int ovlp_id,
                enum mdp4_dma dma_id);
index a5eddf5..0f0af24 100644 (file)
@@ -61,7 +61,9 @@ static int mdp4_plane_update(struct drm_plane *plane,
 static int mdp4_plane_disable(struct drm_plane *plane)
 {
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
-       DBG("%s: TODO", mdp4_plane->name); // XXX
+       DBG("%s: disable", mdp4_plane->name);
+       if (plane->crtc)
+               mdp4_crtc_detach(plane->crtc, plane);
        return 0;
 }
 
@@ -141,6 +143,10 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        src_w = src_w >> 16;
        src_h = src_h >> 16;
 
+       DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp4_plane->name,
+                       fb->base.id, src_x, src_y, src_w, src_h,
+                       crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
        if (src_w != crtc_w) {
                op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN;
                /* TODO calc phasex_step */
@@ -191,7 +197,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
 
-       plane->crtc = crtc;
+       /* TODO detach from old crtc (if we had more than one) */
+       mdp4_crtc_attach(crtc, plane);
 
        return 0;
 }
@@ -212,7 +219,6 @@ enum mdp4_pipe mdp4_plane_pipe(struct drm_plane *plane)
 struct drm_plane *mdp4_plane_init(struct drm_device *dev,
                enum mdp4_pipe pipe_id, bool private_plane)
 {
-       struct msm_drm_private *priv = dev->dev_private;
        struct drm_plane *plane = NULL;
        struct mdp4_plane *mdp4_plane;
        int ret;
@@ -228,8 +234,12 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
        mdp4_plane->pipe = pipe_id;
        mdp4_plane->name = pipe_names[pipe_id];
 
-       drm_plane_init(dev, plane, (1 << priv->num_crtcs) - 1, &mdp4_plane_funcs,
-                       mdp4_plane->formats, mdp4_plane->nformats, private_plane);
+       mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
+                       ARRAY_SIZE(mdp4_plane->formats));
+
+       drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+                       mdp4_plane->formats, mdp4_plane->nformats,
+                       private_plane);
 
        mdp4_plane_install_properties(plane, &plane->base);
 
index 9ce90c2..2c6bad5 100644 (file)
@@ -77,6 +77,9 @@ struct msm_drm_private {
        unsigned int num_iommus;
        struct iommu_domain *iommus[NUM_DOMAINS];
 
+       unsigned int num_planes;
+       struct drm_plane *planes[8];
+
        unsigned int num_crtcs;
        struct drm_crtc *crtcs[8];