The patch adds function to block/unblock drm master device initialization.
exynos_drm_dev_ready(pdev, bool) informs exynos_drm core if given device is
ready. exynos_drm master is initialized only if all devices are ready,
exynos_drm master is also removed if any device becomes not ready.
During module initialization before driver registration module scans for
devices matching given driver and marks them as not-ready. Driver during
probe/remove can inform exynos_drm core about device readiness, triggering
master drm init/remove.
The core of the patch is in exynos_drm_drv.c.
Drivers modifications is limited only to call exynos_drm_dev_ready on return
from probe and in remove callback before manager/display/subdriver
unregistration.

Signed-off-by: Andrzej Hajda <a.hajda at samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c     |  35 +++++----
 drivers/gpu/drm/exynos/exynos_drm_drv.c     | 106 +++++++++++++++++++++++++++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h     |   2 +
 drivers/gpu/drm/exynos/exynos_drm_dsi.c     |  40 ++++++-----
 drivers/gpu/drm/exynos/exynos_drm_fimc.c    |  33 +++++----
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    |  36 +++++++---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c     |  15 ++--
 drivers/gpu/drm/exynos/exynos_drm_gsc.c     |  28 +++++---
 drivers/gpu/drm/exynos/exynos_drm_ipp.c     |  16 +++--
 drivers/gpu/drm/exynos/exynos_drm_rotator.c |  25 ++++---
 drivers/gpu/drm/exynos/exynos_drm_vidi.c    |  16 +++--
 drivers/gpu/drm/exynos/exynos_hdmi.c        |  51 ++++++++-----
 drivers/gpu/drm/exynos/exynos_mixer.c       |  12 +++-
 13 files changed, 307 insertions(+), 108 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c 
b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 9385e96..b2955cc 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -1240,29 +1240,32 @@ static int exynos_dp_probe(struct platform_device *pdev)
        dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
                                GFP_KERNEL);
        if (!dp) {
-               dev_err(&pdev->dev, "no memory for device data\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }

        dp->dev = &pdev->dev;
        dp->dpms_mode = DRM_MODE_DPMS_OFF;

        dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
-       if (IS_ERR(dp->video_info))
-               return PTR_ERR(dp->video_info);
+       if (IS_ERR(dp->video_info)) {
+               ret = PTR_ERR(dp->video_info);
+               goto out;
+       }

        ret = exynos_dp_dt_parse_phydata(dp);
        if (ret)
-               return ret;
+               goto out;

        ret = exynos_dp_dt_parse_panel(dp);
        if (ret)
-               return ret;
+               goto out;

        dp->clock = devm_clk_get(&pdev->dev, "dp");
        if (IS_ERR(dp->clock)) {
                dev_err(&pdev->dev, "failed to get clock\n");
-               return PTR_ERR(dp->clock);
+               ret = PTR_ERR(dp->clock);
+               goto out;
        }

        clk_prepare_enable(dp->clock);
@@ -1270,13 +1273,16 @@ static int exynos_dp_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

        dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dp->reg_base))
-               return PTR_ERR(dp->reg_base);
+       if (IS_ERR(dp->reg_base)) {
+               ret = PTR_ERR(dp->reg_base);
+               goto out;
+       }

        dp->irq = platform_get_irq(pdev, 0);
        if (dp->irq == -ENXIO) {
                dev_err(&pdev->dev, "failed to get irq\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out;
        }

        INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
@@ -1289,7 +1295,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
                                "exynos-dp", dp);
        if (ret) {
                dev_err(&pdev->dev, "failed to request irq\n");
-               return ret;
+               goto out;
        }
        disable_irq(dp->irq);

@@ -1298,13 +1304,18 @@ static int exynos_dp_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, &exynos_dp_display);
        exynos_drm_display_register(&exynos_dp_display);

