static void omap_crtc_destroy(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	omap_crtc->plane->funcs->destroy(omap_crtc->plane);
	drm_crtc_cleanup(crtc);
	kfree(omap_crtc);
}
Esempio n. 2
0
static void page_flip_cb(void *arg)
{
	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 timeval now;
	unsigned long flags;

	WARN_ON(!event);

	omap_crtc->event = NULL;

	update_scanout(crtc);
	WARN_ON(commit(crtc));

	/* 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(
				dev, omap_crtc->id, &now);
		event->event.tv_sec = now.tv_sec;
		event->event.tv_usec = now.tv_usec;
		list_add_tail(&event->base.link,
				&event->base.file_priv->event_list);
		wake_up_interruptible(&event->base.file_priv->event_wait);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}
Esempio n. 3
0
static void omap_crtc_destroy(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	DBG("%s", omap_crtc->ovl->name);
	drm_crtc_cleanup(crtc);
	kfree(omap_crtc);
}
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;
	unsigned long flags;
	struct timeval now;

	WARN_ON(!event);

	omap_crtc->event = NULL;

	
	if (event) {
		do_gettimeofday(&now);

		spin_lock_irqsave(&dev->event_lock, flags);
		event->event.sequence = sequence++;
		event->event.tv_sec = now.tv_sec;
		event->event.tv_usec = now.tv_usec;
		list_add_tail(&event->base.link,
				&event->base.file_priv->event_list);
		wake_up_interruptible(&event->base.file_priv->event_wait);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}
Esempio n. 5
0
static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
				  struct drm_display_mode *mode,
				  struct drm_display_mode *adjusted_mode)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	DBG("%s", omap_crtc->ovl->name);
	return true;
}
static void omap_crtc_disable(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%s", omap_crtc->name);

	drm_crtc_vblank_off(crtc);
}
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));
}
/* Called only from the encoder enable/disable and suspend/resume handlers. */
static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
{
	struct drm_device *dev = crtc->dev;
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	enum omap_channel channel = omap_crtc->channel;
	struct omap_irq_wait *wait;
	u32 framedone_irq, vsync_irq;
	int ret;

	if (dispc_mgr_is_enabled(channel) == enable)
		return;

	if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
		/*
		 * Digit output produces some sync lost interrupts during the
		 * first frame when enabling, so we need to ignore those.
		 */
		omap_crtc->ignore_digit_sync_lost = true;
	}

	framedone_irq = dispc_mgr_get_framedone_irq(channel);
	vsync_irq = dispc_mgr_get_vsync_irq(channel);

	if (enable) {
		wait = omap_irq_wait_init(dev, vsync_irq, 1);
	} else {
		/*
		 * When we disable the digit output, we need to wait for
		 * FRAMEDONE to know that DISPC has finished with the output.
		 *
		 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
		 * that case we need to use vsync interrupt, and wait for both
		 * even and odd frames.
		 */

		if (framedone_irq)
			wait = omap_irq_wait_init(dev, framedone_irq, 1);
		else
			wait = omap_irq_wait_init(dev, vsync_irq, 2);
	}

	dispc_mgr_enable(channel, enable);

	ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
	if (ret) {
		dev_err(dev->dev, "%s: timeout waiting for %s\n",
				omap_crtc->name, enable ? "enable" : "disable");
	}

	if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
		omap_crtc->ignore_digit_sync_lost = false;
		/* make sure the irq handler sees the value above */
		mb();
	}
}
Esempio n. 9
0
static void omap_crtc_prepare(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct omap_overlay *ovl = omap_crtc->ovl;

	DBG("%s", omap_crtc->ovl->name);

	ovl->get_overlay_info(ovl, &omap_crtc->info);

	omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}
