On 04/01/2014 02:37 PM, Inki Dae wrote:
> This patch adds super device support to bind sub drivers
> using device tree.
> 
> For this, you should add a super device node to each machine dt files
> like belows,
> 
> In case of using MIPI-DSI,
>       display-subsystem {
>               compatible = "samsung,exynos-display-subsystem";
>               ports = <&fimd>, <&dsi>;
>       };
> 
> In case of using DisplayPort,
>       display-subsystem {
>               compatible = "samsung,exynos-display-subsystem";
>               ports = <&fimd>, <&dp>;
>       };
> 
> In case of using Parallel panel,
>       display-subsystem {
>               compatible = "samsung,exynos-display-subsystem";
>               ports = <&fimd>;
>       };
> 
> And if you don't add connector device node to ports property,
> default parallel panel driver, exynos_drm_dpi module, will be used.
> 
> ports property can have the following device nodes,
>       fimd, mixer, Image Enhancer, MIPI-DSI, eDP, LVDS Bridge, or HDMI
> 
> With this patch, we can resolve the probing order issue without
> some global lists. So this patch also removes the unnecessary lists and
> stuff related to these lists.
> 

(...)

> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c 
> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 40fd6cc..7ebfe15 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"
> @@ -144,12 +146,14 @@ static inline struct fimd_driver_data 
> *drm_fimd_get_driver_data(
>  }
>  
>  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.
> @@ -803,8 +807,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,
> @@ -849,9 +851,10 @@ 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 resource *res;
>       int win;
> @@ -910,11 +913,16 @@ 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);
> +     /*
> +      * 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);
> @@ -922,18 +930,56 @@ 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;
> +
> +     fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
>  
> -     exynos_dpi_remove(&pdev->dev);
> +     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;
> +     }

Wouldn't be better to leave it in exynos_dpi_probe? It should be called
in fimd_probe. It can return ERR_PTR(-EPROBE_DEFER) if the panel is
missing, NULL if there are no parallel bindings otherwise it will return
&exynos_dpi_display. fimd_bind will run exynos_drm_create_enc_conn on
returned pointer. In this case
in fimd_unbind connector and encoder should be removed and in
fimd_remove, exynos_dpi_remove should be conditionally called.

Regards
Andrzej

> +
> +     pm_runtime_enable(&pdev->dev);
> +
> +     return component_add(&pdev->dev, &fimd_component_ops);
> +}
> +
> +static int fimd_remove(struct platform_device *pdev)
> +{
>       pm_runtime_disable(&pdev->dev);
>  
> +     component_del(&pdev->dev, &fimd_component_ops);
>       return 0;
>  }
>  

Reply via email to