Commit 72d0c336 authored by Rob Clark's avatar Rob Clark Committed by Greg Kroah-Hartman
Browse files

staging: drm/omap: send page-flip event after endwin



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: default avatarRob Clark <rob@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b66848eb
Loading
Loading
Loading
Loading
+20 −7
Original line number Diff line number Diff line
@@ -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)
+2 −0
Original line number Diff line number Diff line
@@ -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);
+45 −11
Original line number Diff line number Diff line
@@ -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,