From: Russell King Date: Mon, 30 Jul 2018 11:53:06 +0100 Subject: drm/armada: update planes after the dumb frame is complete Git-commit: 3cb13ac97bdfda5b301609256e3e0b59bc94f10a Patch-mainline: v4.19-rc1 References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166 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 Acked-by: Petr Tesarik --- drivers/gpu/drm/armada/armada_crtc.c | 46 ++++++++++++++++++++--------------- drivers/gpu/drm/armada/armada_crtc.h | 1 2 files changed, 28 insertions(+), 19 deletions(-) --- 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 a 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_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 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 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); --- 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;