-       return 0;
+out:
+       exynos_drm_dev_ready(pdev, ret != -EPROBE_DEFER);
+
+       return ret;
 }

 static int exynos_dp_remove(struct platform_device *pdev)
 {
        struct exynos_drm_display *display = platform_get_drvdata(pdev);

+       exynos_drm_dev_ready(pdev, false);
+
        exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
        exynos_drm_display_unregister(&exynos_dp_display);

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c 
b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 5067b32..d63ae9e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -366,12 +366,12 @@ static int exynos_drm_platform_probe(struct 
platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);

-       return drm_platform_init(&exynos_drm_driver, pdev);
+       return exynos_drm_dev_ready(pdev, true);
 }

 static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-       drm_put_dev(platform_get_drvdata(pdev));
+       exynos_drm_dev_ready(pdev, false);

        return 0;
 }
@@ -455,6 +455,104 @@ static void exynos_platform_device_drm_unregister(void)
        platform_device_unregister(exynos_drm_pdev);
 }

+struct pdev_node {
+       struct list_head list;
+       struct platform_device *pdev;
+};
+
+static DEFINE_MUTEX(exynos_drm_blockers_mutex);
+static LIST_HEAD(exynos_drm_blockers);
+
+int exynos_drm_dev_ready(struct platform_device *pdev, bool ready)
+{
+       static bool master_ready;
+       struct pdev_node *n;
+       bool update = false;
+       int ret = 0;
+
+       dev_dbg(&pdev->dev, "exynos_drm %s ready=%d\n",
+               (pdev == exynos_drm_pdev) ? "master" : "subdev", ready);
+
+       mutex_lock(&exynos_drm_blockers_mutex);
+       list_for_each_entry(n, &exynos_drm_blockers, list) {
+               if (n->pdev != pdev)
+                       continue;
+
+               if (!ready)
+                       goto out;
+
+               list_del(&n->list);
+               kfree(n);
+
+               if (list_empty(&exynos_drm_blockers))
+                       update = true;
+               break;
+       }
+
+       if (!ready) {
+               struct pdev_node *p = kmalloc(sizeof(*p), GFP_KERNEL);
+
+               if (!p) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               if (list_empty(&exynos_drm_blockers))
+                       update = true;
+
+               p->pdev = pdev;
+               list_add_tail(&p->list, &exynos_drm_blockers);
+       }
+
+       if (pdev == exynos_drm_pdev) {
+               master_ready = ready;
+               update = list_empty(&exynos_drm_blockers) && ready;
+       } else if (!master_ready) {
+               goto out;
+       }
+
+       if (!update)
+               goto out;
+
+       if (ready)
+               ret = drm_platform_init(&exynos_drm_driver, exynos_drm_pdev);
+       else
+               drm_put_dev(platform_get_drvdata(exynos_drm_pdev));
+
+out:
+       mutex_unlock(&exynos_drm_blockers_mutex);
+
+       return ret;
+}
+
+static int exynos_drm_add_blocker(struct device *dev, void *data)
+{
+       struct platform_driver *pd = data;
+
+       if (!platform_bus_type.match(dev, &pd->driver))
+               return 0;
+
+       if (!dev->driver)
+               exynos_drm_dev_ready(to_platform_device(dev), false);
+
+       return 0;
+}
+
+static void exynos_drm_add_pdrv_blockers(struct platform_driver *pd)
+{
+       bus_for_each_dev(&platform_bus_type, NULL, pd, exynos_drm_add_blocker);
+}
+
+static void exynos_drm_remove_blockers(void)
+{
+       struct pdev_node *n, *tmp;
+
+       list_for_each_entry_safe(n, tmp, &exynos_drm_blockers, list) {
+               list_del(&n->list);
+               kfree(n);
+       }
+}
+
 extern struct platform_driver exynos_drm_drivers;

 static int __init exynos_drm_init(void)
@@ -472,6 +570,7 @@ static int __init exynos_drm_init(void)

        while (pd <= &exynos_drm_drv) {
                pr_debug("%s: registering %s\n", __func__, pd->driver.name);
+               exynos_drm_add_pdrv_blockers(pd);
                ret = platform_driver_register(pd);
                if (ret < 0)
                        goto err;
@@ -485,6 +584,8 @@ err:
 err_dev:
        exynos_platform_device_ipp_unregister();

+       exynos_drm_remove_blockers();
+
        return ret;
 }

