diff options
Diffstat (limited to 'drivers/gpu/drm/omapdrm')
| -rw-r--r-- | drivers/gpu/drm/omapdrm/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_connector.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 132 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_debugfs.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_dmm_tiler.c | 14 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.c | 121 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_drv.h | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_encoder.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fb.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_fbdev.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_gem.c | 48 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_irq.c | 41 | ||||
| -rw-r--r-- | drivers/gpu/drm/omapdrm/omap_plane.c | 16 | 
13 files changed, 288 insertions, 130 deletions
diff --git a/drivers/gpu/drm/omapdrm/Kconfig b/drivers/gpu/drm/omapdrm/Kconfig index 20c41e73d44..6c220cd3497 100644 --- a/drivers/gpu/drm/omapdrm/Kconfig +++ b/drivers/gpu/drm/omapdrm/Kconfig @@ -5,6 +5,7 @@ config DRM_OMAP  	depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM  	depends on OMAP2_DSS  	select DRM_KMS_HELPER +	select DRM_KMS_FB_HELPER  	select FB_SYS_FILLRECT  	select FB_SYS_COPYAREA  	select FB_SYS_IMAGEBLIT diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c index 912759daf56..86f4ead0441 100644 --- a/drivers/gpu/drm/omapdrm/omap_connector.c +++ b/drivers/gpu/drm/omapdrm/omap_connector.c @@ -37,7 +37,7 @@ struct omap_connector {  void copy_timings_omap_to_drm(struct drm_display_mode *mode,  		struct omap_video_timings *timings)  { -	mode->clock = timings->pixel_clock; +	mode->clock = timings->pixelclock / 1000;  	mode->hdisplay = timings->x_res;  	mode->hsync_start = mode->hdisplay + timings->hfp; @@ -68,7 +68,7 @@ void copy_timings_omap_to_drm(struct drm_display_mode *mode,  void copy_timings_drm_to_omap(struct omap_video_timings *timings,  		struct drm_display_mode *mode)  { -	timings->pixel_clock = mode->clock; +	timings->pixelclock = mode->clock * 1000;  	timings->x_res = mode->hdisplay;  	timings->hfp = mode->hsync_start - mode->hdisplay; @@ -220,7 +220,7 @@ static int omap_connector_mode_valid(struct drm_connector *connector,  	if (!r) {  		/* check if vrefresh is still valid */  		new_mode = drm_mode_duplicate(dev, mode); -		new_mode->clock = timings.pixel_clock; +		new_mode->clock = timings.pixelclock / 1000;  		new_mode->vrefresh = 0;  		if (mode->vrefresh == drm_mode_vrefresh(new_mode))  			ret = MODE_OK; diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 0fd2eb139f6..2d28dc337cf 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -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); @@ -245,7 +257,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,  	copy_timings_drm_to_omap(&omap_crtc->timings, mode);  	omap_crtc->full_update = true; -	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, +	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,  			0, 0, mode->hdisplay, mode->vdisplay,  			x << 16, y << 16,  			mode->hdisplay << 16, mode->vdisplay << 16, @@ -273,7 +285,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,  	struct drm_plane *plane = omap_crtc->plane;  	struct drm_display_mode *mode = &crtc->mode; -	return omap_plane_mode_set(plane, crtc, crtc->fb, +	return omap_plane_mode_set(plane, crtc, crtc->primary->fb,  			0, 0, mode->hdisplay, mode->vdisplay,  			x << 16, y << 16,  			mode->hdisplay << 16, mode->vdisplay << 16, @@ -307,15 +319,15 @@ static void page_flip_worker(struct work_struct *work)  	struct drm_display_mode *mode = &crtc->mode;  	struct drm_gem_object *bo; -	mutex_lock(&crtc->mutex); -	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, +	drm_modeset_lock(&crtc->mutex, NULL); +	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,  			0, 0, mode->hdisplay, mode->vdisplay,  			crtc->x << 16, crtc->y << 16,  			mode->hdisplay << 16, mode->vdisplay << 16,  			vblank_cb, crtc); -	mutex_unlock(&crtc->mutex); +	drm_modeset_unlock(&crtc->mutex); -	bo = omap_framebuffer_bo(crtc->fb, 0); +	bo = omap_framebuffer_bo(crtc->primary->fb, 0);  	drm_gem_object_unreference_unlocked(bo);  } @@ -336,18 +348,25 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,  {  	struct drm_device *dev = crtc->dev;  	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)", crtc->fb ? crtc->fb->base.id : -1, +	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; -	crtc->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 @@ -411,7 +430,7 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)  	struct drm_crtc *crtc = &omap_crtc->base;  	DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);  	/* avoid getting in a flood, unregister the irq until next vblank */ -	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); +	__omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);  }  static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) @@ -421,13 +440,13 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)  	struct drm_crtc *crtc = &omap_crtc->base;  	if (!omap_crtc->error_irq.registered) -		omap_irq_register(crtc->dev, &omap_crtc->error_irq); +		__omap_irq_register(crtc->dev, &omap_crtc->error_irq);  	if (!dispc_mgr_go_busy(omap_crtc->channel)) {  		struct omap_drm_private *priv =  				crtc->dev->dev_private;  		DBG("%s: apply done", omap_crtc->name); -		omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); +		__omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);  		queue_work(priv->wq, &omap_crtc->apply_work);  	}  } @@ -446,7 +465,7 @@ static void apply_worker(struct work_struct *work)  	 * the callbacks and list modification all serialized  	 * with respect to modesetting ioctls from userspace.  	 */ -	mutex_lock(&crtc->mutex); +	drm_modeset_lock(&crtc->mutex, NULL);  	dispc_runtime_get();  	/* @@ -491,7 +510,7 @@ static void apply_worker(struct work_struct *work)  out:  	dispc_runtime_put(); -	mutex_unlock(&crtc->mutex); +	drm_modeset_unlock(&crtc->mutex);  }  int omap_crtc_apply(struct drm_crtc *crtc, @@ -499,7 +518,7 @@ int omap_crtc_apply(struct drm_crtc *crtc,  {  	struct omap_crtc *omap_crtc = to_omap_crtc(crtc); -	WARN_ON(!mutex_is_locked(&crtc->mutex)); +	WARN_ON(!drm_modeset_is_locked(&crtc->mutex));  	/* no need to queue it again if it is already queued: */  	if (apply->queued) @@ -527,38 +546,46 @@ 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)); -		if (ret) { -			dev_err(dev->dev, "%s: timeout waiting for %s\n", -					omap_crtc->name, enable ? "enable" : "disable"); -		} +	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); @@ -585,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 { @@ -595,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; @@ -612,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) @@ -623,6 +668,11 @@ void omap_crtc_pre_init(void)  	dss_install_mgr_ops(&mgr_ops);  } +void omap_crtc_pre_uninit(void) +{ +	dss_uninstall_mgr_ops(); +} +  /* initialize crtc */  struct drm_crtc *omap_crtc_init(struct drm_device *dev,  		struct drm_plane *plane, enum omap_channel channel, int id) diff --git a/drivers/gpu/drm/omapdrm/omap_debugfs.c b/drivers/gpu/drm/omapdrm/omap_debugfs.c index c27f59da7f2..d4c04d69fc4 100644 --- a/drivers/gpu/drm/omapdrm/omap_debugfs.c +++ b/drivers/gpu/drm/omapdrm/omap_debugfs.c @@ -48,7 +48,7 @@ static int mm_show(struct seq_file *m, void *arg)  {  	struct drm_info_node *node = (struct drm_info_node *) m->private;  	struct drm_device *dev = node->minor->dev; -	return drm_mm_dump_table(m, dev->mm_private); +	return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);  }  static int fb_show(struct seq_file *m, void *arg) diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c index acf667859cb..f926b4caf44 100644 --- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c +++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c @@ -664,8 +664,9 @@ static int omap_dmm_probe(struct platform_device *dev)  	}  	/* set dma mask for device */ -	/* NOTE: this is a workaround for the hwmod not initializing properly */ -	dev->dev.coherent_dma_mask = DMA_BIT_MASK(32); +	ret = dma_set_coherent_mask(&dev->dev, DMA_BIT_MASK(32)); +	if (ret) +		goto fail;  	omap_dmm->dummy_pa = page_to_phys(omap_dmm->dummy_page); @@ -968,12 +969,21 @@ static const struct dev_pm_ops omap_dmm_pm_ops = {  };  #endif +#if defined(CONFIG_OF) +static const struct of_device_id dmm_of_match[] = { +	{ .compatible = "ti,omap4-dmm", }, +	{ .compatible = "ti,omap5-dmm", }, +	{}, +}; +#endif +  struct platform_driver omap_dmm_driver = {  	.probe = omap_dmm_probe,  	.remove = omap_dmm_remove,  	.driver = {  		.owner = THIS_MODULE,  		.name = DMM_DRIVER_NAME, +		.of_match_table = of_match_ptr(dmm_of_match),  #ifdef CONFIG_PM  		.pm = &omap_dmm_pm_ops,  #endif diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c index 2603d909f49..002b9721e85 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.c +++ b/drivers/gpu/drm/omapdrm/omap_drv.c @@ -86,6 +86,47 @@ static bool channel_used(struct drm_device *dev, enum omap_channel channel)  	return false;  } +static void omap_disconnect_dssdevs(void) +{ +	struct omap_dss_device *dssdev = NULL; + +	for_each_dss_dev(dssdev) +		dssdev->driver->disconnect(dssdev); +} + +static int omap_connect_dssdevs(void) +{ +	int r; +	struct omap_dss_device *dssdev = NULL; +	bool no_displays = true; + +	for_each_dss_dev(dssdev) { +		r = dssdev->driver->connect(dssdev); +		if (r == -EPROBE_DEFER) { +			omap_dss_put_device(dssdev); +			goto cleanup; +		} else if (r) { +			dev_warn(dssdev->dev, "could not connect display: %s\n", +				dssdev->name); +		} else { +			no_displays = false; +		} +	} + +	if (no_displays) +		return -EPROBE_DEFER; + +	return 0; + +cleanup: +	/* +	 * if we are deferring probe, we disconnect the devices we previously +	 * connected +	 */ +	omap_disconnect_dssdevs(); + +	return r; +}  static int omap_modeset_init(struct drm_device *dev)  { @@ -95,9 +136,6 @@ static int omap_modeset_init(struct drm_device *dev)  	int num_mgrs = dss_feat_get_num_mgrs();  	int num_crtcs;  	int i, id = 0; -	int r; - -	omap_crtc_pre_init();  	drm_mode_config_init(dev); @@ -119,26 +157,8 @@ static int omap_modeset_init(struct drm_device *dev)  		enum omap_channel channel;  		struct omap_overlay_manager *mgr; -		if (!dssdev->driver) { -			dev_warn(dev->dev, "%s has no driver.. skipping it\n", -					dssdev->name); -			continue; -		} - -		if (!(dssdev->driver->get_timings || -					dssdev->driver->read_edid)) { -			dev_warn(dev->dev, "%s driver does not support " -				"get_timings or read_edid.. skipping it!\n", -				dssdev->name); -			continue; -		} - -		r = dssdev->driver->connect(dssdev); -		if (r) { -			dev_err(dev->dev, "could not connect display: %s\n", -					dssdev->name); +		if (!omapdss_device_is_connected(dssdev))  			continue; -		}  		encoder = omap_encoder_init(dev, dssdev); @@ -493,20 +513,26 @@ 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); -	drm_vblank_cleanup(dev); -	omap_drm_irq_uninstall(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); -	flush_workqueue(priv->wq);  	destroy_workqueue(priv->wq); +	drm_vblank_cleanup(dev); +	omap_drm_irq_uninstall(dev); +  	kfree(dev->dev_private);  	dev->dev_private = NULL; @@ -562,9 +588,7 @@ static void dev_lastclose(struct drm_device *dev)  		}  	} -	drm_modeset_lock_all(dev); -	ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); -	drm_modeset_unlock_all(dev); +	ret = drm_fb_helper_restore_fbdev_mode_unlocked(priv->fbdev);  	if (ret)  		DBG("failed to restore crtc mode");  } @@ -620,7 +644,6 @@ static struct drm_driver omap_drm_driver = {  		.prime_fd_to_handle = drm_gem_prime_fd_to_handle,  		.gem_prime_export = omap_gem_prime_export,  		.gem_prime_import = omap_gem_prime_import, -		.gem_init_object = omap_gem_init_object,  		.gem_free_object = omap_gem_free_object,  		.gem_vm_ops = &omap_gem_vm_ops,  		.dumb_create = omap_gem_dumb_create, @@ -656,9 +679,19 @@ static void pdev_shutdown(struct platform_device *device)  static int pdev_probe(struct platform_device *device)  { +	int r; +  	if (omapdss_is_initialized() == false)  		return -EPROBE_DEFER; +	omap_crtc_pre_init(); + +	r = omap_connect_dssdevs(); +	if (r) { +		omap_crtc_pre_uninit(); +		return r; +	} +  	DBG("%s", device->name);  	return drm_platform_init(&omap_drm_driver, device);  } @@ -666,9 +699,12 @@ static int pdev_probe(struct platform_device *device)  static int pdev_remove(struct platform_device *device)  {  	DBG(""); -	drm_platform_exit(&omap_drm_driver, device); -	platform_driver_unregister(&omap_dmm_driver); +	drm_put_dev(platform_get_drvdata(device)); + +	omap_disconnect_dssdevs(); +	omap_crtc_pre_uninit(); +  	return 0;  } @@ -695,18 +731,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; +	} + +	r = platform_driver_register(&pdev); +	if (r) { +		pr_err("omapdrm driver registration failed\n"); +		platform_driver_unregister(&omap_dmm_driver); +		return r;  	} -	return platform_driver_register(&pdev); + +	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 */ diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 30b95b73665..284b80fc3c5 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -141,10 +141,12 @@ int omap_gem_resume(struct device *dev);  int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id);  void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id); -irqreturn_t omap_irq_handler(DRM_IRQ_ARGS); +irqreturn_t omap_irq_handler(int irq, void *arg);  void omap_irq_preinstall(struct drm_device *dev);  int omap_irq_postinstall(struct drm_device *dev);  void omap_irq_uninstall(struct drm_device *dev); +void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq); +void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);  void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);  void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);  int omap_drm_irq_uninstall(struct drm_device *dev); @@ -158,8 +160,10 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);  int omap_crtc_apply(struct drm_crtc *crtc,  		struct omap_drm_apply *apply);  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); @@ -220,7 +224,6 @@ struct drm_gem_object *omap_gem_new(struct drm_device *dev,  int omap_gem_new_handle(struct drm_device *dev, struct drm_file *file,  		union omap_gem_size gsize, uint32_t flags, uint32_t *handle);  void omap_gem_free_object(struct drm_gem_object *obj); -int omap_gem_init_object(struct drm_gem_object *obj);  void *omap_gem_vaddr(struct drm_gem_object *obj);  int omap_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,  		uint32_t handle, uint64_t *offset); diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c index 6a12e899235..5290a88c681 100644 --- a/drivers/gpu/drm/omapdrm/omap_encoder.c +++ b/drivers/gpu/drm/omapdrm/omap_encoder.c @@ -51,6 +51,9 @@ struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)  static void omap_encoder_destroy(struct drm_encoder *encoder)  {  	struct omap_encoder *omap_encoder = to_omap_encoder(encoder); + +	omap_encoder_set_enabled(encoder, false); +  	drm_encoder_cleanup(encoder);  	kfree(omap_encoder);  } diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index f2b8f0668c0..2a5cacdc344 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -123,12 +123,16 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,  {  	int i; +	drm_modeset_lock_all(fb->dev); +  	for (i = 0; i < num_clips; i++) {  		omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1,  					clips[i].x2 - clips[i].x1,  					clips[i].y2 - clips[i].y1);  	} +	drm_modeset_unlock_all(fb->dev); +  	return 0;  } @@ -214,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; @@ -302,13 +320,14 @@ struct drm_connector *omap_framebuffer_get_next_connector(  	struct drm_connector *connector = from;  	if (!from) -		return list_first_entry(connector_list, typeof(*from), head); +		return list_first_entry_or_null(connector_list, typeof(*from), +						head);  	list_for_each_entry_from(connector, connector_list, head) {  		if (connector != from) {  			struct drm_encoder *encoder = connector->encoder;  			struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; -			if (crtc && crtc->fb == fb) +			if (crtc && crtc->primary->fb == fb)  				return connector;  		} @@ -327,6 +346,7 @@ void omap_framebuffer_flush(struct drm_framebuffer *fb,  	VERB("flush: %d,%d %dx%d, fb=%p", x, y, w, h, fb); +	/* FIXME: This is racy - no protection against modeset config changes. */  	while ((connector = omap_framebuffer_get_next_connector(fb, connector))) {  		/* only consider connectors that are part of a chain */  		if (connector->encoder && connector->encoder->crtc) { diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c index 002988d0902..1388ca7f87e 100644 --- a/drivers/gpu/drm/omapdrm/omap_fbdev.c +++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c @@ -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); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index 533f6ebec53..95dbce286a4 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -153,24 +153,24 @@ static struct {  static void evict_entry(struct drm_gem_object *obj,  		enum tiler_fmt fmt, struct usergart_entry *entry)  { -	if (obj->dev->dev_mapping) { -		struct omap_gem_object *omap_obj = to_omap_bo(obj); -		int n = usergart[fmt].height; -		size_t size = PAGE_SIZE * n; -		loff_t off = mmap_offset(obj) + -				(entry->obj_pgoff << PAGE_SHIFT); -		const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); -		if (m > 1) { -			int i; -			/* if stride > than PAGE_SIZE then sparse mapping: */ -			for (i = n; i > 0; i--) { -				unmap_mapping_range(obj->dev->dev_mapping, -						off, PAGE_SIZE, 1); -				off += PAGE_SIZE * m; -			} -		} else { -			unmap_mapping_range(obj->dev->dev_mapping, off, size, 1); +	struct omap_gem_object *omap_obj = to_omap_bo(obj); +	int n = usergart[fmt].height; +	size_t size = PAGE_SIZE * n; +	loff_t off = mmap_offset(obj) + +			(entry->obj_pgoff << PAGE_SHIFT); +	const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); + +	if (m > 1) { +		int i; +		/* if stride > than PAGE_SIZE then sparse mapping: */ +		for (i = n; i > 0; i--) { +			unmap_mapping_range(obj->dev->anon_inode->i_mapping, +					    off, PAGE_SIZE, 1); +			off += PAGE_SIZE * m;  		} +	} else { +		unmap_mapping_range(obj->dev->anon_inode->i_mapping, +				    off, size, 1);  	}  	entry->obj = NULL; @@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev)  #ifdef CONFIG_DEBUG_FS  void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)  { -	struct drm_device *dev = obj->dev;  	struct omap_gem_object *omap_obj = to_omap_bo(obj);  	uint64_t off; -	WARN_ON(!mutex_is_locked(&dev->struct_mutex)); -  	off = drm_vma_node_start(&obj->vma_node);  	seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", @@ -1050,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)  {  	struct omap_gem_object *omap_obj = waiter->omap_obj;  	if ((waiter->op & OMAP_GEM_READ) && -			(omap_obj->sync->read_complete < waiter->read_target)) +			(omap_obj->sync->write_complete < waiter->write_target))  		return true;  	if ((waiter->op & OMAP_GEM_WRITE) && -			(omap_obj->sync->write_complete < waiter->write_target)) +			(omap_obj->sync->read_complete < waiter->read_target))  		return true;  	return false;  } @@ -1229,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,  		}  		spin_unlock(&sync_lock); + +		kfree(waiter);  	}  	/* no waiting.. */ @@ -1274,11 +1273,6 @@ unlock:  	return ret;  } -int omap_gem_init_object(struct drm_gem_object *obj) -{ -	return -EINVAL;          /* unused */ -} -  /* don't call directly.. called from GEM core when it is time to actually   * free the object..   */ diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c index 9263db117ff..f035d2bceae 100644 --- a/drivers/gpu/drm/omapdrm/omap_irq.c +++ b/drivers/gpu/drm/omapdrm/omap_irq.c @@ -45,12 +45,11 @@ static void omap_irq_update(struct drm_device *dev)  	dispc_read_irqenable();        /* flush posted write */  } -void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) +void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)  {  	struct omap_drm_private *priv = dev->dev_private;  	unsigned long flags; -	dispc_runtime_get();  	spin_lock_irqsave(&list_lock, flags);  	if (!WARN_ON(irq->registered)) { @@ -60,14 +59,21 @@ void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)  	}  	spin_unlock_irqrestore(&list_lock, flags); +} + +void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) +{ +	dispc_runtime_get(); + +	__omap_irq_register(dev, irq); +  	dispc_runtime_put();  } -void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) +void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)  {  	unsigned long flags; -	dispc_runtime_get();  	spin_lock_irqsave(&list_lock, flags);  	if (!WARN_ON(!irq->registered)) { @@ -77,6 +83,14 @@ void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)  	}  	spin_unlock_irqrestore(&list_lock, flags); +} + +void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq) +{ +	dispc_runtime_get(); + +	__omap_irq_unregister(dev, irq); +  	dispc_runtime_put();  } @@ -173,7 +187,7 @@ void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id)  	dispc_runtime_put();  } -irqreturn_t omap_irq_handler(DRM_IRQ_ARGS) +irqreturn_t omap_irq_handler(int irq, void *arg)  {  	struct drm_device *dev = (struct drm_device *) arg;  	struct omap_drm_private *priv = dev->dev_private; @@ -261,7 +275,7 @@ int omap_drm_irq_install(struct drm_device *dev)  		mutex_unlock(&dev->struct_mutex);  		return -EBUSY;  	} -	dev->irq_enabled = 1; +	dev->irq_enabled = true;  	mutex_unlock(&dev->struct_mutex);  	/* Before installing handler */ @@ -272,7 +286,7 @@ int omap_drm_irq_install(struct drm_device *dev)  	if (ret < 0) {  		mutex_lock(&dev->struct_mutex); -		dev->irq_enabled = 0; +		dev->irq_enabled = false;  		mutex_unlock(&dev->struct_mutex);  		return ret;  	} @@ -283,7 +297,7 @@ int omap_drm_irq_install(struct drm_device *dev)  	if (ret < 0) {  		mutex_lock(&dev->struct_mutex); -		dev->irq_enabled = 0; +		dev->irq_enabled = false;  		mutex_unlock(&dev->struct_mutex);  		dispc_free_irq(dev);  	} @@ -294,11 +308,12 @@ int omap_drm_irq_install(struct drm_device *dev)  int omap_drm_irq_uninstall(struct drm_device *dev)  {  	unsigned long irqflags; -	int irq_enabled, i; +	bool irq_enabled; +	int i;  	mutex_lock(&dev->struct_mutex);  	irq_enabled = dev->irq_enabled; -	dev->irq_enabled = 0; +	dev->irq_enabled = false;  	mutex_unlock(&dev->struct_mutex);  	/* @@ -307,9 +322,9 @@ int omap_drm_irq_uninstall(struct drm_device *dev)  	if (dev->num_crtcs) {  		spin_lock_irqsave(&dev->vbl_lock, irqflags);  		for (i = 0; i < dev->num_crtcs; i++) { -			DRM_WAKEUP(&dev->vbl_queue[i]); -			dev->vblank_enabled[i] = 0; -			dev->last_vblank[i] = +			wake_up(&dev->vblank[i].queue); +			dev->vblank[i].enabled = false; +			dev->vblank[i].last =  				dev->driver->get_vblank_counter(dev, i);  		}  		spin_unlock_irqrestore(&dev->vbl_lock, irqflags); diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c index 046d5e660c0..3cf31ee59aa 100644 --- a/drivers/gpu/drm/omapdrm/omap_plane.c +++ b/drivers/gpu/drm/omapdrm/omap_plane.c @@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane,  		omap_plane->apply_done_cb.arg = arg;  	} +	if (plane->fb) +		drm_framebuffer_unreference(plane->fb); + +	drm_framebuffer_reference(fb); +  	plane->fb = fb;  	plane->crtc = crtc; @@ -241,10 +246,13 @@ static int omap_plane_update(struct drm_plane *plane,  	struct omap_plane *omap_plane = to_omap_plane(plane);  	omap_plane->enabled = true; -	if (plane->fb) -		drm_framebuffer_unreference(plane->fb); - -	drm_framebuffer_reference(fb); +	/* omap_plane_mode_set() takes adjusted src */ +	switch (omap_plane->win.rotation & 0xf) { +	case BIT(DRM_ROTATE_90): +	case BIT(DRM_ROTATE_270): +		swap(src_w, src_h); +		break; +	}  	return omap_plane_mode_set(plane, crtc, fb,  			crtc_x, crtc_y, crtc_w, crtc_h,  | 
