From: Darren Etheridge <detheridge@xxxxxx> Update the DMA pointers during the pan display ioctl. Borrowed from da8xx_fb.c update the scanout buffers immediately so the DMA ping/pong doesn't end up out of sync with what we really want it to DMA, otherwise part of the screen ends up tearing during rapid flip operations. Ported from commit deb95c6c958f ("video: da8xx-fb: fix flicker due to 1 frame delay in updated frame") Signed-off-by: Darren Etheridge <detheridge@xxxxxx> [Rewrapped description and fixed commit reference] Signed-off-by: Jyri Sarha <jsarha@xxxxxx> --- drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index cc45818..50384fa 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -31,6 +31,8 @@ struct tilcdc_crtc { int dpms; wait_queue_head_t frame_done_wq; bool frame_done; + spinlock_t irq_lock; + int dma_completed_channel; /* fb currently set to scanout 0/1: */ struct drm_framebuffer *scanout[2]; @@ -102,10 +104,23 @@ static void update_scanout(struct drm_crtc *crtc) (crtc->mode.vdisplay * fb->pitches[0]); if (tilcdc_crtc->dpms == DRM_MODE_DPMS_ON) { - /* already enabled, so just mark the frames that need - * updating and they will be updated on vblank: + /* + * already enabled, so just mark the frames that need + * updating and they will be updated on vblank + * and update the inactive DMA channel immediately + * to avoid any tearing due to the DMA already starting + * on the pending dma buffer when we hit the vblank IRQ */ - tilcdc_crtc->dirty |= LCDC_END_OF_FRAME0 | LCDC_END_OF_FRAME1; + if (tilcdc_crtc->dma_completed_channel == 0) { + tilcdc_crtc->dirty |= LCDC_END_OF_FRAME1; + set_scanout(crtc, 0); + } + + if (tilcdc_crtc->dma_completed_channel == 1) { + tilcdc_crtc->dirty |= LCDC_END_OF_FRAME0; + set_scanout(crtc, 1); + } + drm_vblank_get(dev, 0); } else { /* not enabled yet, so update registers immediately: */ @@ -647,6 +662,7 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct tilcdc_drm_private *priv = dev->dev_private; uint32_t stat = tilcdc_read_irqstatus(dev); + unsigned long irq_flags; if ((stat & LCDC_SYNC_LOST) && (stat & LCDC_FIFO_UNDERFLOW)) { stop(crtc); @@ -662,11 +678,19 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) tilcdc_clear_irqstatus(dev, stat); - if (dirty & LCDC_END_OF_FRAME0) + spin_lock_irqsave(&tilcdc_crtc->irq_lock, irq_flags); + + if (dirty & LCDC_END_OF_FRAME0) { set_scanout(crtc, 0); + tilcdc_crtc->dma_completed_channel = 0; + } - if (dirty & LCDC_END_OF_FRAME1) + if (dirty & LCDC_END_OF_FRAME1) { set_scanout(crtc, 1); + tilcdc_crtc->dma_completed_channel = 1; + } + + spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, irq_flags); drm_handle_vblank(dev, 0); @@ -732,6 +756,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) drm_flip_work_init(&tilcdc_crtc->unref_work, "unref", unref_worker); + spin_lock_init(&tilcdc_crtc->irq_lock); + ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); if (ret < 0) goto fail; -- 1.9.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel