drm: rcar-du: Keep plane to CRTC associations when disabling a plane
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tue, 28 Apr 2015 15:01:45 +0000 (18:01 +0300)
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Mon, 25 May 2015 12:34:12 +0000 (15:34 +0300)
Changing the plane to CRTC associations requires restarting the CRTC
group, creating visible flicker. Mitigate the issue by changing plane
association only when a plane becomes enabled, not when it get disabled.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_group.c
drivers/gpu/drm/rcar-du/rcar_du_group.h

index 15f8d145a133482098849e4013743ba2e1a65d18..620a2c51185cbb35c9b7ba34814ea9d3e398bd23 100644 (file)
@@ -208,9 +208,10 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
 {
        struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
        unsigned int num_planes = 0;
+       unsigned int dptsr_planes;
+       unsigned int hwplanes = 0;
        unsigned int prio = 0;
        unsigned int i;
-       u32 dptsr = 0;
        u32 dspr = 0;
 
        for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
@@ -238,37 +239,44 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
 
                prio -= 4;
                dspr |= (index + 1) << prio;
-               dptsr |= DPTSR_PnDK(index) |  DPTSR_PnTS(index);
+               hwplanes |= 1 << index;
 
                if (plane_format(plane)->planes == 2) {
                        index = (index + 1) % 8;
 
                        prio -= 4;
                        dspr |= (index + 1) << prio;
-                       dptsr |= DPTSR_PnDK(index) |  DPTSR_PnTS(index);
+                       hwplanes |= 1 << index;
                }
        }
 
-       /* Select display timing and dot clock generator 2 for planes associated
-        * with superposition controller 2.
+       /* Update the planes to display timing and dot clock generator
+        * associations.
+        *
+        * Updating the DPTSR register requires restarting the CRTC group,
+        * resulting in visible flicker. To mitigate the issue only update the
+        * association if needed by enabled planes. Planes being disabled will
+        * keep their current association.
+        *
+        * To mitigate the issue further we could pre-associate planes with
+        * CRTCs, either with a fixed 4/4 split, or through a module parameter.
         */
-       if (rcrtc->index % 2) {
-               /* The DPTSR register is updated when the display controller is
-                * stopped. We thus need to restart the DU. Once again, sorry
-                * for the flicker. One way to mitigate the issue would be to
-                * pre-associate planes with CRTCs (either with a fixed 4/4
-                * split, or through a module parameter). Flicker would then
-                * occur only if we need to break the pre-association.
-                */
-               mutex_lock(&rcrtc->group->lock);
-               if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) {
-                       rcar_du_group_write(rcrtc->group, DPTSR, dptsr);
-                       if (rcrtc->group->used_crtcs)
-                               rcar_du_group_restart(rcrtc->group);
-               }
-               mutex_unlock(&rcrtc->group->lock);
+       mutex_lock(&rcrtc->group->lock);
+
+       dptsr_planes = rcrtc->index % 2 ? rcrtc->group->dptsr_planes | hwplanes
+                    : rcrtc->group->dptsr_planes & ~hwplanes;
+
+       if (dptsr_planes != rcrtc->group->dptsr_planes) {
+               rcar_du_group_write(rcrtc->group, DPTSR,
+                                   (dptsr_planes << 16) | dptsr_planes);
+               rcrtc->group->dptsr_planes = dptsr_planes;
+
+               if (rcrtc->group->used_crtcs)
+                       rcar_du_group_restart(rcrtc->group);
        }
 
+       mutex_unlock(&rcrtc->group->lock);
+
        rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
                            dspr);
 }
index 1bdc0ee0c2483c936b8fffd31948c42fe74e8455..7fd39a7d91c8b2fd411c4b2d27b4a1eabc4e9051 100644 (file)
@@ -85,6 +85,12 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
         * superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
         */
        rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
+
+       /* Apply planes to CRTCs association. */
+       mutex_lock(&rgrp->lock);
+       rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) |
+                           rgrp->dptsr_planes);
+       mutex_unlock(&rgrp->lock);
 }
 
 /*
index ea02bb02f3e1b6ce218322c7334c11c2c900b86c..4f6c37c8d3360c49325d18e0d465d9a4d931130b 100644 (file)
@@ -27,7 +27,8 @@ struct rcar_du_device;
  * @index: group index
  * @use_count: number of users of the group (rcar_du_group_(get|put))
  * @used_crtcs: number of CRTCs currently in use
- * @lock: protects the DPTSR register
+ * @lock: protects the dptsr_planes field and the DPTSR register
+ * @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1
  * @planes: planes handled by the group
  */
 struct rcar_du_group {
@@ -39,6 +40,7 @@ struct rcar_du_group {
        unsigned int used_crtcs;
 
        struct mutex lock;
+       unsigned int dptsr_planes;
 
        struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
 };