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>
This commit is contained in:
Laurent Pinchart 2015-02-18 13:21:56 +02:00
parent 17f6b8a027
commit 36693f3c32
2 changed files with 38 additions and 0 deletions

View File

@ -300,11 +300,39 @@ static void rcar_du_crtc_finish_page_flip(struct rcar_du_crtc *rcrtc)
spin_lock_irqsave(&dev->event_lock, flags); spin_lock_irqsave(&dev->event_lock, flags);
drm_send_vblank_event(dev, rcrtc->index, event); drm_send_vblank_event(dev, rcrtc->index, event);
wake_up(&rcrtc->flip_wait);
spin_unlock_irqrestore(&dev->event_lock, flags); spin_unlock_irqrestore(&dev->event_lock, flags);
drm_vblank_put(dev, rcrtc->index); 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 * Start/Stop and Suspend/Resume
*/ */
@ -365,6 +393,11 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
if (!rcrtc->started) if (!rcrtc->started)
return; 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); mutex_lock(&rcrtc->group->planes.lock);
rcrtc->plane->enabled = false; rcrtc->plane->enabled = false;
rcar_du_crtc_update_planes(crtc); 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; return -EPROBE_DEFER;
} }
init_waitqueue_head(&rcrtc->flip_wait);
rcrtc->group = rgrp; rcrtc->group = rgrp;
rcrtc->mmio_offset = mmio_offsets[index]; rcrtc->mmio_offset = mmio_offsets[index];
rcrtc->index = index; rcrtc->index = index;

View File

@ -15,6 +15,7 @@
#define __RCAR_DU_CRTC_H__ #define __RCAR_DU_CRTC_H__
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/wait.h>
#include <drm/drmP.h> #include <drm/drmP.h>
#include <drm/drm_crtc.h> #include <drm/drm_crtc.h>
@ -32,6 +33,8 @@ struct rcar_du_crtc {
bool started; bool started;
struct drm_pending_vblank_event *event; struct drm_pending_vblank_event *event;
wait_queue_head_t flip_wait;
unsigned int outputs; unsigned int outputs;
int dpms; int dpms;