diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_fimd.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 83 |
1 files changed, 68 insertions, 15 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 99ae79e09e82..d1a282c3b062 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -19,10 +19,12 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/pm_runtime.h> +#include <linux/component.h> #include <video/of_display_timing.h> #include <video/of_videomode.h> #include <video/samsung_fimd.h> +#include <drm/drm_panel.h> #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" @@ -186,12 +188,14 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr) } static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, - struct drm_device *drm_dev, int pipe) + struct drm_device *drm_dev) { struct fimd_context *ctx = mgr->ctx; + struct exynos_drm_private *priv; + priv = drm_dev->dev_private; - ctx->drm_dev = drm_dev; - ctx->pipe = pipe; + mgr->drm_dev = ctx->drm_dev = drm_dev; + mgr->pipe = ctx->pipe = priv->pipe++; /* * enable drm irq mode. @@ -832,8 +836,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) } static struct exynos_drm_manager_ops fimd_manager_ops = { - .initialize = fimd_mgr_initialize, - .remove = fimd_mgr_remove, .dpms = fimd_dpms, .mode_fixup = fimd_mode_fixup, .mode_set = fimd_mode_set, @@ -878,10 +880,12 @@ out: return IRQ_HANDLED; } -static int fimd_probe(struct platform_device *pdev) +static int fimd_bind(struct device *dev, struct device *master, void *data) { - struct device *dev = &pdev->dev; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm_dev = data; struct fimd_context *ctx; + struct device_node *dn; struct resource *res; int win; int ret = -EINVAL; @@ -939,11 +943,19 @@ static int fimd_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &fimd_manager); fimd_manager.ctx = ctx; - exynos_drm_manager_register(&fimd_manager); + fimd_mgr_initialize(&fimd_manager, drm_dev); - exynos_dpi_probe(ctx->dev); + exynos_drm_crtc_create(&fimd_manager); - pm_runtime_enable(dev); + dn = exynos_dpi_of_find_panel_node(&pdev->dev); + if (dn) { + /* + * It should be called after exynos_drm_crtc_create call + * because exynos_dpi_probe call will try to find same lcd + * type of manager to setup possible_crtcs. + */ + exynos_dpi_probe(drm_dev, dev); + } for (win = 0; win < WINDOWS_NR; win++) fimd_clear_win(ctx, win); @@ -951,18 +963,59 @@ static int fimd_probe(struct platform_device *pdev) return 0; } -static int fimd_remove(struct platform_device *pdev) +static void fimd_unbind(struct device *dev, struct device *master, + void *data) { - struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); + struct exynos_drm_manager *mgr = dev_get_drvdata(dev); + struct drm_crtc *crtc = mgr->crtc; + struct device_node *dn; + + fimd_dpms(mgr, DRM_MODE_DPMS_OFF); - exynos_dpi_remove(&pdev->dev); + dn = exynos_dpi_of_find_panel_node(dev); + if (dn) + exynos_dpi_remove(mgr->drm_dev, dev); - exynos_drm_manager_unregister(&fimd_manager); + fimd_mgr_remove(mgr); - fimd_dpms(mgr, DRM_MODE_DPMS_OFF); + crtc->funcs->destroy(crtc); +} + +static const struct component_ops fimd_component_ops = { + .bind = fimd_bind, + .unbind = fimd_unbind, +}; + +static int fimd_probe(struct platform_device *pdev) +{ + struct device_node *dn; + + /* Check if fimd node has port node. */ + dn = exynos_dpi_of_find_panel_node(&pdev->dev); + if (dn) { + struct drm_panel *panel; + + /* + * Do not bind if there is the port node but a drm_panel + * isn't added to panel_list yet. + * In this case, fimd_probe will be called by defered probe + * again after the drm_panel is added to panel_list. + */ + panel = of_drm_find_panel(dn); + if (!panel) + return -EPROBE_DEFER; + } + + pm_runtime_enable(&pdev->dev); + + return exynos_drm_component_add(&pdev->dev, &fimd_component_ops); +} +static int fimd_remove(struct platform_device *pdev) +{ pm_runtime_disable(&pdev->dev); + exynos_drm_component_del(&pdev->dev, &fimd_component_ops); return 0; } |