Esempio n. 10
0
static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
		    struct drm_framebuffer *old_fb)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%s %d,%d: fb=%p", omap_crtc->ovl->name, x, y, old_fb);

	update_scanout(crtc);

	return commit(crtc);
}
static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
		struct drm_framebuffer *old_fb)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct drm_plane *plane = omap_crtc->plane;
	struct drm_display_mode *mode = &crtc->mode;

	return plane->funcs->update_plane(plane, crtc, crtc->fb,
			0, 0, mode->hdisplay, mode->vdisplay,
			x << 16, y << 16,
			mode->hdisplay << 16, mode->vdisplay << 16);
}
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);

	omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc);
}
Esempio n. 13
0
static void omap_crtc_destroy(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%s", omap_crtc->name);

	WARN_ON(omap_crtc->vblank_irq.registered);
	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);

	drm_crtc_cleanup(crtc);

	kfree(omap_crtc);
}
static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
{
	struct omap_drm_private *priv = crtc->dev->dev_private;
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	int i;

	WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));

	for (i = 0; i < priv->num_planes; i++) {
		struct drm_plane *plane = priv->planes[i];
		if (plane->crtc == crtc)
			WARN_ON(omap_plane_dpms(plane, mode));
	}
}
static int omap_crtc_mode_set(struct drm_crtc *crtc,
		struct drm_display_mode *mode,
		struct drm_display_mode *adjusted_mode,
		int x, int y,
		struct drm_framebuffer *old_fb)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct drm_plane *plane = omap_crtc->plane;

	return omap_plane_mode_set(plane, crtc, crtc->fb,
			0, 0, mode->hdisplay, mode->vdisplay,
			x << 16, y << 16,
			mode->hdisplay << 16, mode->vdisplay << 16);
}
Esempio n. 16
0
static void omap_crtc_mode_set_nofb(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct drm_display_mode *mode = &crtc->state->adjusted_mode;

	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
	    omap_crtc->name, mode->base.id, mode->name,
	    mode->vrefresh, mode->clock,
	    mode->hdisplay, mode->hsync_start, mode->hsync_end, mode->htotal,
	    mode->vdisplay, mode->vsync_start, mode->vsync_end, mode->vtotal,
	    mode->type, mode->flags);

	copy_timings_drm_to_omap(&omap_crtc->timings, mode);
}
Esempio n. 17
0
static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%s: %d", omap_crtc->ovl->name, mode);

	if (mode == DRM_MODE_DPMS_ON) {
		update_scanout(crtc);
		omap_crtc->info.enabled = true;
	} else {
		omap_crtc->info.enabled = false;
	}

	WARN_ON(commit(crtc));
}
Esempio n. 18
0
static void omap_crtc_enable(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_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);
}
Esempio n. 19
0
/* update parameters that are dependent on the framebuffer dimensions and
 * position within the fb that this crtc scans out from. This is called
 * when framebuffer dimensions or x,y base may have changed, either due
 * to our mode, or a change in another crtc that is scanning out of the
 * same fb.
 */
