summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/omapdrm
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@ti.com>2015-05-29 16:01:18 +0300
committerLaurent Pinchart <laurent.pinchart@ideasonboard.com>2015-06-12 23:30:47 +0300
commit5f741b39dde47c054af78727cce7202fff9f781b (patch)
treee0ba2b0b2f0b4a301b7c23c1439ee80fc0e33237 /drivers/gpu/drm/omapdrm
parent6646dfd02985eb67d8dcc00d0d345c8dc40f9925 (diff)
downloadlinux-5f741b39dde47c054af78727cce7202fff9f781b.tar.xz
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 <tomi.valkeinen@ti.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c123
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c22
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h1
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 <http://www.gnu.org/licenses/>.
*/
-#include <linux/completion.h>
-
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
@@ -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);