@@ -498,6 +599,7 @@ static void __exit exynos_drm_exit(void)
        exynos_platform_device_drm_unregister();
        exynos_platform_device_ipp_unregister();

+       exynos_drm_remove_blockers();
 }

 module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h 
b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 3917200..743080a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -359,6 +359,8 @@ static inline int exynos_platform_device_ipp_register() { 
return 0; }
 static inline void exynos_platform_device_ipp_unregister() {}
 #endif

+int exynos_drm_dev_ready(struct platform_device *pdev, bool ready);
+
 #ifdef CONFIG_DRM_EXYNOS_DPI
 int exynos_dpi_probe(struct device *dev);
 int exynos_dpi_remove(struct device *dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c 
b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 56230e6..948f405 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1386,8 +1386,8 @@ static int exynos_dsi_probe(struct platform_device *pdev)

        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 out;
        }

        init_completion(&dsi->completed);
@@ -1401,46 +1401,48 @@ static int exynos_dsi_probe(struct platform_device 
*pdev)

        ret = exynos_dsi_parse_dt(dsi);
        if (ret)
-               return ret;
+               goto out;

        dsi->supplies[0].supply = "vddcore";
        dsi->supplies[1].supply = "vddio";
        ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies),
                                      dsi->supplies);
-       if (ret) {
-               dev_info(&pdev->dev, "failed to get regulators: %d\n", ret);
-               return -EPROBE_DEFER;
-       }
+       if (ret)
+               goto out;

        dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk");
        if (IS_ERR(dsi->pll_clk)) {
-               dev_info(&pdev->dev, "failed to get dsi pll input clock\n");
-               return -EPROBE_DEFER;
+               ret = PTR_ERR(dsi->pll_clk);
+               dev_info(&pdev->dev, "failed to get dsi pll clock\n");
+               goto out;
        }

        dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
        if (IS_ERR(dsi->bus_clk)) {
+               ret = PTR_ERR(dsi->bus_clk);
                dev_info(&pdev->dev, "failed to get dsi bus clock\n");
-               return -EPROBE_DEFER;
+               goto out;
        }

        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
        if (!dsi->reg_base) {
                dev_err(&pdev->dev, "failed to remap io region\n");
-               return -EADDRNOTAVAIL;
+               ret = -EADDRNOTAVAIL;
+               goto out;
        }

        dsi->phy = devm_phy_get(&pdev->dev, "dsim");
        if (IS_ERR(dsi->phy)) {
-               dev_info(&pdev->dev, "failed to get dsim phy\n");
-               return -EPROBE_DEFER;
+               ret = PTR_ERR(dsi->phy);
+               goto out;
        }

        dsi->irq = platform_get_irq(pdev, 0);
        if (dsi->irq < 0) {
+               ret = dsi->irq;
                dev_err(&pdev->dev, "failed to request dsi irq resource\n");
-               return dsi->irq;
+               goto out;
        }

        irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
@@ -1449,7 +1451,7 @@ 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 out;
        }

        exynos_dsi_display.ctx = dsi;
@@ -1457,7 +1459,11 @@ static int exynos_dsi_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, &exynos_dsi_display);
        exynos_drm_display_register(&exynos_dsi_display);

-       return mipi_dsi_host_register(&dsi->dsi_host);
+       ret = mipi_dsi_host_register(&dsi->dsi_host);
+out:
+       exynos_drm_dev_ready(pdev, ret != -EPROBE_DEFER);
+
+       return ret;
 }

 static int exynos_dsi_remove(struct platform_device *pdev)
@@ -1465,7 +1471,7 @@ static int exynos_dsi_remove(struct platform_device *pdev)
        struct exynos_dsi *dsi = exynos_dsi_display.ctx;

        exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
-
+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_display_unregister(&exynos_dsi_display);
        mipi_dsi_host_unregister(&dsi->dsi_host);

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c 
b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 0865d5d..3e2bd4d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1788,37 +1788,44 @@ static int fimc_probe(struct platform_device *pdev)

        if (!dev->of_node) {
                dev_err(dev, "device tree node not found.\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out;
        }

        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto out;
+       }

        ctx->ippdrv.dev = dev;

        ret = fimc_parse_dt(ctx);
        if (ret < 0)
