diff options
Diffstat (limited to 'drivers/gpu')
-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) 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; 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 @@ #define __RCAR_DU_CRTC_H__ #include <linux/mutex.h> +#include <linux/wait.h> #include <drm/drmP.h> #include <drm/drm_crtc.h> @@ -32,6 +33,8 @@ struct rcar_du_crtc { bool started; struct drm_pending_vblank_event *event; + wait_queue_head_t flip_wait; + unsigned int outputs; int dpms; |