diff options
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/omapdrm/omap_crtc.c | 27 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_drv.h | 2 | ||||
-rw-r--r-- | drivers/staging/omapdrm/omap_plane.c | 56 |
3 files changed, 67 insertions, 18 deletions
diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index 17ca163e5896..13e3c7f7d2b9 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -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) diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 21e48cf430f4..b7e0f0773003 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -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); diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 9b3bfa02a91c..7997be74010d 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c @@ -31,6 +31,11 @@ * 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, |