-               return ret;
+               goto out;

        ctx->sysreg = syscon_regmap_lookup_by_phandle(dev->of_node,
                                                "samsung,sysreg");
        if (IS_ERR(ctx->sysreg)) {
                dev_err(dev, "syscon regmap lookup failed.\n");
-               return PTR_ERR(ctx->sysreg);
+               ret = PTR_ERR(ctx->sysreg);
+               goto out;
        }

        /* resource memory */
        ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
-       if (IS_ERR(ctx->regs))
-               return PTR_ERR(ctx->regs);
+       if (IS_ERR(ctx->regs)) {
+               ret = PTR_ERR(ctx->regs);
+               goto out;
+       }

        /* resource irq */
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "failed to request irq resource.\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto out;
        }

        ctx->irq = res->start;
@@ -1826,12 +1833,12 @@ static int fimc_probe(struct platform_device *pdev)
                IRQF_ONESHOT, "drm_fimc", ctx);
        if (ret < 0) {
                dev_err(dev, "failed to request irq.\n");
-               return ret;
+               goto out;
        }

        ret = fimc_setup_clocks(ctx);
        if (ret < 0)
-               return ret;
+               goto out;

        ippdrv = &ctx->ippdrv;
        ippdrv->ops[EXYNOS_DRM_OPS_SRC] = &fimc_src_ops;
@@ -1862,12 +1869,14 @@ static int fimc_probe(struct platform_device *pdev)

        dev_info(dev, "drm fimc registered successfully.\n");

-       return 0;
+       goto out;

 err_pm_dis:
        pm_runtime_disable(dev);
 err_put_clk:
        fimc_put_clocks(ctx);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);

        return ret;
 }
@@ -1878,6 +1887,7 @@ static int fimc_remove(struct platform_device *pdev)
        struct fimc_context *ctx = get_fimc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_ippdrv_unregister(ippdrv);
        mutex_destroy(&ctx->lock);

@@ -1955,4 +1965,3 @@ EXYNOS_DRM_DRV(fimc_driver) = {
                .pm     = &fimc_pm_ops,
        },
 };
-
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c 
b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index a0f5037..5217178 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -857,12 +857,16 @@ static int fimd_probe(struct platform_device *pdev)
        int win;
        int ret = -EINVAL;

-       if (!dev->of_node)
-               return -ENODEV;
+       if (!dev->of_node) {
+               ret = -ENODEV;
+               goto out;
+       }

        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto out;
+       }

        ctx->dev = dev;
        ctx->suspended = true;
@@ -875,32 +879,37 @@ 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);
+               ret = PTR_ERR(ctx->bus_clk);
+               goto out;
        }

        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);
+               ret = PTR_ERR(ctx->lcd_clk);
+               goto out;
        }

        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 out;
+       }

        res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "vsync");
        if (!res) {
                dev_err(dev, "irq request failed.\n");
-               return -ENXIO;
+               ret = -ENXIO;
+               goto out;
        }

        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 out;
        }

        ctx->driver_data = drm_fimd_get_driver_data(pdev);
@@ -919,13 +928,18 @@ static int fimd_probe(struct platform_device *pdev)
        for (win = 0; win < WINDOWS_NR; win++)
                fimd_clear_win(ctx, win);

-       return 0;
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
+
+       return ret;
 }

 static int fimd_remove(struct platform_device *pdev)
 {
        struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);

+       exynos_drm_dev_ready(pdev, false);
+
        exynos_dpi_remove(&pdev->dev);

        exynos_drm_manager_unregister(&fimd_manager);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c 
b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 2eb4676..f0203a3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1372,13 +1372,17 @@ static int g2d_probe(struct platform_device *pdev)
        int ret;

        g2d = devm_kzalloc(dev, sizeof(*g2d), GFP_KERNEL);
