diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2015-02-18 06:21:56 -0500 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2015-03-03 09:16:04 -0500 |
commit | 36693f3c3254d9361095f6b225d5e69bd8da5c32 (patch) | |
tree | 89e80dd9bf956eb9dea66f40d39ffa11463967c2 | |
parent | 17f6b8a0270f7a40b3dbe07dbcb6cb7f67ce570a (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 35 | ||||
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 3 |
2 files changed, 38 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) | |||
300 | 300 | ||
301 | spin_lock_irqsave(&dev->event_lock, flags); | 301 | spin_lock_irqsave(&dev->event_lock, flags); |
302 | drm_send_vblank_event(dev, rcrtc->index, event); | 302 | drm_send_vblank_event(dev, rcrtc->index, event); |
303 | wake_up(&rcrtc->flip_wait); | ||
303 | spin_unlock_irqrestore(&dev->event_lock, flags); | 304 | spin_unlock_irqrestore(&dev->event_lock, flags); |
304 | 305 | ||
305 | drm_vblank_put(dev, rcrtc->index); | 306 | drm_vblank_put(dev, rcrtc->index); |
306 | } | 307 | } |
307 | 308 | ||
309 | static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc) | ||
310 | { | ||
311 | struct drm_device *dev = rcrtc->crtc.dev; | ||
312 | unsigned long flags; | ||
313 | bool pending; | ||
314 | |||
315 | spin_lock_irqsave(&dev->event_lock, flags); | ||
316 | pending = rcrtc->event != NULL; | ||
317 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
318 | |||
319 | return pending; | ||
320 | } | ||
321 | |||
322 | static void rcar_du_crtc_wait_page_flip(struct rcar_du_crtc *rcrtc) | ||
323 | { | ||
324 | struct rcar_du_device *rcdu = rcrtc->group->dev; | ||
325 | |||
326 | if (wait_event_timeout(rcrtc->flip_wait, | ||
327 | !rcar_du_crtc_page_flip_pending(rcrtc), | ||
328 | msecs_to_jiffies(50))) | ||
329 | return; | ||
330 | |||
331 | dev_warn(rcdu->dev, "page flip timeout\n"); | ||
332 | |||
333 | rcar_du_crtc_finish_page_flip(rcrtc); | ||
334 | } | ||
335 | |||
308 | /* ----------------------------------------------------------------------------- | 336 | /* ----------------------------------------------------------------------------- |
309 | * Start/Stop and Suspend/Resume | 337 | * Start/Stop and Suspend/Resume |
310 | */ | 338 | */ |
@@ -365,6 +393,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) | |||
365 | if (!rcrtc->started) | 393 | if (!rcrtc->started) |
366 | return; | 394 | return; |
367 | 395 | ||
396 | /* Wait for page flip completion before stopping the CRTC as userspace | ||
397 | * excepts page flips to eventually complete. | ||
398 | */ | ||
399 | rcar_du_crtc_wait_page_flip(rcrtc); | ||
400 | |||
368 | mutex_lock(&rcrtc->group->planes.lock); | 401 | mutex_lock(&rcrtc->group->planes.lock); |
369 | rcrtc->plane->enabled = false; | 402 | rcrtc->plane->enabled = false; |
370 | rcar_du_crtc_update_planes(crtc); | 403 | rcar_du_crtc_update_planes(crtc); |
@@ -644,6 +677,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) | |||
644 | return -EPROBE_DEFER; | 677 | return -EPROBE_DEFER; |
645 | } | 678 | } |
646 | 679 | ||
680 | init_waitqueue_head(&rcrtc->flip_wait); | ||
681 | |||
647 | rcrtc->group = rgrp; | 682 | rcrtc->group = rgrp; |
648 | rcrtc->mmio_offset = mmio_offsets[index]; | 683 | rcrtc->mmio_offset = mmio_offsets[index]; |
649 | rcrtc->index = index; | 684 | rcrtc->index = index; |
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index d2f89f7d2e5e..fb39e040f17b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define __RCAR_DU_CRTC_H__ | 15 | #define __RCAR_DU_CRTC_H__ |
16 | 16 | ||
17 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
18 | #include <linux/wait.h> | ||
18 | 19 | ||
19 | #include <drm/drmP.h> | 20 | #include <drm/drmP.h> |
20 | #include <drm/drm_crtc.h> | 21 | #include <drm/drm_crtc.h> |
@@ -32,6 +33,8 @@ struct rcar_du_crtc { | |||
32 | bool started; | 33 | bool started; |
33 | 34 | ||
34 | struct drm_pending_vblank_event *event; | 35 | struct drm_pending_vblank_event *event; |
36 | wait_queue_head_t flip_wait; | ||
37 | |||
35 | unsigned int outputs; | 38 | unsigned int outputs; |
36 | int dpms; | 39 | int dpms; |
37 | 40 | ||