From: Russell King Date: Mon, 30 Jul 2018 10:52:34 +0000 (+0100) Subject: drm/armada: handle atomic modeset crtc events X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=dbb4ca8acae100b21946a9c6439af51bd606595e;p=openwrt%2Fstaging%2Fblogic.git 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 --- diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 80d34a4b7d41..a0c67ec892cf 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -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 = { diff --git a/drivers/gpu/drm/armada/armada_crtc.h b/drivers/gpu/drm/armada/armada_crtc.h index 775c01c52982..8b1de877cb02 100644 --- a/drivers/gpu/drm/armada/armada_crtc.h +++ b/drivers/gpu/drm/armada/armada_crtc.h @@ -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;