-       if (!g2d)
-               return -ENOMEM;
+       if (!g2d) {
+               ret = -ENOMEM;
+               goto out;
+       }

        g2d->runqueue_slab = kmem_cache_create("g2d_runqueue_slab",
                        sizeof(struct g2d_runqueue_node), 0, 0, NULL);
-       if (!g2d->runqueue_slab)
-               return -ENOMEM;
+       if (!g2d->runqueue_slab) {
+               ret = -ENOMEM;
+               goto out;
+       }

        g2d->dev = dev;

@@ -1455,6 +1459,8 @@ err_destroy_workqueue:
        destroy_workqueue(g2d->g2d_workq);
 err_destroy_slab:
        kmem_cache_destroy(g2d->runqueue_slab);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
        return ret;
 }

@@ -1463,6 +1469,7 @@ static int g2d_remove(struct platform_device *pdev)
        struct g2d_data *g2d = platform_get_drvdata(pdev);

        cancel_work_sync(&g2d->runqueue_work);
+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_subdrv_unregister(&g2d->subdrv);

        while (g2d->runqueue_node) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c 
b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 76b15fd..f0a7aca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1659,27 +1659,33 @@ static int gsc_probe(struct platform_device *pdev)
        int ret;

        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto out;
+       }

        /* clock control */
        ctx->gsc_clk = devm_clk_get(dev, "gscl");
        if (IS_ERR(ctx->gsc_clk)) {
                dev_err(dev, "failed to get gsc clock.\n");
-               return PTR_ERR(ctx->gsc_clk);
+               ret = PTR_ERR(ctx->gsc_clk);
+               goto out;
        }

        /* resource memory */
        ctx->regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        ctx->regs = devm_ioremap_resource(dev, ctx->regs_res);
-       if (IS_ERR(ctx->regs))
-               return PTR_ERR(ctx->regs);
+       if (IS_ERR(ctx->regs)) {
+               ret = PTR_ERR(ctx->regs);
+               goto out;
+       }

        /* resource irq */
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
                dev_err(dev, "failed to request irq resource.\n");
-               return -ENOENT;
+               ret = -ENOENT;
+               goto out;
        }

        ctx->irq = res->start;
@@ -1687,7 +1693,7 @@ static int gsc_probe(struct platform_device *pdev)
                IRQF_ONESHOT, "drm_gsc", ctx);
        if (ret < 0) {
                dev_err(dev, "failed to request irq.\n");
-               return ret;
+               goto out;
        }

        /* context initailization */
@@ -1704,7 +1710,7 @@ static int gsc_probe(struct platform_device *pdev)
        ret = gsc_init_prop_list(ippdrv);
        if (ret < 0) {
                dev_err(dev, "failed to init property list.\n");
-               return ret;
+               goto out;
        }

        DRM_DEBUG_KMS("id[%d]ippdrv[0x%x]\n", ctx->id, (int)ippdrv);
@@ -1723,10 +1729,12 @@ static int gsc_probe(struct platform_device *pdev)

        dev_info(dev, "drm gsc registered successfully.\n");

-       return 0;
+       goto out;

 err_ippdrv_register:
        pm_runtime_disable(dev);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
        return ret;
 }

@@ -1736,6 +1744,7 @@ static int gsc_remove(struct platform_device *pdev)
        struct gsc_context *ctx = get_gsc_context(dev);
        struct exynos_drm_ippdrv *ippdrv = &ctx->ippdrv;

+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_ippdrv_unregister(ippdrv);
        mutex_destroy(&ctx->lock);

@@ -1805,4 +1814,3 @@ EXYNOS_DRM_DRV(gsc_driver) = {
                .pm     = &gsc_pm_ops,
        },
 };
-
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c 
b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 1393486..c759a6e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -1840,8 +1840,10 @@ static int ipp_probe(struct platform_device *pdev)
        int ret;

        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto out;
+       }

        mutex_init(&ctx->ipp_lock);
        mutex_init(&ctx->prop_lock);
@@ -1858,7 +1860,8 @@ static int ipp_probe(struct platform_device *pdev)
        ctx->event_workq = create_singlethread_workqueue("ipp_event");
        if (!ctx->event_workq) {
                dev_err(dev, "failed to create event workqueue\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }

        /*
@@ -1893,12 +1896,13 @@ static int ipp_probe(struct platform_device *pdev)

        dev_info(dev, "drm ipp registered successfully.\n");

-       return 0;
-
+       goto out;
 err_cmd_workq:
        destroy_workqueue(ctx->cmd_workq);
 err_event_workq:
        destroy_workqueue(ctx->event_workq);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
        return ret;
 }

@@ -1907,6 +1911,7 @@ static int ipp_remove(struct platform_device *pdev)
        struct ipp_context *ctx = platform_get_drvdata(pdev);

        /* unregister sub driver */
+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_subdrv_unregister(&ctx->subdrv);

        /* remove,destroy ipp idr */
@@ -1982,4 +1987,3 @@ EXYNOS_DRM_DRV(ipp_driver) = {
                .pm     = &ipp_pm_ops,
        },
 };
-
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c 
b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index 625fd9b..59504d9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -707,17 +707,21 @@ static int rotator_probe(struct platform_device *pdev)

        if (!dev->of_node) {
                dev_err(dev, "cannot find of_node.\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out;
        }

        rot = devm_kzalloc(dev, sizeof(*rot), GFP_KERNEL);
-       if (!rot)
-               return -ENOMEM;
+       if (!rot) {
+               ret = -ENOMEM;
+               goto out;
+       }

        match = of_match_node(exynos_rotator_match, dev->of_node);
        if (!match) {
                dev_err(dev, "failed to match node\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto out;
        }
        rot->limit_tbl = (struct rot_limit_table *)match->data;

@@ -729,20 +733,22 @@ static int rotator_probe(struct platform_device *pdev)
        rot->irq = platform_get_irq(pdev, 0);
        if (rot->irq < 0) {
                dev_err(dev, "failed to get irq\n");
-               return rot->irq;
+               ret = rot->irq;
+               goto out;
        }

        ret = devm_request_threaded_irq(dev, rot->irq, NULL,
                        rotator_irq_handler, IRQF_ONESHOT, "drm_rotator", rot);
        if (ret < 0) {
                dev_err(dev, "failed to request irq\n");
-               return ret;
+               goto out;
        }

        rot->clock = devm_clk_get(dev, "rotator");
        if (IS_ERR(rot->clock)) {
                dev_err(dev, "failed to get clock\n");
-               return PTR_ERR(rot->clock);
+               ret = PTR_ERR(rot->clock);
+               goto out;
        }

        pm_runtime_enable(dev);
@@ -771,10 +777,12 @@ static int rotator_probe(struct platform_device *pdev)

        dev_info(dev, "The exynos rotator is probed successfully\n");

-       return 0;
+       goto out;

 err_ippdrv_register:
        pm_runtime_disable(dev);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
        return ret;
 }

@@ -784,6 +792,7 @@ static int rotator_remove(struct platform_device *pdev)
        struct rot_context *rot = dev_get_drvdata(dev);
        struct exynos_drm_ippdrv *ippdrv = &rot->ippdrv;

+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_ippdrv_unregister(ippdrv);

        pm_runtime_disable(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c 
b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 976a8fe..4e90a9d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -593,8 +593,10 @@ static int vidi_probe(struct platform_device *pdev)
        int ret;

        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
+       if (!ctx) {
+               ret = -ENOMEM;
+               goto out;
+       }

        ctx->default_win = 0;

@@ -607,20 +609,22 @@ static int vidi_probe(struct platform_device *pdev)

        platform_set_drvdata(pdev, &vidi_manager);

-       ret = device_create_file(dev, &dev_attr_connection);
-       if (ret < 0)
+       if (device_create_file(dev, &dev_attr_connection) < 0)
                DRM_INFO("failed to create connection sysfs.\n");

        exynos_drm_manager_register(&vidi_manager);
        exynos_drm_display_register(&vidi_display);
-
-       return 0;
+       ret = 0;
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
+       return ret;
 }

 static int vidi_remove(struct platform_device *pdev)
 {
        struct vidi_context *ctx = platform_get_drvdata(pdev);

+       exynos_drm_dev_ready(pdev, false);
        exynos_drm_display_unregister(&vidi_display);
        exynos_drm_manager_unregister(&vidi_manager);

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c 
b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3e659e9..2205469 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2058,24 +2058,32 @@ static int hdmi_probe(struct platform_device *pdev)
        struct hdmi_driver_data *drv_data;
        int ret;

-        if (!dev->of_node)
-               return -ENODEV;
+        if (!dev->of_node) {
+               ret = -ENODEV;
+               goto out;
+        }

        pdata = drm_hdmi_dt_parse_pdata(dev);
-       if (!pdata)
-               return -EINVAL;
+       if (!pdata) {
+               ret = -EINVAL;
+               goto out;
+       }

        hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
-       if (!hdata)
-               return -ENOMEM;
+       if (!hdata) {
+               ret = -ENOMEM;
+               goto out;
+       }

        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 out;
+       }

        drv_data = (struct hdmi_driver_data *)match->data;
        hdata->type = drv_data->type;
@@ -2086,35 +2094,41 @@ static int hdmi_probe(struct platform_device *pdev)
        ret = hdmi_resources_init(hdata);
        if (ret) {
                DRM_ERROR("hdmi_resources_init failed\n");
-               return -EINVAL;
+               goto out;
        }

        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 out;
+       }

        ret = devm_gpio_request(dev, hdata->hpd_gpio, "HPD");
        if (ret) {
                DRM_ERROR("failed to request HPD gpio\n");
-               return ret;
+               goto out;
        }

        /* DDC i2c driver */
        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 out;
        }
        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;
