diff mbox

[1/2] drm/exynos: consider deferred probe case

Message ID 1401194563-803-2-git-send-email-inki.dae@samsung.com (mailing list archive)
State New, archived
Headers show

Commit Message

Inki Dae May 27, 2014, 12:42 p.m. UTC
This patch makes sure that exynos drm framework handles deferred
probe case correctly.

Sub drivers could be probed before resources, clock, regulator,
phy or panel, are ready for them so we should make sure that exynos
drm core waits until all resources are ready and sub drivers are
probed correctly.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c  |   16 +++++++-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |   28 +++++++-------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |    7 +---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c  |   31 +++++++++++----
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |   49 +++++++++++++++++------
 drivers/gpu/drm/exynos/exynos_hdmi.c     |   62 ++++++++++++++++++++++--------
 drivers/gpu/drm/exynos/exynos_mixer.c    |   16 +++++++-
 7 files changed, 151 insertions(+), 58 deletions(-)

Comments

Andrzej Hajda May 28, 2014, 11:22 a.m. UTC | #1
Hi Inki,

On 05/27/2014 02:42 PM, Inki Dae wrote:
> This patch makes sure that exynos drm framework handles deferred
> probe case correctly.
>
> Sub drivers could be probed before resources, clock, regulator,
> phy or panel, are ready for them so we should make sure that exynos
> drm core waits until all resources are ready and sub drivers are
> probed correctly.
>
> Signed-off-by: Inki Dae <inki.dae@samsung.com>
> Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
> ---
>  drivers/gpu/drm/exynos/exynos_dp_core.c  |   16 +++++++-
>  drivers/gpu/drm/exynos/exynos_drm_drv.c  |   28 +++++++-------
>  drivers/gpu/drm/exynos/exynos_drm_drv.h  |    7 +---
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c  |   31 +++++++++++----
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c |   49 +++++++++++++++++------
>  drivers/gpu/drm/exynos/exynos_hdmi.c     |   62 ++++++++++++++++++++++--------
>  drivers/gpu/drm/exynos/exynos_mixer.c    |   16 +++++++-
>  7 files changed, 151 insertions(+), 58 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
> index ff63901..7526f36 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp_core.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
> @@ -1328,12 +1328,24 @@ static const struct component_ops exynos_dp_ops = {
>  
>  static int exynos_dp_probe(struct platform_device *pdev)
>  {
> -	return exynos_drm_component_add(&pdev->dev, &exynos_dp_ops);
> +	int ret;
> +
> +	ret = exynos_drm_component_add(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = component_add(&pdev->dev, &exynos_dp_ops);
> +	if (ret)
> +		exynos_drm_component_del(&pdev->dev);
> +
> +	return ret;

Hmm, exynos_drm_component_add adds component to the list of devices drm
master
should wait for and it is called from probe of each component. It is the
same concept
as the one I have proposed some times ago [1], the main difference is
that this one
is build on top of the component framework :)

[1]: http://permalink.gmane.org/gmane.comp.video.dri.devel/103817

Regarding the implementation, to allow it work with drivers unbinding
exynos_drm_component_del
should be removed and drm_component_list should be cleaned on drm module
removal.
This will also decrease significantly patch size, all those "goto
err_del_component" can be removed.

Two additional small comments below.

>  }
>  
>  static int exynos_dp_remove(struct platform_device *pdev)
>  {
> -	exynos_drm_component_del(&pdev->dev, &exynos_dp_ops);
> +	component_del(&pdev->dev, &exynos_dp_ops);
> +	exynos_drm_component_del(&pdev->dev);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> index c5a401ae..f611f5a 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> @@ -381,22 +381,25 @@ static const struct dev_pm_ops exynos_drm_pm_ops = {
>  	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
>  };
>  
> -int exynos_drm_component_add(struct device *dev,
> -				const struct component_ops *ops)
> +int exynos_drm_component_add(struct device *dev)
>  {
>  	struct component_dev *cdev;
> -	int ret;
> +
> +	mutex_lock(&drm_component_lock);
> +
> +	list_for_each_entry(cdev, &drm_component_list, list) {
> +		if (cdev->dev == dev) {
> +			mutex_unlock(&drm_component_lock);
> +			return 0;
> +		}
> +	}
> +
> +	mutex_unlock(&drm_component_lock);
>  
>  	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
>  	if (!cdev)
>  		return -ENOMEM;
>  
> -	ret = component_add(dev, ops);
> -	if (ret) {
> -		kfree(cdev);
> -		return ret;
> -	}
> -
>  	cdev->dev = dev;
>  
>  	mutex_lock(&drm_component_lock);
> @@ -406,8 +409,7 @@ int exynos_drm_component_add(struct device *dev,
>  	return 0;
>  }
>  
> -void exynos_drm_component_del(struct device *dev,
> -				const struct component_ops *ops)
> +void exynos_drm_component_del(struct device *dev)
>  {
>  	struct component_dev *cdev, *next;
>  
> @@ -422,8 +424,6 @@ void exynos_drm_component_del(struct device *dev,
>  	}
>  
>  	mutex_unlock(&drm_component_lock);
> -
> -	component_del(dev, ops);
>  }
>  
>  static int compare_of(struct device *dev, void *data)
> @@ -446,6 +446,8 @@ static int exynos_drm_add_components(struct device *dev, struct master *m)
>  		ret = component_master_add_child(m, compare_of, cdev->dev);
>  		if (!ret)
>  			attached_cnt++;
> +		else
> +			return ret;
>  
>  		mutex_lock(&drm_component_lock);
>  	}
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index e82e620..13480b2 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -354,12 +354,9 @@ void exynos_drm_remove_vidi(void);
>  int exynos_drm_create_enc_conn(struct drm_device *dev,
>  				struct exynos_drm_display *display);
>  
> -struct component_ops;
> -int exynos_drm_component_add(struct device *dev,
> -				const struct component_ops *ops);
> +int exynos_drm_component_add(struct device *dev);
>  
> -void exynos_drm_component_del(struct device *dev,
> -				const struct component_ops *ops);
> +void exynos_drm_component_del(struct device *dev);
>  
>  extern struct platform_driver fimd_driver;
>  extern struct platform_driver dp_driver;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index 84661fe..1421d9b 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1423,10 +1423,15 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  	struct exynos_dsi *dsi;
>  	int ret;
>  
> +	ret = exynos_drm_component_add(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
>  	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
>  	if (!dsi) {
>  		dev_err(&pdev->dev, "failed to allocate dsi object.\n");
> -		return -ENOMEM;
> +		ret = -ENOMEM;
> +		goto err_del_component;
>  	}
>  
>  	init_completion(&dsi->completed);
> @@ -1440,7 +1445,7 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  
>  	ret = exynos_dsi_parse_dt(dsi);
>  	if (ret)
> -		return ret;
> +		goto err_del_component;
>  
>  	dsi->supplies[0].supply = "vddcore";
>  	dsi->supplies[1].supply = "vddio";
> @@ -1467,7 +1472,8 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  	dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
>  	if (IS_ERR(dsi->reg_base)) {
>  		dev_err(&pdev->dev, "failed to remap io region\n");
> -		return PTR_ERR(dsi->reg_base);
> +		ret = PTR_ERR(dsi->reg_base);
> +		goto err_del_component;
>  	}
>  
>  	dsi->phy = devm_phy_get(&pdev->dev, "dsim");
> @@ -1479,7 +1485,8 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  	dsi->irq = platform_get_irq(pdev, 0);
>  	if (dsi->irq < 0) {
>  		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
> -		return dsi->irq;
> +		ret = dsi->irq;
> +		goto err_del_component;
>  	}
>  
>  	irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
> @@ -1488,19 +1495,29 @@ static int exynos_dsi_probe(struct platform_device *pdev)
>  					dev_name(&pdev->dev), dsi);
>  	if (ret) {
>  		dev_err(&pdev->dev, "failed to request dsi irq\n");
> -		return ret;
> +		goto err_del_component;
>  	}
>  
>  	exynos_dsi_display.ctx = dsi;
>  
>  	platform_set_drvdata(pdev, &exynos_dsi_display);
>  
> -	return exynos_drm_component_add(&pdev->dev, &exynos_dsi_component_ops);
> +	ret = component_add(&pdev->dev, &exynos_dsi_component_ops);
> +	if (ret)
> +		goto err_del_component;
> +
> +	return ret;
> +
> +err_del_component:
> +	exynos_drm_component_del(&pdev->dev);
> +	return ret;
>  }
>  
>  static int exynos_dsi_remove(struct platform_device *pdev)
>  {
> -	exynos_drm_component_del(&pdev->dev, &exynos_dsi_component_ops);
> +	component_del(&pdev->dev, &exynos_dsi_component_ops);
> +	exynos_drm_component_del(&pdev->dev);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index bd30d0c..5b85253 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -941,12 +941,21 @@ static int fimd_probe(struct platform_device *pdev)
>  	struct resource *res;
>  	int ret = -EINVAL;
>  
> -	if (!dev->of_node)
> -		return -ENODEV;
> +
> +	ret = exynos_drm_component_add(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	if (!dev->of_node) {
> +		ret = -ENODEV;
> +		goto err_del_component;
> +	}
>  
>  	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
> -	if (!ctx)
> -		return -ENOMEM;
> +	if (!ctx) {
> +		ret = -ENOMEM;
> +		goto err_del_component;
> +	}
>  
>  	ctx->dev = dev;
>  	ctx->suspended = true;
> @@ -959,32 +968,35 @@ static int fimd_probe(struct platform_device *pdev)
>  	ctx->bus_clk = devm_clk_get(dev, "fimd");
>  	if (IS_ERR(ctx->bus_clk)) {
>  		dev_err(dev, "failed to get bus clock\n");
> -		return PTR_ERR(ctx->bus_clk);
> +		return -EPROBE_DEFER;
I think it is not correct to mask any clock error by -EPROBE_DEFER.
It will be OK to return PTR_ERR(ctx->bus_clk).
>  	}
>  
>  	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
>  	if (IS_ERR(ctx->lcd_clk)) {
>  		dev_err(dev, "failed to get lcd clock\n");
> -		return PTR_ERR(ctx->lcd_clk);
> +		return -EPROBE_DEFER;
>  	}
ditto

Regards
Andrzej
>  
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  
>  	ctx->regs = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(ctx->regs))
> -		return PTR_ERR(ctx->regs);
> +	if (IS_ERR(ctx->regs)) {
> +		ret = PTR_ERR(ctx->regs);
> +		goto err_del_component;
> +	}
>  
>  	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
>  	if (!res) {
>  		dev_err(dev, "irq request failed.\n");
> -		return -ENXIO;
> +		ret = -ENXIO;
> +		goto err_del_component;
>  	}
>  
>  	ret = devm_request_irq(dev, res->start, fimd_irq_handler,
>  							0, "drm_fimd", ctx);
>  	if (ret) {
>  		dev_err(dev, "irq request failed.\n");
> -		return ret;
> +		goto err_del_component;
>  	}
>  
>  	ctx->driver_data = drm_fimd_get_driver_data(pdev);
> @@ -1001,14 +1013,27 @@ static int fimd_probe(struct platform_device *pdev)
>  
>  	pm_runtime_enable(&pdev->dev);
>  
> -	return exynos_drm_component_add(&pdev->dev, &fimd_component_ops);
> +	ret = component_add(&pdev->dev, &fimd_component_ops);
> +	if (ret)
> +		goto err_disable_pm_runtime;
> +
> +	return ret;
> +
> +err_disable_pm_runtime:
> +	pm_runtime_disable(&pdev->dev);
> +
> +err_del_component:
> +	exynos_drm_component_del(&pdev->dev);
> +	return ret;
>  }
>  
>  static int fimd_remove(struct platform_device *pdev)
>  {
>  	pm_runtime_disable(&pdev->dev);
>  
> -	exynos_drm_component_del(&pdev->dev, &fimd_component_ops);
> +	component_del(&pdev->dev, &fimd_component_ops);
> +	exynos_drm_component_del(&pdev->dev);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index e05c86a..5919800 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -2275,24 +2275,36 @@ static int hdmi_probe(struct platform_device *pdev)
>  	struct resource *res;
>  	int ret;
>  
> -	if (!dev->of_node)
> -		return -ENODEV;
> +	ret = exynos_drm_component_add(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	if (!dev->of_node) {
> +		ret = -ENODEV;
> +		goto err_del_component;
> +	}
>  
>  	pdata = drm_hdmi_dt_parse_pdata(dev);
> -	if (!pdata)
> -		return -EINVAL;
> +	if (!pdata) {
> +		ret = -EINVAL;
> +		goto err_del_component;
> +	}
>  
>  	hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
> -	if (!hdata)
> -		return -ENOMEM;
> +	if (!hdata) {
> +		ret = -ENOMEM;
> +		goto err_del_component;
> +	}
>  
>  	mutex_init(&hdata->hdmi_mutex);
>  
>  	platform_set_drvdata(pdev, &hdmi_display);
>  
>  	match = of_match_node(hdmi_match_types, dev->of_node);
> -	if (!match)
> -		return -ENODEV;
> +	if (!match) {
> +		ret = -ENODEV;
> +		goto err_del_component;
> +	}
>  
>  	drv_data = (struct hdmi_driver_data *)match->data;
>  	hdata->type = drv_data->type;
> @@ -2305,18 +2317,20 @@ static int hdmi_probe(struct platform_device *pdev)
>  	ret = hdmi_resources_init(hdata);
>  	if (ret) {
>  		DRM_ERROR("hdmi_resources_init failed\n");
> -		return -EINVAL;
> +		return -EPROBE_DEFER;
>  	}
>  
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	hdata->regs = devm_ioremap_resource(dev, res);
> -	if (IS_ERR(hdata->regs))
> -		return PTR_ERR(hdata->regs);
> +	if (IS_ERR(hdata->regs)) {
> +		ret = PTR_ERR(hdata->regs);
> +		goto err_del_component;
> +	}
>  
>  	ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
>  	if (ret) {
>  		DRM_ERROR("failed to request HPD gpio\n");
> -		return ret;
> +		goto err_del_component;
>  	}
>  
>  	ddc_node = hdmi_legacy_ddc_dt_binding(dev);
> @@ -2327,14 +2341,15 @@ static int hdmi_probe(struct platform_device *pdev)
>  	ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
>  	if (!ddc_node) {
>  		DRM_ERROR("Failed to find ddc node in device tree\n");
> -		return -ENODEV;
> +		ret = -ENODEV;
> +		goto err_del_component;
>  	}
>  
>  out_get_ddc_adpt:
>  	hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
>  	if (!hdata->ddc_adpt) {
>  		DRM_ERROR("Failed to get ddc i2c adapter by node\n");
> -		return -ENODEV;
> +		return -EPROBE_DEFER;
>  	}
>  
>  	phy_node = hdmi_legacy_phy_dt_binding(dev);
> @@ -2361,7 +2376,7 @@ out_get_phy_port:
>  		hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
>  		if (!hdata->hdmiphy_port) {
>  			DRM_ERROR("Failed to get hdmi phy i2c client\n");
> -			ret = -ENODEV;
> +			ret = -EPROBE_DEFER;
>  			goto err_ddc;
>  		}
>  	}
> @@ -2390,19 +2405,31 @@ out_get_phy_port:
>  			"samsung,syscon-phandle");
>  	if (IS_ERR(hdata->pmureg)) {
>  		DRM_ERROR("syscon regmap lookup failed.\n");
> +		ret = -EPROBE_DEFER;
>  		goto err_hdmiphy;
>  	}
>  
>  	pm_runtime_enable(dev);
>  	hdmi_display.ctx = hdata;
>  
> -	return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
> +	ret = component_add(&pdev->dev, &hdmi_component_ops);
> +	if (ret)
> +		goto err_disable_pm_runtime;
> +
> +	return ret;
> +
> +err_disable_pm_runtime:
> +	pm_runtime_disable(dev);
>  
>  err_hdmiphy:
>  	if (hdata->hdmiphy_port)
>  		put_device(&hdata->hdmiphy_port->dev);
>  err_ddc:
>  	put_device(&hdata->ddc_adpt->dev);
> +
> +err_del_component:
> +	exynos_drm_component_del(&pdev->dev);
> +
>  	return ret;
>  }
>  
> @@ -2416,8 +2443,9 @@ static int hdmi_remove(struct platform_device *pdev)
>  	put_device(&hdata->ddc_adpt->dev);
>  
>  	pm_runtime_disable(&pdev->dev);
> +	component_del(&pdev->dev, &hdmi_component_ops);
>  
> -	exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
> +	exynos_drm_component_del(&pdev->dev);
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
> index 483d7c0..eaae17b 100644
> --- a/drivers/gpu/drm/exynos/exynos_mixer.c
> +++ b/drivers/gpu/drm/exynos/exynos_mixer.c
> @@ -1273,12 +1273,24 @@ static const struct component_ops mixer_component_ops = {
>  
>  static int mixer_probe(struct platform_device *pdev)
>  {
> -	return exynos_drm_component_add(&pdev->dev, &mixer_component_ops);
> +	int ret;
> +
> +	ret = exynos_drm_component_add(&pdev->dev);
> +	if (ret)
> +		return ret;
> +
> +	ret = component_add(&pdev->dev, &mixer_component_ops);
> +	if (ret)
> +		exynos_drm_component_del(&pdev->dev);
> +
> +	return ret;
>  }
>  
>  static int mixer_remove(struct platform_device *pdev)
>  {
> -	exynos_drm_component_del(&pdev->dev, &mixer_component_ops);
> +	component_del(&pdev->dev, &mixer_component_ops);
> +	exynos_drm_component_del(&pdev->dev);
> +
>  	return 0;
>  }
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index ff63901..7526f36 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -1328,12 +1328,24 @@  static const struct component_ops exynos_dp_ops = {
 
 static int exynos_dp_probe(struct platform_device *pdev)
 {
-	return exynos_drm_component_add(&pdev->dev, &exynos_dp_ops);
+	int ret;
+
+	ret = exynos_drm_component_add(&pdev->dev);
+	if (ret)
+		return ret;
+
+	ret = component_add(&pdev->dev, &exynos_dp_ops);
+	if (ret)
+		exynos_drm_component_del(&pdev->dev);
+
+	return ret;
 }
 
 static int exynos_dp_remove(struct platform_device *pdev)
 {
-	exynos_drm_component_del(&pdev->dev, &exynos_dp_ops);
+	component_del(&pdev->dev, &exynos_dp_ops);
+	exynos_drm_component_del(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index c5a401ae..f611f5a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -381,22 +381,25 @@  static const struct dev_pm_ops exynos_drm_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
 };
 
-int exynos_drm_component_add(struct device *dev,
-				const struct component_ops *ops)
+int exynos_drm_component_add(struct device *dev)
 {
 	struct component_dev *cdev;
-	int ret;
+
+	mutex_lock(&drm_component_lock);
+
+	list_for_each_entry(cdev, &drm_component_list, list) {
+		if (cdev->dev == dev) {
+			mutex_unlock(&drm_component_lock);
+			return 0;
+		}
+	}
+
+	mutex_unlock(&drm_component_lock);
 
 	cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
 	if (!cdev)
 		return -ENOMEM;
 
-	ret = component_add(dev, ops);
-	if (ret) {
-		kfree(cdev);
-		return ret;
-	}
-
 	cdev->dev = dev;
 
 	mutex_lock(&drm_component_lock);
@@ -406,8 +409,7 @@  int exynos_drm_component_add(struct device *dev,
 	return 0;
 }
 
-void exynos_drm_component_del(struct device *dev,
-				const struct component_ops *ops)
+void exynos_drm_component_del(struct device *dev)
 {
 	struct component_dev *cdev, *next;
 
@@ -422,8 +424,6 @@  void exynos_drm_component_del(struct device *dev,
 	}
 
 	mutex_unlock(&drm_component_lock);
-
-	component_del(dev, ops);
 }
 
 static int compare_of(struct device *dev, void *data)
@@ -446,6 +446,8 @@  static int exynos_drm_add_components(struct device *dev, struct master *m)
 		ret = component_master_add_child(m, compare_of, cdev->dev);
 		if (!ret)
 			attached_cnt++;
+		else
+			return ret;
 
 		mutex_lock(&drm_component_lock);
 	}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index e82e620..13480b2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -354,12 +354,9 @@  void exynos_drm_remove_vidi(void);
 int exynos_drm_create_enc_conn(struct drm_device *dev,
 				struct exynos_drm_display *display);
 
-struct component_ops;
-int exynos_drm_component_add(struct device *dev,
-				const struct component_ops *ops);
+int exynos_drm_component_add(struct device *dev);
 
-void exynos_drm_component_del(struct device *dev,
-				const struct component_ops *ops);
+void exynos_drm_component_del(struct device *dev);
 
 extern struct platform_driver fimd_driver;
 extern struct platform_driver dp_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 84661fe..1421d9b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1423,10 +1423,15 @@  static int exynos_dsi_probe(struct platform_device *pdev)
 	struct exynos_dsi *dsi;
 	int ret;
 
+	ret = exynos_drm_component_add(&pdev->dev);
+	if (ret)
+		return ret;
+
 	dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
 	if (!dsi) {
 		dev_err(&pdev->dev, "failed to allocate dsi object.\n");
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto err_del_component;
 	}
 
 	init_completion(&dsi->completed);
@@ -1440,7 +1445,7 @@  static int exynos_dsi_probe(struct platform_device *pdev)
 
 	ret = exynos_dsi_parse_dt(dsi);
 	if (ret)
-		return ret;
+		goto err_del_component;
 
 	dsi->supplies[0].supply = "vddcore";
 	dsi->supplies[1].supply = "vddio";
@@ -1467,7 +1472,8 @@  static int exynos_dsi_probe(struct platform_device *pdev)
 	dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR(dsi->reg_base)) {
 		dev_err(&pdev->dev, "failed to remap io region\n");
-		return PTR_ERR(dsi->reg_base);
+		ret = PTR_ERR(dsi->reg_base);
+		goto err_del_component;
 	}
 
 	dsi->phy = devm_phy_get(&pdev->dev, "dsim");
@@ -1479,7 +1485,8 @@  static int exynos_dsi_probe(struct platform_device *pdev)
 	dsi->irq = platform_get_irq(pdev, 0);
 	if (dsi->irq < 0) {
 		dev_err(&pdev->dev, "failed to request dsi irq resource\n");
-		return dsi->irq;
+		ret = dsi->irq;
+		goto err_del_component;
 	}
 
 	irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
@@ -1488,19 +1495,29 @@  static int exynos_dsi_probe(struct platform_device *pdev)
 					dev_name(&pdev->dev), dsi);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request dsi irq\n");
-		return ret;
+		goto err_del_component;
 	}
 
 	exynos_dsi_display.ctx = dsi;
 
 	platform_set_drvdata(pdev, &exynos_dsi_display);
 
