diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c')
| -rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 460 | 
1 files changed, 231 insertions, 229 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index d27809372d54..bd0a3bd07167 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -20,6 +20,8 @@  #include <linux/component.h>  #include <linux/pinctrl/consumer.h>  #include <linux/suspend.h> +#include <drm/drm_atomic.h> +#include <drm/drm_atomic_helper.h>  #include "tilcdc_drv.h"  #include "tilcdc_regs.h" @@ -31,6 +33,20 @@  static LIST_HEAD(module_list); +static const u32 tilcdc_rev1_formats[] = { DRM_FORMAT_RGB565 }; + +static const u32 tilcdc_straight_formats[] = { DRM_FORMAT_RGB565, +					       DRM_FORMAT_BGR888, +					       DRM_FORMAT_XBGR8888 }; + +static const u32 tilcdc_crossed_formats[] = { DRM_FORMAT_BGR565, +					      DRM_FORMAT_RGB888, +					      DRM_FORMAT_XRGB8888 }; + +static const u32 tilcdc_legacy_formats[] = { DRM_FORMAT_RGB565, +					     DRM_FORMAT_RGB888, +					     DRM_FORMAT_XRGB8888 }; +  void tilcdc_module_init(struct tilcdc_module *mod, const char *name,  		const struct tilcdc_module_ops *funcs)  { @@ -59,20 +75,83 @@ static void tilcdc_fb_output_poll_changed(struct drm_device *dev)  	drm_fbdev_cma_hotplug_event(priv->fbdev);  } +static int tilcdc_atomic_check(struct drm_device *dev, +			       struct drm_atomic_state *state) +{ +	int ret; + +	ret = drm_atomic_helper_check_modeset(dev, state); +	if (ret) +		return ret; + +	ret = drm_atomic_helper_check_planes(dev, state); +	if (ret) +		return ret; + +	/* +	 * tilcdc ->atomic_check can update ->mode_changed if pixel format +	 * changes, hence will we check modeset changes again. +	 */ +	ret = drm_atomic_helper_check_modeset(dev, state); +	if (ret) +		return ret; + +	return ret; +} + +static int tilcdc_commit(struct drm_device *dev, +		  struct drm_atomic_state *state, +		  bool async) +{ +	int ret; + +	ret = drm_atomic_helper_prepare_planes(dev, state); +	if (ret) +		return ret; + +	drm_atomic_helper_swap_state(state, true); + +	/* +	 * Everything below can be run asynchronously without the need to grab +	 * any modeset locks at all under one condition: It must be guaranteed +	 * that the asynchronous work has either been cancelled (if the driver +	 * supports it, which at least requires that the framebuffers get +	 * cleaned up with drm_atomic_helper_cleanup_planes()) or completed +	 * before the new state gets committed on the software side with +	 * drm_atomic_helper_swap_state(). +	 * +	 * This scheme allows new atomic state updates to be prepared and +	 * checked in parallel to the asynchronous completion of the previous +	 * update. Which is important since compositors need to figure out the +	 * composition of the next frame right after having submitted the +	 * current layout. +	 */ + +	drm_atomic_helper_commit_modeset_disables(dev, state); + +	drm_atomic_helper_commit_planes(dev, state, 0); + +	drm_atomic_helper_commit_modeset_enables(dev, state); + +	drm_atomic_helper_wait_for_vblanks(dev, state); + +	drm_atomic_helper_cleanup_planes(dev, state); + +	return 0; +} +  static const struct drm_mode_config_funcs mode_config_funcs = {  	.fb_create = tilcdc_fb_create,  	.output_poll_changed = tilcdc_fb_output_poll_changed, +	.atomic_check = tilcdc_atomic_check, +	.atomic_commit = tilcdc_commit,  }; -static int modeset_init(struct drm_device *dev) +static void modeset_init(struct drm_device *dev)  {  	struct tilcdc_drm_private *priv = dev->dev_private;  	struct tilcdc_module *mod; -	drm_mode_config_init(dev); - -	priv->crtc = tilcdc_crtc_create(dev); -  	list_for_each_entry(mod, &module_list, list) {  		DBG("loading module: %s", mod->name);  		mod->funcs->modeset_init(mod, dev); @@ -83,8 +162,6 @@ static int modeset_init(struct drm_device *dev)  	dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc);  	dev->mode_config.max_height = 2048;  	dev->mode_config.funcs = &mode_config_funcs; - -	return 0;  }  #ifdef CONFIG_CPU_FREQ @@ -93,12 +170,9 @@ static int cpufreq_transition(struct notifier_block *nb,  {  	struct tilcdc_drm_private *priv = container_of(nb,  			struct tilcdc_drm_private, freq_transition); -	if (val == CPUFREQ_POSTCHANGE) { -		if (priv->lcd_fck_rate != clk_get_rate(priv->clk)) { -			priv->lcd_fck_rate = clk_get_rate(priv->clk); -			tilcdc_crtc_update_clk(priv->crtc); -		} -	} + +	if (val == CPUFREQ_POSTCHANGE) +		tilcdc_crtc_update_clk(priv->crtc);  	return 0;  } @@ -108,26 +182,29 @@ static int cpufreq_transition(struct notifier_block *nb,   * DRM operations:   */ -static int tilcdc_unload(struct drm_device *dev) +static void tilcdc_fini(struct drm_device *dev)  {  	struct tilcdc_drm_private *priv = dev->dev_private; -	tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); +	if (priv->crtc) +		tilcdc_crtc_shutdown(priv->crtc); -	tilcdc_remove_external_encoders(dev); +	if (priv->is_registered) +		drm_dev_unregister(dev); -	drm_fbdev_cma_fini(priv->fbdev);  	drm_kms_helper_poll_fini(dev); -	drm_mode_config_cleanup(dev); -	drm_vblank_cleanup(dev); -	pm_runtime_get_sync(dev->dev); +	if (priv->fbdev) +		drm_fbdev_cma_fini(priv->fbdev); +  	drm_irq_uninstall(dev); -	pm_runtime_put_sync(dev->dev); +	drm_mode_config_cleanup(dev); +	tilcdc_remove_external_device(dev);  #ifdef CONFIG_CPU_FREQ -	cpufreq_unregister_notifier(&priv->freq_transition, -			CPUFREQ_TRANSITION_NOTIFIER); +	if (priv->freq_transition.notifier_call) +		cpufreq_unregister_notifier(&priv->freq_transition, +					    CPUFREQ_TRANSITION_NOTIFIER);  #endif  	if (priv->clk) @@ -136,78 +213,81 @@ static int tilcdc_unload(struct drm_device *dev)  	if (priv->mmio)  		iounmap(priv->mmio); -	flush_workqueue(priv->wq); -	destroy_workqueue(priv->wq); +	if (priv->wq) { +		flush_workqueue(priv->wq); +		destroy_workqueue(priv->wq); +	}  	dev->dev_private = NULL;  	pm_runtime_disable(dev->dev); -	return 0; +	drm_dev_unref(dev);  } -static size_t tilcdc_num_regs(void); - -static int tilcdc_load(struct drm_device *dev, unsigned long flags) +static int tilcdc_init(struct drm_driver *ddrv, struct device *dev)  { -	struct platform_device *pdev = dev->platformdev; -	struct device_node *node = pdev->dev.of_node; +	struct drm_device *ddev; +	struct platform_device *pdev = to_platform_device(dev); +	struct device_node *node = dev->of_node;  	struct tilcdc_drm_private *priv; -	struct tilcdc_module *mod;  	struct resource *res;  	u32 bpp = 0;  	int ret; -	priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); -	if (priv) -		priv->saved_register = -			devm_kcalloc(dev->dev, tilcdc_num_regs(), -				     sizeof(*priv->saved_register), GFP_KERNEL); -	if (!priv || !priv->saved_register) { -		dev_err(dev->dev, "failed to allocate private data\n"); +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); +	if (!priv) { +		dev_err(dev, "failed to allocate private data\n");  		return -ENOMEM;  	} -	dev->dev_private = priv; +	ddev = drm_dev_alloc(ddrv, dev); +	if (IS_ERR(ddev)) +		return PTR_ERR(ddev); + +	ddev->platformdev = pdev; +	ddev->dev_private = priv; +	platform_set_drvdata(pdev, ddev); +	drm_mode_config_init(ddev);  	priv->is_componentized = -		tilcdc_get_external_components(dev->dev, NULL) > 0; +		tilcdc_get_external_components(dev, NULL) > 0;  	priv->wq = alloc_ordered_workqueue("tilcdc", 0);  	if (!priv->wq) {  		ret = -ENOMEM; -		goto fail_unset_priv; +		goto init_failed;  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) { -		dev_err(dev->dev, "failed to get memory resource\n"); +		dev_err(dev, "failed to get memory resource\n");  		ret = -EINVAL; -		goto fail_free_wq; +		goto init_failed;  	}  	priv->mmio = ioremap_nocache(res->start, resource_size(res));  	if (!priv->mmio) { -		dev_err(dev->dev, "failed to ioremap\n"); +		dev_err(dev, "failed to ioremap\n");  		ret = -ENOMEM; -		goto fail_free_wq; +		goto init_failed;  	} -	priv->clk = clk_get(dev->dev, "fck"); +	priv->clk = clk_get(dev, "fck");  	if (IS_ERR(priv->clk)) { -		dev_err(dev->dev, "failed to get functional clock\n"); +		dev_err(dev, "failed to get functional clock\n");  		ret = -ENODEV; -		goto fail_iounmap; +		goto init_failed;  	}  #ifdef CONFIG_CPU_FREQ -	priv->lcd_fck_rate = clk_get_rate(priv->clk);  	priv->freq_transition.notifier_call = cpufreq_transition;  	ret = cpufreq_register_notifier(&priv->freq_transition,  			CPUFREQ_TRANSITION_NOTIFIER);  	if (ret) { -		dev_err(dev->dev, "failed to register cpufreq notifier\n"); -		goto fail_put_clk; +		dev_err(dev, "failed to register cpufreq notifier\n"); +		priv->freq_transition.notifier_call = NULL; +		goto init_failed;  	}  #endif @@ -216,22 +296,22 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)  	DBG("Maximum Bandwidth Value %d", priv->max_bandwidth); -	if (of_property_read_u32(node, "ti,max-width", &priv->max_width)) +	if (of_property_read_u32(node, "max-width", &priv->max_width))  		priv->max_width = TILCDC_DEFAULT_MAX_WIDTH;  	DBG("Maximum Horizontal Pixel Width Value %dpixels", priv->max_width); -	if (of_property_read_u32(node, "ti,max-pixelclock", +	if (of_property_read_u32(node, "max-pixelclock",  					&priv->max_pixelclock))  		priv->max_pixelclock = TILCDC_DEFAULT_MAX_PIXELCLOCK;  	DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); -	pm_runtime_enable(dev->dev); +	pm_runtime_enable(dev);  	/* Determine LCD IP Version */ -	pm_runtime_get_sync(dev->dev); -	switch (tilcdc_read(dev, LCDC_PID_REG)) { +	pm_runtime_get_sync(dev); +	switch (tilcdc_read(ddev, LCDC_PID_REG)) {  	case 0x4c100102:  		priv->rev = 1;  		break; @@ -240,110 +320,107 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)  		priv->rev = 2;  		break;  	default: -		dev_warn(dev->dev, "Unknown PID Reg value 0x%08x, " -				"defaulting to LCD revision 1\n", -				tilcdc_read(dev, LCDC_PID_REG)); +		dev_warn(dev, "Unknown PID Reg value 0x%08x, " +			"defaulting to LCD revision 1\n", +			tilcdc_read(ddev, LCDC_PID_REG));  		priv->rev = 1;  		break;  	} -	pm_runtime_put_sync(dev->dev); +	pm_runtime_put_sync(dev); -	ret = modeset_init(dev); -	if (ret < 0) { -		dev_err(dev->dev, "failed to initialize mode setting\n"); -		goto fail_cpufreq_unregister; +	if (priv->rev == 1) { +		DBG("Revision 1 LCDC supports only RGB565 format"); +		priv->pixelformats = tilcdc_rev1_formats; +		priv->num_pixelformats = ARRAY_SIZE(tilcdc_rev1_formats); +		bpp = 16; +	} else { +		const char *str = "\0"; + +		of_property_read_string(node, "blue-and-red-wiring", &str); +		if (0 == strcmp(str, "crossed")) { +			DBG("Configured for crossed blue and red wires"); +			priv->pixelformats = tilcdc_crossed_formats; +			priv->num_pixelformats = +				ARRAY_SIZE(tilcdc_crossed_formats); +			bpp = 32; /* Choose bpp with RGB support for fbdef */ +		} else if (0 == strcmp(str, "straight")) { +			DBG("Configured for straight blue and red wires"); +			priv->pixelformats = tilcdc_straight_formats; +			priv->num_pixelformats = +				ARRAY_SIZE(tilcdc_straight_formats); +			bpp = 16; /* Choose bpp with RGB support for fbdef */ +		} else { +			DBG("Blue and red wiring '%s' unknown, use legacy mode", +			    str); +			priv->pixelformats = tilcdc_legacy_formats; +			priv->num_pixelformats = +				ARRAY_SIZE(tilcdc_legacy_formats); +			bpp = 16; /* This is just a guess */ +		}  	} -	platform_set_drvdata(pdev, dev); +	ret = tilcdc_crtc_create(ddev); +	if (ret < 0) { +		dev_err(dev, "failed to create crtc\n"); +		goto init_failed; +	} +	modeset_init(ddev);  	if (priv->is_componentized) { -		ret = component_bind_all(dev->dev, dev); +		ret = component_bind_all(dev, ddev);  		if (ret < 0) -			goto fail_mode_config_cleanup; +			goto init_failed; -		ret = tilcdc_add_external_encoders(dev, &bpp); +		ret = tilcdc_add_component_encoder(ddev);  		if (ret < 0) -			goto fail_component_cleanup; +			goto init_failed; +	} else { +		ret = tilcdc_attach_external_device(ddev); +		if (ret) +			goto init_failed;  	} -	if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { -		dev_err(dev->dev, "no encoders/connectors found\n"); +	if (!priv->external_connector && +	    ((priv->num_encoders == 0) || (priv->num_connectors == 0))) { +		dev_err(dev, "no encoders/connectors found\n");  		ret = -ENXIO; -		goto fail_external_cleanup; +		goto init_failed;  	} -	ret = drm_vblank_init(dev, 1); +	ret = drm_vblank_init(ddev, 1);  	if (ret < 0) { -		dev_err(dev->dev, "failed to initialize vblank\n"); -		goto fail_external_cleanup; +		dev_err(dev, "failed to initialize vblank\n"); +		goto init_failed;  	} -	pm_runtime_get_sync(dev->dev); -	ret = drm_irq_install(dev, platform_get_irq(dev->platformdev, 0)); -	pm_runtime_put_sync(dev->dev); +	ret = drm_irq_install(ddev, platform_get_irq(pdev, 0));  	if (ret < 0) { -		dev_err(dev->dev, "failed to install IRQ handler\n"); -		goto fail_vblank_cleanup; +		dev_err(dev, "failed to install IRQ handler\n"); +		goto init_failed;  	} -	list_for_each_entry(mod, &module_list, list) { -		DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); -		bpp = mod->preferred_bpp; -		if (bpp > 0) -			break; -	} +	drm_mode_config_reset(ddev); -	drm_helper_disable_unused_functions(dev); -	priv->fbdev = drm_fbdev_cma_init(dev, bpp, -			dev->mode_config.num_crtc, -			dev->mode_config.num_connector); +	priv->fbdev = drm_fbdev_cma_init(ddev, bpp, +			ddev->mode_config.num_crtc, +			ddev->mode_config.num_connector);  	if (IS_ERR(priv->fbdev)) {  		ret = PTR_ERR(priv->fbdev); -		goto fail_irq_uninstall; +		goto init_failed;  	} -	drm_kms_helper_poll_init(dev); +	drm_kms_helper_poll_init(ddev); -	return 0; +	ret = drm_dev_register(ddev, 0); +	if (ret) +		goto init_failed; -fail_irq_uninstall: -	pm_runtime_get_sync(dev->dev); -	drm_irq_uninstall(dev); -	pm_runtime_put_sync(dev->dev); - -fail_vblank_cleanup: -	drm_vblank_cleanup(dev); - -fail_mode_config_cleanup: -	drm_mode_config_cleanup(dev); - -fail_component_cleanup: -	if (priv->is_componentized) -		component_unbind_all(dev->dev, dev); - -fail_external_cleanup: -	tilcdc_remove_external_encoders(dev); - -fail_cpufreq_unregister: -	pm_runtime_disable(dev->dev); -#ifdef CONFIG_CPU_FREQ -	cpufreq_unregister_notifier(&priv->freq_transition, -			CPUFREQ_TRANSITION_NOTIFIER); - -fail_put_clk: -#endif -	clk_put(priv->clk); - -fail_iounmap: -	iounmap(priv->mmio); - -fail_free_wq: -	flush_workqueue(priv->wq); -	destroy_workqueue(priv->wq); +	priv->is_registered = true; +	return 0; -fail_unset_priv: -	dev->dev_private = NULL; +init_failed: +	tilcdc_fini(ddev);  	return ret;  } @@ -361,45 +438,6 @@ static irqreturn_t tilcdc_irq(int irq, void *arg)  	return tilcdc_crtc_irq(priv->crtc);  } -static void tilcdc_irq_preinstall(struct drm_device *dev) -{ -	tilcdc_clear_irqstatus(dev, 0xffffffff); -} - -static int tilcdc_irq_postinstall(struct drm_device *dev) -{ -	struct tilcdc_drm_private *priv = dev->dev_private; - -	/* enable FIFO underflow irq: */ -	if (priv->rev == 1) { -		tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); -	} else { -		tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, -			   LCDC_V2_UNDERFLOW_INT_ENA | -			   LCDC_V2_END_OF_FRAME0_INT_ENA | -			   LCDC_FRAME_DONE | LCDC_SYNC_LOST); -	} - -	return 0; -} - -static void tilcdc_irq_uninstall(struct drm_device *dev) -{ -	struct tilcdc_drm_private *priv = dev->dev_private; - -	/* disable irqs that we might have enabled: */ -	if (priv->rev == 1) { -		tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, -				LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); -		tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA); -	} else { -		tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, -			LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | -			LCDC_V2_END_OF_FRAME0_INT_ENA | -			LCDC_FRAME_DONE | LCDC_SYNC_LOST); -	} -} -  static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe)  {  	return 0; @@ -410,7 +448,7 @@ static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe)  	return;  } -#if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) +#if defined(CONFIG_DEBUG_FS)  static const struct {  	const char *name;  	uint8_t  rev; @@ -441,15 +479,6 @@ static const struct {  #undef REG  }; -static size_t tilcdc_num_regs(void) -{ -	return ARRAY_SIZE(registers); -} -#else -static size_t tilcdc_num_regs(void) -{ -	return 0; -}  #endif  #ifdef CONFIG_DEBUG_FS @@ -526,9 +555,7 @@ static const struct file_operations fops = {  	.open               = drm_open,  	.release            = drm_release,  	.unlocked_ioctl     = drm_ioctl, -#ifdef CONFIG_COMPAT  	.compat_ioctl       = drm_compat_ioctl, -#endif  	.poll               = drm_poll,  	.read               = drm_read,  	.llseek             = no_llseek, @@ -537,14 +564,9 @@ static const struct file_operations fops = {  static struct drm_driver tilcdc_driver = {  	.driver_features    = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | -			       DRIVER_PRIME), -	.load               = tilcdc_load, -	.unload             = tilcdc_unload, +			       DRIVER_PRIME | DRIVER_ATOMIC),  	.lastclose          = tilcdc_lastclose,  	.irq_handler        = tilcdc_irq, -	.irq_preinstall     = tilcdc_irq_preinstall, -	.irq_postinstall    = tilcdc_irq_postinstall, -	.irq_uninstall      = tilcdc_irq_uninstall,  	.get_vblank_counter = drm_vblank_no_hw_counter,  	.enable_vblank      = tilcdc_enable_vblank,  	.disable_vblank     = tilcdc_disable_vblank, @@ -584,28 +606,12 @@ static int tilcdc_pm_suspend(struct device *dev)  {  	struct drm_device *ddev = dev_get_drvdata(dev);  	struct tilcdc_drm_private *priv = ddev->dev_private; -	unsigned i, n = 0; -	drm_kms_helper_poll_disable(ddev); +	priv->saved_state = drm_atomic_helper_suspend(ddev);  	/* Select sleep pin state */  	pinctrl_pm_select_sleep_state(dev); -	if (pm_runtime_suspended(dev)) { -		priv->ctx_valid = false; -		return 0; -	} - -	/* Disable the LCDC controller, to avoid locking up the PRCM */ -	tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); - -	/* Save register state: */ -	for (i = 0; i < ARRAY_SIZE(registers); i++) -		if (registers[i].save && (priv->rev >= registers[i].rev)) -			priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg); - -	priv->ctx_valid = true; -  	return 0;  } @@ -613,23 +619,15 @@ static int tilcdc_pm_resume(struct device *dev)  {  	struct drm_device *ddev = dev_get_drvdata(dev);  	struct tilcdc_drm_private *priv = ddev->dev_private; -	unsigned i, n = 0; +	int ret = 0;  	/* Select default pin state */  	pinctrl_pm_select_default_state(dev); -	if (priv->ctx_valid == true) { -		/* Restore register state: */ -		for (i = 0; i < ARRAY_SIZE(registers); i++) -			if (registers[i].save && -			    (priv->rev >= registers[i].rev)) -				tilcdc_write(ddev, registers[i].reg, -					     priv->saved_register[n++]); -	} - -	drm_kms_helper_poll_enable(ddev); +	if (priv->saved_state) +		ret = drm_atomic_helper_resume(ddev, priv->saved_state); -	return 0; +	return ret;  }  #endif @@ -640,15 +638,20 @@ static const struct dev_pm_ops tilcdc_pm_ops = {  /*   * Platform driver:   */ -  static int tilcdc_bind(struct device *dev)  { -	return drm_platform_init(&tilcdc_driver, to_platform_device(dev)); +	return tilcdc_init(&tilcdc_driver, dev);  }  static void tilcdc_unbind(struct device *dev)  { -	drm_put_dev(dev_get_drvdata(dev)); +	struct drm_device *ddev = dev_get_drvdata(dev); + +	/* Check if a subcomponent has already triggered the unloading. */ +	if (!ddev->dev_private) +		return; + +	tilcdc_fini(dev_get_drvdata(dev));  }  static const struct component_master_ops tilcdc_comp_ops = { @@ -671,7 +674,7 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)  	if (ret < 0)  		return ret;  	else if (ret == 0) -		return drm_platform_init(&tilcdc_driver, pdev); +		return tilcdc_init(&tilcdc_driver, &pdev->dev);  	else  		return component_master_add_with_match(&pdev->dev,  						       &tilcdc_comp_ops, @@ -680,23 +683,22 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)  static int tilcdc_pdev_remove(struct platform_device *pdev)  { -	struct drm_device *ddev = dev_get_drvdata(&pdev->dev); -	struct tilcdc_drm_private *priv = ddev->dev_private; - -	/* Check if a subcomponent has already triggered the unloading. */ -	if (!priv) -		return 0; +	int ret; -	if (priv->is_componentized) -		component_master_del(&pdev->dev, &tilcdc_comp_ops); +	ret = tilcdc_get_external_components(&pdev->dev, NULL); +	if (ret < 0) +		return ret; +	else if (ret == 0) +		tilcdc_fini(platform_get_drvdata(pdev));  	else -		drm_put_dev(platform_get_drvdata(pdev)); +		component_master_del(&pdev->dev, &tilcdc_comp_ops);  	return 0;  }  static struct of_device_id tilcdc_of_match[] = {  		{ .compatible = "ti,am33xx-tilcdc", }, +		{ .compatible = "ti,da850-tilcdc", },  		{ },  };  MODULE_DEVICE_TABLE(of, tilcdc_of_match);  | 