+               ret = -ENODEV;
+               goto out;
        }

        /* Not support APB PHY yet. */
-       if (drv_data->is_apb_phy)
-               return -EPERM;
+       if (drv_data->is_apb_phy) {
+               ret = -EPERM;
+               goto out;
+       }

        /* hdmiphy i2c driver */
        phy_node = of_parse_phandle(dev->of_node, "phy", 0);
@@ -2153,12 +2167,14 @@ static int hdmi_probe(struct platform_device *pdev)
        hdmi_display.ctx = hdata;
        exynos_drm_display_register(&hdmi_display);

-       return 0;
+       goto out;

 err_hdmiphy:
        put_device(&hdata->hdmiphy_port->dev);
 err_ddc:
        put_device(&hdata->ddc_adpt->dev);
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);
        return ret;
 }

@@ -2168,6 +2184,7 @@ static int hdmi_remove(struct platform_device *pdev)
        struct exynos_drm_display *display = get_hdmi_display(dev);
        struct hdmi_context *hdata = display->ctx;

+       exynos_drm_dev_ready(pdev, false);
        put_device(&hdata->hdmiphy_port->dev);
        put_device(&hdata->ddc_adpt->dev);
        pm_runtime_disable(&pdev->dev);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c 
b/drivers/gpu/drm/exynos/exynos_mixer.c
index b978bde..c17ccb2 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1205,13 +1205,14 @@ static int mixer_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct mixer_context *ctx;
        struct mixer_drv_data *drv;
+       int ret;

        dev_info(dev, "probe start\n");

        ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
        if (!ctx) {
-               DRM_ERROR("failed to alloc mixer context.\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto out;
        }

        mutex_init(&ctx->mixer_mutex);
@@ -1237,12 +1238,17 @@ static int mixer_probe(struct platform_device *pdev)
        exynos_drm_manager_register(&mixer_manager);

        pm_runtime_enable(dev);
+       ret = 0;
+out:
+       exynos_drm_dev_ready(pdev, ret != EPROBE_DEFER);

-       return 0;
+       return ret;
 }

 static int mixer_remove(struct platform_device *pdev)
 {
+       exynos_drm_dev_ready(pdev, false);
+
        dev_info(&pdev->dev, "remove successful\n");

        pm_runtime_disable(&pdev->dev);
-- 
1.8.3.2

Reply via email to