-	return exynos_drm_component_add(&pdev->dev, &exynos_dsi_component_ops);
+	ret = component_add(&pdev->dev, &exynos_dsi_component_ops);
+	if (ret)
+		goto err_del_component;
+
+	return ret;
+
+err_del_component:
+	exynos_drm_component_del(&pdev->dev);
+	return ret;
 }
 
 static int exynos_dsi_remove(struct platform_device *pdev)
 {
-	exynos_drm_component_del(&pdev->dev, &exynos_dsi_component_ops);
+	component_del(&pdev->dev, &exynos_dsi_component_ops);
+	exynos_drm_component_del(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index bd30d0c..5b85253 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -941,12 +941,21 @@  static int fimd_probe(struct platform_device *pdev)
 	struct resource *res;
 	int ret = -EINVAL;
 
-	if (!dev->of_node)
-		return -ENODEV;
+
+	ret = exynos_drm_component_add(&pdev->dev);
+	if (ret)
+		return ret;
+
+	if (!dev->of_node) {
+		ret = -ENODEV;
+		goto err_del_component;
+	}
 
 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
+	if (!ctx) {
+		ret = -ENOMEM;
+		goto err_del_component;
+	}
 
 	ctx->dev = dev;
 	ctx->suspended = true;
@@ -959,32 +968,35 @@  static int fimd_probe(struct platform_device *pdev)
 	ctx->bus_clk = devm_clk_get(dev, "fimd");
 	if (IS_ERR(ctx->bus_clk)) {
 		dev_err(dev, "failed to get bus clock\n");
-		return PTR_ERR(ctx->bus_clk);
+		return -EPROBE_DEFER;
 	}
 
 	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
 	if (IS_ERR(ctx->lcd_clk)) {
 		dev_err(dev, "failed to get lcd clock\n");
-		return PTR_ERR(ctx->lcd_clk);
+		return -EPROBE_DEFER;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
 	ctx->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(ctx->regs))
-		return PTR_ERR(ctx->regs);
+	if (IS_ERR(ctx->regs)) {
+		ret = PTR_ERR(ctx->regs);
+		goto err_del_component;
+	}
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
 	if (!res) {
 		dev_err(dev, "irq request failed.\n");
-		return -ENXIO;
+		ret = -ENXIO;
+		goto err_del_component;
 	}
 
 	ret = devm_request_irq(dev, res->start, fimd_irq_handler,
 							0, "drm_fimd", ctx);
 	if (ret) {
 		dev_err(dev, "irq request failed.\n");
-		return ret;
+		goto err_del_component;
 	}
 
 	ctx->driver_data = drm_fimd_get_driver_data(pdev);
@@ -1001,14 +1013,27 @@  static int fimd_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(&pdev->dev);
 
-	return exynos_drm_component_add(&pdev->dev, &fimd_component_ops);
+	ret = component_add(&pdev->dev, &fimd_component_ops);
+	if (ret)
+		goto err_disable_pm_runtime;
+
+	return ret;
+
+err_disable_pm_runtime:
+	pm_runtime_disable(&pdev->dev);
+
+err_del_component:
+	exynos_drm_component_del(&pdev->dev);
+	return ret;
 }
 
 static int fimd_remove(struct platform_device *pdev)
 {
 	pm_runtime_disable(&pdev->dev);
 
-	exynos_drm_component_del(&pdev->dev, &fimd_component_ops);
+	component_del(&pdev->dev, &fimd_component_ops);
+	exynos_drm_component_del(&pdev->dev);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index e05c86a..5919800 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2275,24 +2275,36 @@  static int hdmi_probe(struct platform_device *pdev)
 	struct resource *res;
 	int ret;
 
-	if (!dev->of_node)
-		return -ENODEV;
+	ret = exynos_drm_component_add(&pdev->dev);
+	if (ret)
+		return ret;
+
+	if (!dev->of_node) {
+		ret = -ENODEV;
+		goto err_del_component;
+	}
 
 	pdata = drm_hdmi_dt_parse_pdata(dev);
-	if (!pdata)
-		return -EINVAL;
+	if (!pdata) {
+		ret = -EINVAL;
+		goto err_del_component;
+	}
 
 	hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
-	if (!hdata)
-		return -ENOMEM;
+	if (!hdata) {
+		ret = -ENOMEM;
+		goto err_del_component;
+	}
 
 	mutex_init(&hdata->hdmi_mutex);
 
 	platform_set_drvdata(pdev, &hdmi_display);
 
 	match = of_match_node(hdmi_match_types, dev->of_node);
-	if (!match)
-		return -ENODEV;
+	if (!match) {
+		ret = -ENODEV;
+		goto err_del_component;
+	}
 
 	drv_data = (struct hdmi_driver_data *)match->data;
 	hdata->type = drv_data->type;
@@ -2305,18 +2317,20 @@  static int hdmi_probe(struct platform_device *pdev)
 	ret = hdmi_resources_init(hdata);
 	if (ret) {
 		DRM_ERROR("hdmi_resources_init failed\n");
-		return -EINVAL;
+		return -EPROBE_DEFER;
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	hdata->regs = devm_ioremap_resource(dev, res);
-	if (IS_ERR(hdata->regs))
-		return PTR_ERR(hdata->regs);
+	if (IS_ERR(hdata->regs)) {
+		ret = PTR_ERR(hdata->regs);
+		goto err_del_component;
+	}
 
 	ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
 	if (ret) {
 		DRM_ERROR("failed to request HPD gpio\n");
-		return ret;
+		goto err_del_component;
 	}
 
 	ddc_node = hdmi_legacy_ddc_dt_binding(dev);
@@ -2327,14 +2341,15 @@  static int hdmi_probe(struct platform_device *pdev)
 	ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
 	if (!ddc_node) {
 		DRM_ERROR("Failed to find ddc node in device tree\n");
-		return -ENODEV;
+		ret = -ENODEV;
+		goto err_del_component;
 	}
 
 out_get_ddc_adpt:
 	hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
 	if (!hdata->ddc_adpt) {
 		DRM_ERROR("Failed to get ddc i2c adapter by node\n");
-		return -ENODEV;
+		return -EPROBE_DEFER;
 	}
 
 	phy_node = hdmi_legacy_phy_dt_binding(dev);
@@ -2361,7 +2376,7 @@  out_get_phy_port:
 		hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
 		if (!hdata->hdmiphy_port) {
 			DRM_ERROR("Failed to get hdmi phy i2c client\n");
-			ret = -ENODEV;
+			ret = -EPROBE_DEFER;
 			goto err_ddc;
 		}
 	}
@@ -2390,19 +2405,31 @@  out_get_phy_port:
 			"samsung,syscon-phandle");
 	if (IS_ERR(hdata->pmureg)) {
 		DRM_ERROR("syscon regmap lookup failed.\n");
+		ret = -EPROBE_DEFER;
 		goto err_hdmiphy;
 	}
 
 	pm_runtime_enable(dev);
 	hdmi_display.ctx = hdata;
 
-	return exynos_drm_component_add(&pdev->dev, &hdmi_component_ops);
+	ret = component_add(&pdev->dev, &hdmi_component_ops);
+	if (ret)
+		goto err_disable_pm_runtime;
+
+	return ret;
+
+err_disable_pm_runtime:
+	pm_runtime_disable(dev);
 
 err_hdmiphy:
 	if (hdata->hdmiphy_port)
 		put_device(&hdata->hdmiphy_port->dev);
 err_ddc:
 	put_device(&hdata->ddc_adpt->dev);
+
+err_del_component:
+	exynos_drm_component_del(&pdev->dev);
+
 	return ret;
 }
 
@@ -2416,8 +2443,9 @@  static int hdmi_remove(struct platform_device *pdev)
 	put_device(&hdata->ddc_adpt->dev);
 
 	pm_runtime_disable(&pdev->dev);
+	component_del(&pdev->dev, &hdmi_component_ops);
 
-	exynos_drm_component_del(&pdev->dev, &hdmi_component_ops);
+	exynos_drm_component_del(&pdev->dev);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 483d7c0..eaae17b 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1273,12 +1273,24 @@  static const struct component_ops mixer_component_ops = {
 
 static int mixer_probe(struct platform_device *pdev)
 {
-	return exynos_drm_component_add(&pdev->dev, &mixer_component_ops);
+	int ret;
+
+	ret = exynos_drm_component_add(&pdev->dev);
+	if (ret)
+		return ret;
+
+	ret = component_add(&pdev->dev, &mixer_component_ops);
+	if (ret)
+		exynos_drm_component_del(&pdev->dev);
+
+	return ret;
 }
 
 static int mixer_remove(struct platform_device *pdev)
 {
-	exynos_drm_component_del(&pdev->dev, &mixer_component_ops);
+	component_del(&pdev->dev, &mixer_component_ops);
+	exynos_drm_component_del(&pdev->dev);
+
 	return 0;
 }