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:
parent
17f6b8a027
commit
36693f3c32
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue