From 5f741b39dde47c054af78727cce7202fff9f781b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 29 May 2015 16:01:18 +0300 Subject: [PATCH] drm: omapdrm: new vblank and event handling Rework the crtc event/flip_wait system as follows: - If we enable a crtc (full modeset), we set omap_crtc->pending and register vblank irq. - If we need to set GO bit (page flip), we do the same but also set the GO bit. - On vblank we unregister the irq, clear the 'pending' flag, send vblank event to userspace if crtc->state->event != NULL, and wake up 'pending_wait' wq. - In omap_atomic_complete() we wait for the 'pending' flag to get reset for all enabled crtcs using 'pending_wait' wq. The above ensures that we send the events to userspace in vblank, and that after the wait in omap_atomic_complete() everything for the affected crtcs has been completed. Signed-off-by: Tomi Valkeinen Signed-off-by: Laurent Pinchart --- drivers/gpu/drm/omapdrm/omap_crtc.c | 123 +++++++++++----------------- drivers/gpu/drm/omapdrm/omap_drv.c | 22 ++++- drivers/gpu/drm/omapdrm/omap_drv.h | 1 + 3 files changed, 70 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 8d2bf8565ddd..23d9c928cdc9 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -17,8 +17,6 @@ * this program. If not, see . */ -#include - #include #include #include @@ -49,13 +47,10 @@ struct omap_crtc { struct omap_drm_irq vblank_irq; struct omap_drm_irq error_irq; - /* pending event */ - struct drm_pending_vblank_event *event; - wait_queue_head_t flip_wait; - - struct completion completion; - bool ignore_digit_sync_lost; + + bool pending; + wait_queue_head_t pending_wait; }; /* ----------------------------------------------------------------------------- @@ -81,6 +76,15 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) return omap_crtc->channel; } +int omap_crtc_wait_pending(struct drm_crtc *crtc) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + + return wait_event_timeout(omap_crtc->pending_wait, + !omap_crtc->pending, + msecs_to_jiffies(50)); +} + /* ----------------------------------------------------------------------------- * DSS Manager Functions */ @@ -255,61 +259,29 @@ static const struct dss_mgr_ops mgr_ops = { static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) { - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_pending_vblank_event *event; struct drm_device *dev = crtc->dev; unsigned long flags; - spin_lock_irqsave(&dev->event_lock, flags); - - event = omap_crtc->event; - omap_crtc->event = NULL; + event = crtc->state->event; - if (event) { - list_del(&event->base.link); - - /* - * Queue the event for delivery if it's still linked to a file - * handle, otherwise just destroy it. - */ - if (event->base.file_priv) - drm_crtc_send_vblank_event(crtc, event); - else - event->base.destroy(&event->base); - - wake_up(&omap_crtc->flip_wait); - drm_crtc_vblank_put(crtc); - } - - spin_unlock_irqrestore(&dev->event_lock, flags); -} - -static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc) -{ - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - bool pending; + if (!event) + return; spin_lock_irqsave(&dev->event_lock, flags); - pending = omap_crtc->event != NULL; - spin_unlock_irqrestore(&dev->event_lock, flags); - return pending; -} + list_del(&event->base.link); -static void omap_crtc_wait_page_flip(struct drm_crtc *crtc) -{ - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - - if (wait_event_timeout(omap_crtc->flip_wait, - !omap_crtc_page_flip_pending(crtc), - msecs_to_jiffies(50))) - return; - - dev_warn(crtc->dev->dev, "page flip timeout!\n"); + /* + * Queue the event for delivery if it's still linked to a file + * handle, otherwise just destroy it. + */ + if (event->base.file_priv) + drm_crtc_send_vblank_event(crtc, event); + else + event->base.destroy(&event->base); - omap_crtc_complete_page_flip(crtc); + spin_unlock_irqrestore(&dev->event_lock, flags); } static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) @@ -336,12 +308,19 @@ static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus) return; DBG("%s: apply done", omap_crtc->name); + __omap_irq_unregister(dev, &omap_crtc->vblank_irq); - /* wakeup userspace */ + rmb(); + WARN_ON(!omap_crtc->pending); + omap_crtc->pending = false; + wmb(); + + /* wake up userspace */ omap_crtc_complete_page_flip(&omap_crtc->base); - complete(&omap_crtc->completion); + /* wake up omap_atomic_complete */ + wake_up(&omap_crtc->pending_wait); } /* ----------------------------------------------------------------------------- @@ -375,6 +354,13 @@ static void omap_crtc_enable(struct drm_crtc *crtc) DBG("%s", omap_crtc->name); + rmb(); + WARN_ON(omap_crtc->pending); + omap_crtc->pending = true; + wmb(); + + omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); + drm_crtc_vblank_on(crtc); } @@ -384,7 +370,6 @@ static void omap_crtc_disable(struct drm_crtc *crtc) DBG("%s", omap_crtc->name); - omap_crtc_wait_page_flip(crtc); drm_crtc_vblank_off(crtc); } @@ -405,19 +390,6 @@ static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc) static void omap_crtc_atomic_begin(struct drm_crtc *crtc) { - struct drm_pending_vblank_event *event = crtc->state->event; - struct omap_crtc *omap_crtc = to_omap_crtc(crtc); - struct drm_device *dev = crtc->dev; - unsigned long flags; - - if (event) { - WARN_ON(omap_crtc->event); - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - - spin_lock_irqsave(&dev->event_lock, flags); - omap_crtc->event = event; - spin_unlock_irqrestore(&dev->event_lock, flags); - } } static void omap_crtc_atomic_flush(struct drm_crtc *crtc) @@ -427,14 +399,16 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc) WARN_ON(omap_crtc->vblank_irq.registered); if (dispc_mgr_is_enabled(omap_crtc->channel)) { + DBG("%s: GO", omap_crtc->name); + rmb(); + WARN_ON(omap_crtc->pending); + omap_crtc->pending = true; + wmb(); + dispc_mgr_go(omap_crtc->channel); omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); - - WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion, - msecs_to_jiffies(100))); - reinit_completion(&omap_crtc->completion); } crtc->invert_dimensions = !!(crtc->primary->state->rotation & @@ -534,8 +508,7 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, crtc = &omap_crtc->base; - init_waitqueue_head(&omap_crtc->flip_wait); - init_completion(&omap_crtc->completion); + init_waitqueue_head(&omap_crtc->pending_wait); omap_crtc->channel = channel; omap_crtc->name = channel_names[channel]; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 50f555530e55..419c2e49adf5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -66,6 +66,26 @@ struct omap_atomic_state_commit { u32 crtcs; }; +static void omap_atomic_wait_for_completion(struct drm_device *dev, + struct drm_atomic_state *old_state) +{ + struct drm_crtc_state *old_crtc_state; + struct drm_crtc *crtc; + unsigned int i; + int ret; + + for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + if (!crtc->state->enable) + continue; + + ret = omap_crtc_wait_pending(crtc); + + if (!ret) + dev_warn(dev->dev, + "atomic complete timeout (pipe %u)!\n", i); + } +} + static void omap_atomic_complete(struct omap_atomic_state_commit *commit) { struct drm_device *dev = commit->dev; @@ -79,7 +99,7 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit) drm_atomic_helper_commit_planes(dev, old_state); drm_atomic_helper_commit_modeset_enables(dev, old_state); - drm_atomic_helper_wait_for_vblanks(dev, old_state); + omap_atomic_wait_for_completion(dev, old_state); drm_atomic_helper_cleanup_planes(dev, old_state); diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 0b7a055bf007..ae2df41f216f 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -147,6 +147,7 @@ void omap_crtc_pre_init(void); void omap_crtc_pre_uninit(void); struct drm_crtc *omap_crtc_init(struct drm_device *dev, struct drm_plane *plane, enum omap_channel channel, int id); +int omap_crtc_wait_pending(struct drm_crtc *crtc); struct drm_plane *omap_plane_init(struct drm_device *dev, int id, enum drm_plane_type type); -- 2.20.1