staging: drm/omap: send page-flip event after endwin
authorRob Clark <rob@ti.com>
Mon, 12 Mar 2012 02:11:21 +0000 (21:11 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 13 Mar 2012 22:44:44 +0000 (15:44 -0700)
The endwin irq indicates that DSS has finished scanning out a buffer.
Use this to trigger page-flip event to userspace, so this happens
only *after* the previous buffer is finished.

Signed-off-by: Rob Clark <rob@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/omapdrm/omap_crtc.c
drivers/staging/omapdrm/omap_drv.h
drivers/staging/omapdrm/omap_plane.c

index 17ca163..13e3c7f 100644 (file)
@@ -118,25 +118,21 @@ static void omap_crtc_load_lut(struct drm_crtc *crtc)
 {
 }
 
-static void page_flip_cb(void *arg)
+static void vblank_cb(void *arg)
 {
+       static uint32_t sequence = 0;
        struct drm_crtc *crtc = arg;
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
        struct drm_pending_vblank_event *event = omap_crtc->event;
-       struct drm_framebuffer *old_fb = omap_crtc->old_fb;
-       struct timeval now;
        unsigned long flags;
+       struct timeval now;
 
        WARN_ON(!event);
 
        omap_crtc->event = NULL;
-       omap_crtc->old_fb = NULL;
-
-       omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
 
        /* wakeup userspace */
-       /* TODO: this should happen *after* flip in vsync IRQ handler */
        if (event) {
                spin_lock_irqsave(&dev->event_lock, flags);
                event->event.sequence = drm_vblank_count_and_time(
@@ -150,6 +146,23 @@ static void page_flip_cb(void *arg)
        }
 }
 
+static void page_flip_cb(void *arg)
+{
+       struct drm_crtc *crtc = arg;
+       struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       struct drm_framebuffer *old_fb = omap_crtc->old_fb;
+
+       omap_crtc->old_fb = NULL;
+
+       omap_crtc_mode_set_base(crtc, crtc->x, crtc->y, old_fb);
+
+       /* really we'd like to setup the callback atomically w/ setting the
+        * new scanout buffer to avoid getting stuck waiting an extra vblank
+        * cycle.. for now go for correctness and later figure out speed..
+        */
+       omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc);
+}
+
 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
                 struct drm_framebuffer *fb,
                 struct drm_pending_vblank_event *event)
index 21e48cf..b7e0f07 100644 (file)
@@ -85,6 +85,8 @@ int omap_plane_mode_set(struct drm_plane *plane,
                unsigned int crtc_w, unsigned int crtc_h,
                uint32_t src_x, uint32_t src_y,
                uint32_t src_w, uint32_t src_h);
+void omap_plane_on_endwin(struct drm_plane *plane,
+               void (*fxn)(void *), void *arg);
 
 struct drm_encoder *omap_encoder_init(struct drm_device *dev,
                struct omap_overlay_manager *mgr);
index 9b3bfa0..7997be7 100644 (file)
  * plane funcs
  */
 
+struct callback {
+       void (*fxn)(void *);
+       void *arg;
+};
+
 #define to_omap_plane(x) container_of(x, struct omap_plane, base)
 
 struct omap_plane {
@@ -58,6 +63,9 @@ struct omap_plane {
 
        /* for deferred unpin when we need to wait for scanout complete irq */
        struct work_struct work;
+
+       /* callback on next endwin irq */
+       struct callback endwin;
 };
 
 /* map from ovl->id to the irq we are interested in for scanout-done */
@@ -84,6 +92,7 @@ static void unpin_worker(struct work_struct *work)
 {
        struct omap_plane *omap_plane =
                        container_of(work, struct omap_plane, work);
+       struct callback endwin;
 
        mutex_lock(&omap_plane->unpin_mutex);
        DBG("unpinning %d of %d", omap_plane->num_unpins,
@@ -96,7 +105,28 @@ static void unpin_worker(struct work_struct *work)
                drm_gem_object_unreference_unlocked(bo);
                omap_plane->num_unpins--;
        }
+       endwin = omap_plane->endwin;
+       omap_plane->endwin.fxn = NULL;
        mutex_unlock(&omap_plane->unpin_mutex);
+
+       if (endwin.fxn)
+               endwin.fxn(endwin.arg);
+}
+
+static void install_irq(struct drm_plane *plane)
+{
+       struct omap_plane *omap_plane = to_omap_plane(plane);
+       struct omap_overlay *ovl = omap_plane->ovl;
+       int ret;
+
+       ret = omap_dispc_register_isr(dispc_isr, plane, id2irq[ovl->id]);
+
+       /*
+        * omapdss has upper limit on # of registered irq handlers,
+        * which we shouldn't hit.. but if we do the limit should
+        * be raised or bad things happen:
+        */
+       WARN_ON(ret == -EBUSY);
 }
 
 /* push changes down to dss2 */
@@ -146,17 +176,8 @@ static int commit(struct drm_plane *plane)
                 * NOTE: really this should be atomic w/ mgr->apply() but
                 * omapdss does not expose such an API
                 */
-               if (omap_plane->num_unpins > 0) {
-                       ret = omap_dispc_register_isr(dispc_isr,
-                               plane, id2irq[ovl->id]);
-               }
-
-               /*
-                * omapdss has upper limit on # of registered irq handlers,
-                * which we shouldn't hit.. but if we do the limit should
-                * be raised or bad things happen:
-                */
-               WARN_ON(ret == -EBUSY);
+               if (omap_plane->num_unpins > 0)
+                       install_irq(plane);
 
        } else {
                struct omap_drm_private *priv = dev->dev_private;
@@ -375,6 +396,19 @@ int omap_plane_dpms(struct drm_plane *plane, int mode)
        return r;
 }
 
+void omap_plane_on_endwin(struct drm_plane *plane,
+               void (*fxn)(void *), void *arg)
+{
+       struct omap_plane *omap_plane = to_omap_plane(plane);
+
+       mutex_lock(&omap_plane->unpin_mutex);
+       omap_plane->endwin.fxn = fxn;
+       omap_plane->endwin.arg = arg;
+       mutex_unlock(&omap_plane->unpin_mutex);
+
+       install_irq(plane);
+}
+
 static const struct drm_plane_funcs omap_plane_funcs = {
                .update_plane = omap_plane_update,
                .disable_plane = omap_plane_disable,