static void update_scanout(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	dma_addr_t paddr;
	unsigned int screen_width;

	omap_framebuffer_get_buffer(crtc->fb, crtc->x, crtc->y,
			NULL, &paddr, &screen_width);

	DBG("%s: %d,%d: %08x (%d)", omap_crtc->ovl->name,
			crtc->x, crtc->y, (u32)paddr, screen_width);

	omap_crtc->info.paddr = paddr;
	omap_crtc->info.screen_width = screen_width;
}
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);
}
Esempio n. 21
0
/* push changes down to dss2 */
static int commit(struct drm_crtc *crtc)
{
	struct drm_device *dev = crtc->dev;
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct omap_overlay *ovl = omap_crtc->ovl;
	struct omap_overlay_info *info = &omap_crtc->info;
	int ret;

	DBG("%s", omap_crtc->ovl->name);
	DBG("%dx%d -> %dx%d (%d)", info->width, info->height, info->out_width,
			info->out_height, info->screen_width);
	DBG("%d,%d %08x", info->pos_x, info->pos_y, info->paddr);

	/* NOTE: do we want to do this at all here, or just wait
	 * for dpms(ON) since other CRTC's may not have their mode
	 * set yet, so fb dimensions may still change..
	 */
	ret = ovl->set_overlay_info(ovl, info);
	if (ret) {
		dev_err(dev->dev, "could not set overlay info\n");
		return ret;
	}

	/* our encoder doesn't necessarily get a commit() after this, in
	 * particular in the dpms() and mode_set_base() cases, so force the
	 * manager to update:
	 *
	 * could this be in the encoder somehow?
	 */
	if (ovl->manager) {
		ret = ovl->manager->apply(ovl->manager);
		if (ret) {
			dev_err(dev->dev, "could not apply settings\n");
			return ret;
		}
	}

	if (info->enabled) {
		omap_framebuffer_flush(crtc->fb, crtc->x, crtc->y,
				crtc->fb->width, crtc->fb->height);
	}

	return 0;
}
Esempio n. 22
0
static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
                                  struct drm_crtc_state *old_crtc_state)
{
	struct omap_crtc *omap_crtc = to_omap_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);
	}
}
Esempio n. 23
0
static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
		 struct drm_framebuffer *fb,
		 struct drm_pending_vblank_event *event)
{
	struct drm_device *dev = crtc->dev;
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id);

	if (omap_crtc->event) {
		dev_err(dev->dev, "already a pending flip\n");
		return -EINVAL;
	}

	crtc->fb = fb;
	omap_crtc->event = event;

	omap_gem_op_async(omap_framebuffer_bo(fb), OMAP_GEM_READ,
			page_flip_cb, crtc);

	return 0;
}
Esempio n. 24
0
static int omap_crtc_mode_set(struct drm_crtc *crtc,
			       struct drm_display_mode *mode,
			       struct drm_display_mode *adjusted_mode,
			       int x, int y,
			       struct drm_framebuffer *old_fb)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	DBG("%s: %d,%d: %dx%d", omap_crtc->ovl->name, x, y,
			mode->hdisplay, mode->vdisplay);

	/* just use adjusted mode */
	mode = adjusted_mode;

	omap_crtc->info.width = mode->hdisplay;
	omap_crtc->info.height = mode->vdisplay;
	omap_crtc->info.out_width = mode->hdisplay;
	omap_crtc->info.out_height = mode->vdisplay;
	omap_crtc->info.color_mode = OMAP_DSS_COLOR_RGB24U;
	omap_crtc->info.rotation_type = OMAP_DSS_ROT_DMA;
	omap_crtc->info.rotation = OMAP_DSS_ROT_0;
	omap_crtc->info.global_alpha = 0xff;
	omap_crtc->info.mirror = 0;
	omap_crtc->info.mirror = 0;
	omap_crtc->info.pos_x = 0;
	omap_crtc->info.pos_y = 0;
#if 0 /* re-enable when these are available in DSS2 driver */
	omap_crtc->info.zorder = 3;        /* GUI in the front, video behind */
	omap_crtc->info.min_x_decim = 1;
	omap_crtc->info.max_x_decim = 1;
	omap_crtc->info.min_y_decim = 1;
	omap_crtc->info.max_y_decim = 1;
#endif

	update_scanout(crtc);

	return 0;
}
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;
	unsigned long flags;
	struct timeval now;

	WARN_ON(!event);

	omap_crtc->event = NULL;

	/* wakeup userspace */
	if (event) {
		do_gettimeofday(&now);

		spin_lock_irqsave(&dev->event_lock, flags);
		/* TODO: we can't yet use the vblank time accounting,
		 * because omapdss lower layer is the one that knows
		 * the irq # and registers the handler, which more or
		 * less defeats how drm_irq works.. for now just fake
		 * the sequence number and use gettimeofday..
		 *
		event->event.sequence = drm_vblank_count_and_time(
				dev, omap_crtc->id, &now);
		 */
		event->event.sequence = sequence++;
		event->event.tv_sec = now.tv_sec;
		event->event.tv_usec = now.tv_usec;
		list_add_tail(&event->base.link,
				&event->base.file_priv->event_list);
		wake_up_interruptible(&event->base.file_priv->event_wait);
		spin_unlock_irqrestore(&dev->event_lock, flags);
	}
}
static void omap_crtc_commit(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	DBG("%s", omap_crtc->name);
	omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
}
static void omap_crtc_prepare(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	DBG("%s", omap_crtc->name);
	omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
}
Esempio n. 28
0
struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	return &omap_crtc->timings;
}
Esempio n. 29
0
uint32_t pipe2vbl(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);

	return dispc_mgr_get_vsync_irq(omap_crtc->channel);
}
Esempio n. 30
0
enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	return omap_crtc->channel;
}