Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d62c3e7a authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'omapdrm-fixes-3.15' of...

Merge tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next

Fixes for omapdrm, some of which were already present in 3.14, and some which
appeared in 3.15-rc1:

- fixes for primary-plane handling which caused crashes
- fix all kinds of uninit issues which prevented from unloading the omapdrm
  module.
- fixes for HDMI enable/disable issues

* tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux:
  drm/omap: fix the handling of fb ref counts
  drm/omap: protect omap_crtc's event with event_lock spinlock
  drm/omap: Use old_fb to synchronize between successive page flips
  drm/omap: Fix crash when using LCD3 overlay manager
  drm/omap: gem sync: wait on correct events
  drm/omap: Fix memory leak in omap_gem_op_async
  drm/omap: remove warn from debugfs
  drm/omap: remove extra plane->destroy from crtc destroy
  drm/omap: print warning when rotating non-TILER fb
  drm/omap: fix missing unref to fb's buf object
  drm/omap: fix plane rotation
  drm/omap: fix enabling/disabling of video pipeline
  drm/omap: fix missing disable for unused encoder
  drm/omap: fix race issue when unloading omapdrm
  drm/omap: fix DMM driver (un)registration
  drm/omap: fix uninit order in pdev_remove()
  drm/omap: fix output enable/disable sequence
parents 90e48970 f2d022aa
Loading
Loading
Loading
Loading
+72 −28
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct omap_crtc {
	int pipe;
	enum omap_channel channel;
	struct omap_overlay_manager_info info;
	struct drm_encoder *current_encoder;

	/*
	 * Temporary: eventually this will go away, but it is needed
@@ -120,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
{
}

static void set_enabled(struct drm_crtc *crtc, bool enable);

static int omap_crtc_enable(struct omap_overlay_manager *mgr)
{
	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];

	dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
	dispc_mgr_set_timings(omap_crtc->channel,
			&omap_crtc->timings);
	set_enabled(&omap_crtc->base, true);

	return 0;
}

static void omap_crtc_disable(struct omap_overlay_manager *mgr)
{
	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];

	set_enabled(&omap_crtc->base, false);
}

static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@@ -184,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
	WARN_ON(omap_crtc->apply_irq.registered);
	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);

	omap_crtc->plane->funcs->destroy(omap_crtc->plane);
	drm_crtc_cleanup(crtc);

	kfree(omap_crtc);
@@ -338,17 +350,23 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	struct drm_plane *primary = crtc->primary;
	struct drm_gem_object *bo;
	unsigned long flags;

	DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
			fb->base.id, event);

	spin_lock_irqsave(&dev->event_lock, flags);

	if (omap_crtc->old_fb) {
		spin_unlock_irqrestore(&dev->event_lock, flags);
		dev_err(dev->dev, "already a pending flip\n");
		return -EINVAL;
	}

	omap_crtc->event = event;
	primary->fb = fb;
	omap_crtc->old_fb = primary->fb = fb;

	spin_unlock_irqrestore(&dev->event_lock, flags);

	/*
	 * Hold a reference temporarily until the crtc is updated
@@ -528,39 +546,47 @@ static void 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 = NULL;
	struct omap_irq_wait *wait;
	u32 framedone_irq, vsync_irq;
	int ret;

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

	/* ignore sync-lost irqs during enable/disable */
	/*
	 * Digit output produces some sync lost interrupts during the first
	 * frame when enabling, so we need to ignore those.
	 */
	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);

	if (dispc_mgr_get_framedone_irq(channel)) {
		if (!enable) {
			wait = omap_irq_wait_init(dev,
					dispc_mgr_get_framedone_irq(channel), 1);
		}
	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 digit output, we need to wait until fields
		 * are done.  Otherwise the DSS is still working, and turning
		 * off the clocks prevents DSS from going to OFF mode. And when
		 * enabling, we need to wait for the extra sync losts
		 * 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.
		 */
		wait = omap_irq_wait_init(dev,
				dispc_mgr_get_vsync_irq(channel), 2);

		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);

	if (wait) {
		int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
	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");
	}
	}

	omap_irq_register(crtc->dev, &omap_crtc->error_irq);
}
@@ -586,8 +612,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
		}
	}

	if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
		omap_encoder_set_enabled(omap_crtc->current_encoder, false);

	omap_crtc->current_encoder = encoder;

	if (!omap_crtc->enabled) {
		set_enabled(&omap_crtc->base, false);
		if (encoder)
			omap_encoder_set_enabled(encoder, false);
	} else {
@@ -596,13 +626,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
			omap_encoder_update(encoder, omap_crtc->mgr,
					&omap_crtc->timings);
			omap_encoder_set_enabled(encoder, true);
			omap_crtc->full_update = false;
		}

		dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
		dispc_mgr_set_timings(omap_crtc->channel,
				&omap_crtc->timings);
		set_enabled(&omap_crtc->base, true);
	}

	omap_crtc->full_update = false;
