Write out the plane updates after the dumb frame has completed, but
just before the blank period.  This allows all the plane updates to
be performed in a flicker-free non-tearing manner.

Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk>
---
 drivers/gpu/drm/armada/armada_crtc.c | 46 +++++++++++++++++++++---------------
 drivers/gpu/drm/armada/armada_crtc.h |  1 +
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/armada/armada_crtc.c 
b/drivers/gpu/drm/armada/armada_crtc.c
index ebcb99316c94..bb1e13b4516b 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -197,21 +197,27 @@ static void armada_drm_crtc_irq(struct armada_crtc 
*dcrtc, u32 stat)
                writel_relaxed(val, base + LCD_SPU_ADV_REG);
        }
 
-       if (stat & DUMB_FRAMEDONE && dcrtc->cursor_update) {
-               writel_relaxed(dcrtc->cursor_hw_pos,
-                              base + LCD_SPU_HWC_OVSA_HPXL_VLN);
-               writel_relaxed(dcrtc->cursor_hw_sz,
-                              base + LCD_SPU_HWC_HPXL_VLN);
-               armada_updatel(CFG_HWC_ENA,
-                              CFG_HWC_ENA | CFG_HWC_1BITMOD | CFG_HWC_1BITENA,
-                              base + LCD_SPU_DMA_CTRL0);
-               dcrtc->cursor_update = false;
+       if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) {
+               if (dcrtc->update_pending) {
+                       armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
+                       dcrtc->update_pending = false;
+               }
+               if (dcrtc->cursor_update) {
+                       writel_relaxed(dcrtc->cursor_hw_pos,
+                                      base + LCD_SPU_HWC_OVSA_HPXL_VLN);
+                       writel_relaxed(dcrtc->cursor_hw_sz,
+                                      base + LCD_SPU_HWC_HPXL_VLN);
+                       armada_updatel(CFG_HWC_ENA,
+                                      CFG_HWC_ENA | CFG_HWC_1BITMOD |
+                                      CFG_HWC_1BITENA,
+                                      base + LCD_SPU_DMA_CTRL0);
+                       dcrtc->cursor_update = false;
+               }
                armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
        }
-
        spin_unlock(&dcrtc->irq_lock);
 
-       if (stat & VSYNC_IRQ) {
+       if (stat & VSYNC_IRQ && !dcrtc->update_pending) {
                event = xchg(&dcrtc->event, NULL);
                if (event) {
                        spin_lock(&dcrtc->crtc.dev->event_lock);
@@ -360,22 +366,26 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc 
*crtc,
                                         struct drm_crtc_state *old_crtc_state)
 {
        struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
-       unsigned long flags;
 
        DRM_DEBUG_KMS("[CRTC:%d:%s]\n", crtc->base.id, crtc->name);
 
        armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx);
 
-       spin_lock_irqsave(&dcrtc->irq_lock, flags);
-       armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
-       spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
-
        /*
         * If we aren't doing a full modeset, then we need to queue
         * the event here.
         */
-       if (!drm_atomic_crtc_needs_modeset(crtc->state))
+       if (!drm_atomic_crtc_needs_modeset(crtc->state)) {
+               dcrtc->update_pending = true;
                armada_drm_crtc_queue_state_event(crtc);
+               spin_lock_irq(&dcrtc->irq_lock);
+               armada_drm_crtc_enable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
+               spin_unlock_irq(&dcrtc->irq_lock);
+       } else {
+               spin_lock_irq(&dcrtc->irq_lock);
+               armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
+               spin_unlock_irq(&dcrtc->irq_lock);
+       }
 }
 
 static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc,
@@ -532,7 +542,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc 
*dcrtc, bool reload)
 
        if (!dcrtc->cursor_obj || !h || !w) {
                spin_lock_irq(&dcrtc->irq_lock);
-               armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
                dcrtc->cursor_update = false;
                armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
                spin_unlock_irq(&dcrtc->irq_lock);
@@ -556,7 +565,6 @@ static int armada_drm_crtc_cursor_update(struct armada_crtc 
*dcrtc, bool reload)
 
        if (dcrtc->cursor_hw_sz != (h << 16 | w)) {
                spin_lock_irq(&dcrtc->irq_lock);
-               armada_drm_crtc_disable_irq(dcrtc, DUMB_FRAMEDONE_ENA);
                dcrtc->cursor_update = false;
                armada_updatel(0, CFG_HWC_ENA, dcrtc->base + LCD_SPU_DMA_CTRL0);
                spin_unlock_irq(&dcrtc->irq_lock);
diff --git a/drivers/gpu/drm/armada/armada_crtc.h 
b/drivers/gpu/drm/armada/armada_crtc.h
index 5b607d45f469..b95ea13d0705 100644
--- a/drivers/gpu/drm/armada/armada_crtc.h
+++ b/drivers/gpu/drm/armada/armada_crtc.h
@@ -70,6 +70,7 @@ struct armada_crtc {
        spinlock_t              irq_lock;
        uint32_t                irq_ena;
 
+       bool                    update_pending;
        struct drm_pending_vblank_event *event;
        struct armada_regs      atomic_regs[32];
        struct armada_regs      *regs;
-- 
2.7.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to