[PATCH 16/20] drm/armada: update planes after the dumb frame is complete

Russell King rmk+kernel at armlinux.org.uk
Tue Jul 10 10:42:34 UTC 2018


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+kernel at 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



More information about the dri-devel mailing list