drm/armada: handle atomic modeset crtc events

Prepare handling for atomic modeset CRTC events.  Currently, using the
transition helpers, CRTC events do not exist, but once we switch to
proper atomic modeset, they have to be handled.

We queue an event for the next vblank in two places:
- armada_drm_crtc_atomic_flush() provided we aren't doing an
  atomic modeset.
- armada_drm_crtc_commit() if we are committing a modeset.

This ensures that the event is sent at the correct time (after all
updates have been written to the hardware and after the following
vblank.)

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
Russell King 2018-07-30 11:52:34 +01:00
parent 4e4b3563ac
commit dbb4ca8aca
2 changed files with 34 additions and 0 deletions

View file

@ -232,6 +232,19 @@ static void armada_drm_vblank_off(struct armada_crtc *dcrtc)
armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
}
static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc)
{
struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
struct drm_pending_vblank_event *event;
/* If we have an event, we need vblank events enabled */
event = xchg(&crtc->state->event, NULL);
if (event) {
WARN_ON(drm_crtc_vblank_get(crtc) != 0);
dcrtc->event = event;
}
}
/* The mode_config.mutex will be held for this call */
static void armada_drm_crtc_dpms(struct drm_crtc *crtc, int dpms)
{
@ -294,6 +307,8 @@ static void armada_drm_crtc_commit(struct drm_crtc *crtc)
dcrtc->dpms = DRM_MODE_DPMS_ON;
armada_drm_crtc_update(dcrtc);
drm_crtc_vblank_on(crtc);
armada_drm_crtc_queue_state_event(crtc);
}
/* The mode_config.mutex will be held for this call */
@ -337,6 +352,7 @@ static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask)
static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
{
struct drm_pending_vblank_event *event;
void __iomem *base = dcrtc->base;
struct drm_plane *ovl_plane;
@ -383,6 +399,16 @@ static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat)
if (stat & GRA_FRAME_IRQ)
armada_drm_plane_work_run(dcrtc, dcrtc->crtc.primary);
if (stat & VSYNC_IRQ) {
event = xchg(&dcrtc->event, NULL);
if (event) {
spin_lock(&dcrtc->crtc.dev->event_lock);
drm_crtc_send_vblank_event(&dcrtc->crtc, event);
spin_unlock(&dcrtc->crtc.dev->event_lock);
drm_crtc_vblank_put(&dcrtc->crtc);
}
}
}
static irqreturn_t armada_drm_irq(int irq, void *arg)
@ -554,6 +580,13 @@ static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc,
spin_lock_irqsave(&dcrtc->irq_lock, flags);
armada_drm_crtc_update_regs(dcrtc, dcrtc->regs);
spin_unlock_irqrestore(&dcrtc->irq_lock, flags);
/*
* If we aren't doing a full modeset, then we need to queue
* the event here.
*/
if (!drm_atomic_crtc_needs_modeset(crtc->state))
armada_drm_crtc_queue_state_event(crtc);
}
static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {

View file

@ -90,6 +90,7 @@ struct armada_crtc {
spinlock_t irq_lock;
uint32_t irq_ena;
struct drm_pending_vblank_event *event;
struct armada_regs atomic_regs[32];
struct armada_regs *regs;
unsigned int regs_idx;