@@ -613,10 +637,30 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
	/* nothing needed for post-apply */
}

void omap_crtc_flush(struct drm_crtc *crtc)
{
	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
	int loops = 0;

	while (!list_empty(&omap_crtc->pending_applies) ||
		!list_empty(&omap_crtc->queued_applies) ||
		omap_crtc->event || omap_crtc->old_fb) {

		if (++loops > 10) {
			dev_err(crtc->dev->dev,
				"omap_crtc_flush() timeout\n");
			break;
		}

		schedule_timeout_uninterruptible(msecs_to_jiffies(20));
	}
}

static const char *channel_names[] = {
		[OMAP_DSS_CHANNEL_LCD] = "lcd",
		[OMAP_DSS_CHANNEL_DIGIT] = "tv",
		[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
		[OMAP_DSS_CHANNEL_LCD3] = "lcd3",
};

void omap_crtc_pre_init(void)
+27 −5
Original line number Diff line number Diff line
@@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
static int dev_unload(struct drm_device *dev)
{
	struct omap_drm_private *priv = dev->dev_private;
	int i;

	DBG("unload: dev=%p", dev);

	drm_kms_helper_poll_fini(dev);

	omap_fbdev_free(dev);

	/* flush crtcs so the fbs get released */
	for (i = 0; i < priv->num_crtcs; i++)
		omap_crtc_flush(priv->crtcs[i]);

	omap_modeset_free(dev);
	omap_gem_deinit(dev);

@@ -696,10 +702,11 @@ static int pdev_remove(struct platform_device *device)
{
	DBG("");

	drm_put_dev(platform_get_drvdata(device));

	omap_disconnect_dssdevs();
	omap_crtc_pre_uninit();

	drm_put_dev(platform_get_drvdata(device));
	return 0;
}

@@ -726,18 +733,33 @@ static struct platform_driver pdev = {

static int __init omap_drm_init(void)
{
	int r;

	DBG("init");
	if (platform_driver_register(&omap_dmm_driver)) {
		/* we can continue on without DMM.. so not fatal */
		dev_err(NULL, "DMM registration failed\n");

	r = platform_driver_register(&omap_dmm_driver);
	if (r) {
		pr_err("DMM driver registration failed\n");
		return r;
	}
	return platform_driver_register(&pdev);

	r = platform_driver_register(&pdev);
	if (r) {
		pr_err("omapdrm driver registration failed\n");
		platform_driver_unregister(&omap_dmm_driver);
		return r;
	}

	return 0;
}

static void __exit omap_drm_fini(void)
{
	DBG("fini");

	platform_driver_unregister(&pdev);

	platform_driver_unregister(&omap_dmm_driver);
}

/* need late_initcall() so we load after dss_driver's are loaded */
+1 −0
Original line number Diff line number Diff line
@@ -163,6 +163,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);
void omap_crtc_flush(struct drm_crtc *crtc);

struct drm_plane *omap_plane_init(struct drm_device *dev,
		int plane_id, bool private_plane);
+14 −0
Original line number Diff line number Diff line
@@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
		info->rotation_type = OMAP_DSS_ROT_TILER;
		info->screen_width  = omap_gem_tiled_stride(plane->bo, orient);
	} else {
		switch (win->rotation & 0xf) {
		case 0:
		case BIT(DRM_ROTATE_0):
			/* OK */
			break;

		default:
			dev_warn(fb->dev->dev,
				"rotation '%d' ignored for non-tiled fb\n",
				win->rotation);
			win->rotation = 0;
			break;
		}

		info->paddr         = get_linear_addr(plane, format, 0, x, y);
		info->rotation_type = OMAP_DSS_ROT_DMA;
		info->screen_width  = plane->pitch;
+3 −0
Original line number Diff line number Diff line
@@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev)

	fbdev = to_omap_fbdev(priv->fbdev);

	/* release the ref taken in omap_fbdev_create() */
	omap_gem_put_paddr(fbdev->bo);

	/* this will free the backing object */
	if (fbdev->fb) {
		drm_framebuffer_unregister_private(fbdev->fb);
Loading