summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
diff options
context:
space:
mode:
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2015-02-18 13:21:56 +0200
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2015-03-03 16:16:04 +0200
commit36693f3c3254d9361095f6b225d5e69bd8da5c32 (patch)
tree89e80dd9bf956eb9dea66f40d39ffa11463967c2 /drivers/gpu/drm/rcar-du/rcar_du_crtc.c
parent17f6b8a0270f7a40b3dbe07dbcb6cb7f67ce570a (diff)
downloadlinux-stable-36693f3c3254d9361095f6b225d5e69bd8da5c32.tar.gz
linux-stable-36693f3c3254d9361095f6b225d5e69bd8da5c32.tar.bz2
linux-stable-36693f3c3254d9361095f6b225d5e69bd8da5c32.zip
drm: rcar-du: Wait for page flip completion when turning the CRTC off
Turning a CRTC off will prevent a queued page flip from ever completing, potentially confusing userspace. Wait for queued page flips to complete before turning the CRTC off to avoid this. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/gpu/drm/rcar-du/rcar_du_crtc.c')
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index e0562f2b3261..7f5ae0269a61 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -300,11 +300,39 @@ static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
spin_lock_irqsave(&dev->event_lock, flags);
drm_send_vblank_event(dev, rcrtc->index, event);
+ wake_up(&rcrtc->flip_wait);
spin_unlock_irqrestore(&dev->event_lock, flags);
drm_vblank_put(dev, rcrtc->index);
}
+static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc)
+{
+ struct drm_device *dev = rcrtc->crtc.dev;
+ unsigned long flags;
+ bool pending;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ pending = rcrtc->event != NULL;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ return pending;
+}
+
+static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc)
+{
+ struct rcar_du_device *rcdu = rcrtc->group->dev;
+
+ if (wait_event_timeout(rcrtc->flip_wait,
+ !rcar_du_crtc_page_flip_pending(rcrtc),
+ msecs_to_jiffies(50)))
+ return;
+
+ dev_warn(rcdu->dev, "page flip timeout\n");
+
+ rcar_du_crtc_finish_page_flip(rcrtc);
+}
+
/* -----------------------------------------------------------------------------
* Start/Stop and Suspend/Resume
*/
@@ -365,6 +393,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
if (!rcrtc->started)
return;
+ /* Wait for page flip completion before stopping the CRTC as userspace
+ * excepts page flips to eventually complete.
+ */
+ rcar_du_crtc_wait_page_flip(rcrtc);
+
mutex_lock(&rcrtc->group->planes.lock);
rcrtc->plane->enabled = false;
rcar_du_crtc_update_planes(crtc);
@@ -644,6 +677,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
return -EPROBE_DEFER;
}
+ init_waitqueue_head(&rcrtc->flip_wait);
+
rcrtc->group = rgrp;
rcrtc->mmio_offset = mmio_offsets[index];
rcrtc->index = index;