All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] drm/exynos: more cleanup with super device support
@ 2014-04-01 12:37 Inki Dae
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
                   ` (7 more replies)
  0 siblings, 8 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:37 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

This patch series cleans up exynos drm framework and kms sub drivers
using the component framework[1].

And this patch series had been posted for RFC[2].

Thanks,
Inki Dae

[1] http://lists.freedesktop.org/archives/dri-devel/2014-January/051249.html
[2] http://comments.gmane.org/gmane.comp.video.dri.devel/101200


Inki Dae (7):
  drm/exynos: add super device support
  drm/exynos: dpi: fix hotplug fail issue
  drm/exynos: register platform driver at each kms sub drivers
  ARM: dts: exynos4210-universal: add super device node for exynos drm
  ARM: dts: exynos4210-trats: add super device node for exynos drm
  ARM: dts: exynos4412-trats2: add super device node for exynos drm
  exynos/drm: add DT bindings

 .../bindings/drm/exynos/samsung-exynos-drm.txt     |   32 +++
 arch/arm/boot/dts/exynos4210-trats.dts             |    5 +
 arch/arm/boot/dts/exynos4210-universal_c210.dts    |    5 +
 arch/arm/boot/dts/exynos4412-trats2.dts            |    5 +
 drivers/gpu/drm/exynos/exynos_dp_core.c            |   46 ++--
 drivers/gpu/drm/exynos/exynos_drm_core.c           |  216 +++--------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c           |   17 ++
 drivers/gpu/drm/exynos/exynos_drm_crtc.h           |    4 +
 drivers/gpu/drm/exynos/exynos_drm_dpi.c            |   21 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c            |  256 ++++++++------------
 drivers/gpu/drm/exynos/exynos_drm_drv.h            |   79 +++---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c            |   39 ++-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c           |   77 ++++--
 drivers/gpu/drm/exynos/exynos_drm_vidi.c           |   61 +++--
 drivers/gpu/drm/exynos/exynos_hdmi.c               |   46 ++--
 drivers/gpu/drm/exynos/exynos_mixer.c              |   55 ++++-
 16 files changed, 490 insertions(+), 474 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
@ 2014-04-01 12:37 ` Inki Dae
  2014-04-02 14:06   ` Andrzej Hajda
                     ` (2 more replies)
  2014-04-01 12:37 ` [PATCH 2/7] drm/exynos: dpi: fix hotplug fail issue Inki Dae
                   ` (6 subsequent siblings)
  7 siblings, 3 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:37 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

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.

Previous RFC patch,
	 http://www.spinics.net/lists/dri-devel/msg54671.html

Changelog since RFC patch:
- Register sub drivers and probe them at load(). In case of non sub
  drivers, sub driver probe is needed.
- Enable runtime pm at fimd_probe() instead of fimd_bind(). runtime pm
  should be enabled before iommu device is attached to fimd device.
- Do not return an error with component_master_add fail.
- Remove super device support from mipi dsi driver which was in RFC.
- Add super device support to parallel driver.

Changelog v2:
- Add super device support to mipi dsi driver.
- Bind fimd driver only in case that a drm_panel for parallel panel driver
  is added to panel_list of drm_panel module.
- Change super node name to 'display-subsystem'
  . 'exynos-drm' is specific to Linux so change it to generic name.
- Change propery name of super node to 'ports'
  . crtcs and connectors propery names are also specific to Linux so
    change them to generic name.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c  |   45 ++++---
 drivers/gpu/drm/exynos/exynos_drm_core.c |  216 +++++-------------------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c |   17 +++
 drivers/gpu/drm/exynos/exynos_drm_crtc.h |    4 +
 drivers/gpu/drm/exynos/exynos_drm_dpi.c  |   16 ++-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  202 +++++++++++++++-------------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |   73 +++++-----
 drivers/gpu/drm/exynos/exynos_drm_dsi.c  |   38 +++++-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |   76 ++++++++---
 drivers/gpu/drm/exynos/exynos_drm_vidi.c |   61 +++++++--
 drivers/gpu/drm/exynos/exynos_hdmi.c     |   45 ++++---
 drivers/gpu/drm/exynos/exynos_mixer.c    |   54 ++++++--
 12 files changed, 442 insertions(+), 405 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index a59bca9..cb9aa58 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <linux/component.h>
 #include <linux/phy/phy.h>
 #include <video/of_display_timing.h>
 #include <video/of_videomode.h>
@@ -969,16 +970,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static int exynos_dp_initialize(struct exynos_drm_display *display,
-				struct drm_device *drm_dev)
-{
-	struct exynos_dp_device *dp = display->ctx;
-
-	dp->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static bool find_bridge(const char *compat, struct bridge_init *bridge)
 {
 	bridge->client = NULL;
@@ -1106,7 +1097,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops exynos_dp_display_ops = {
-	.initialize = exynos_dp_initialize,
 	.create_connector = exynos_dp_create_connector,
 	.dpms = exynos_dp_dpms,
 };
@@ -1230,8 +1220,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 	return 0;
 }
 
-static int exynos_dp_probe(struct platform_device *pdev)
+static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct resource *res;
 	struct exynos_dp_device *dp;
 
@@ -1293,21 +1285,40 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	}
 	disable_irq(dp->irq);
 
+	dp->drm_dev = drm_dev;
 	exynos_dp_display.ctx = dp;
 
 	platform_set_drvdata(pdev, &exynos_dp_display);
-	exynos_drm_display_register(&exynos_dp_display);
 
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
 }
 
-static int exynos_dp_remove(struct platform_device *pdev)
+static void exynos_dp_unbind(struct device *dev, struct device *master,
+				void *data)
 {
-	struct exynos_drm_display *display = platform_get_drvdata(pdev);
+	struct exynos_drm_display *display = dev_get_drvdata(dev);
+	struct exynos_dp_device *dp = display->ctx;
+	struct drm_encoder *encoder = dp->encoder;
 
 	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dp_display);
 
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dp->connector);
+}
+
+static const struct component_ops exynos_dp_ops = {
+	.bind	= exynos_dp_bind,
+	.unbind	= exynos_dp_unbind,
+};
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &exynos_dp_ops);
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &exynos_dp_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 0e9e06c..4c9f972 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -19,21 +19,19 @@
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
-static LIST_HEAD(exynos_drm_manager_list);
-static LIST_HEAD(exynos_drm_display_list);
 
-static int exynos_drm_create_enc_conn(struct drm_device *dev,
+int exynos_drm_create_enc_conn(struct drm_device *dev,
 					struct exynos_drm_display *display)
 {
 	struct drm_encoder *encoder;
-	struct exynos_drm_manager *manager;
 	int ret;
 	unsigned long possible_crtcs = 0;
 
-	/* Find possible crtcs for this display */
-	list_for_each_entry(manager, &exynos_drm_manager_list, list)
-		if (manager->type == display->type)
-			possible_crtcs |= 1 << manager->pipe;
+	ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
+	if (ret < 0)
+		return ret;
+
+	possible_crtcs |= 1 << ret;
 
 	/* create and initialize a encoder for this sub driver. */
 	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
@@ -57,127 +55,29 @@ err_destroy_encoder:
 	return ret;
 }
 
-static int exynos_drm_subdrv_probe(struct drm_device *dev,
-					struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->probe) {
-		int ret;
-
-		subdrv->drm_dev = dev;
-
-		/*
-		 * this probe callback would be called by sub driver
-		 * after setting of all resources to this sub driver,
-		 * such as clock, irq and register map are done or by load()
-		 * of exynos drm driver.
-		 *
-		 * P.S. note that this driver is considered for modularization.
-		 */
-		ret = subdrv->probe(dev, subdrv->dev);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void exynos_drm_subdrv_remove(struct drm_device *dev,
-				      struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->remove)
-		subdrv->remove(dev, subdrv->dev);
-}
-
-int exynos_drm_initialize_managers(struct drm_device *dev)
+int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_manager *manager, *n;
-	int ret, pipe = 0;
-
-	list_for_each_entry(manager, &exynos_drm_manager_list, list) {
-		if (manager->ops->initialize) {
-			ret = manager->ops->initialize(manager, dev, pipe);
-			if (ret) {
-				DRM_ERROR("Mgr init [%d] failed with %d\n",
-						manager->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		manager->drm_dev = dev;
-		manager->pipe = pipe++;
+	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
 
-		ret = exynos_drm_crtc_create(manager);
-		if (ret) {
-			DRM_ERROR("CRTC create [%d] failed with %d\n",
-					manager->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
-		if (pipe-- > 0)
-			exynos_drm_manager_unregister(manager);
-		else
-			list_del(&manager->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_managers(struct drm_device *dev)
-{
-	struct exynos_drm_manager *manager, *n;
-
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
-		exynos_drm_manager_unregister(manager);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
 
-int exynos_drm_initialize_displays(struct drm_device *dev)
+int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_display *display, *n;
-	int ret, initialized = 0;
-
-	list_for_each_entry(display, &exynos_drm_display_list, list) {
-		if (display->ops->initialize) {
-			ret = display->ops->initialize(display, dev);
-			if (ret) {
-				DRM_ERROR("Display init [%d] failed with %d\n",
-						display->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		initialized++;
+	list_del(&subdrv->list);
 
-		ret = exynos_drm_create_enc_conn(dev, display);
-		if (ret) {
-			DRM_ERROR("Encoder create [%d] failed with %d\n",
-					display->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
-		if (initialized-- > 0)
-			exynos_drm_display_unregister(display);
-		else
-			list_del(&display->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_displays(struct drm_device *dev)
-{
-	struct exynos_drm_display *display, *n;
-
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
-		exynos_drm_display_unregister(display);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
 
-int exynos_drm_device_register(struct drm_device *dev)
+int exynos_drm_device_subdrv_probe(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv, *n;
 	int err;
@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev)
 		return -EINVAL;
 
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
-		err = exynos_drm_subdrv_probe(dev, subdrv);
-		if (err) {
-			DRM_DEBUG("exynos drm subdrv probe failed.\n");
-			list_del(&subdrv->list);
-			continue;
+		if (subdrv->probe) {
+			subdrv->drm_dev = dev;
+
+			/*
+			 * this probe callback would be called by sub driver
+			 * after setting of all resources to this sub driver,
+			 * such as clock, irq and register map are done.
+			 */
+			err = subdrv->probe(dev, subdrv->dev);
+			if (err) {
+				DRM_DEBUG("exynos drm subdrv probe failed.\n");
+				list_del(&subdrv->list);
+				continue;
+			}
 		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_register);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
 
-int exynos_drm_device_unregister(struct drm_device *dev)
+int exynos_drm_device_subdrv_remove(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv;
 
@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 	}
 
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		exynos_drm_subdrv_remove(dev, subdrv);
+		if (subdrv->remove)
+			subdrv->remove(dev, subdrv->dev);
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager)
-{
-	BUG_ON(!manager->ops);
-	list_add_tail(&manager->list, &exynos_drm_manager_list);
-	return 0;
-}
-
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
-{
-	if (manager->ops->remove)
-		manager->ops->remove(manager);
-
-	list_del(&manager->list);
-	return 0;
-}
-
-int exynos_drm_display_register(struct exynos_drm_display *display)
-{
-	BUG_ON(!display->ops);
-	list_add_tail(&display->list, &exynos_drm_display_list);
-	return 0;
-}
-
-int exynos_drm_display_unregister(struct exynos_drm_display *display)
-{
-	if (display->ops->remove)
-		display->ops->remove(display);
-
-	list_del(&display->list);
-	return 0;
-}
-
-int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
-
-int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_del(&subdrv->list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
 
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
 {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 9cc92ae..c197b99 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -367,6 +367,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 		return -ENOMEM;
 	}
 
+	manager->crtc = &exynos_crtc->drm_crtc;
 	crtc = &exynos_crtc->drm_crtc;
 
 	private->crtc[manager->pipe] = crtc;
@@ -490,3 +491,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
 			manager->ops->wait_for_vblank(manager);
 	}
 }
+
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
+		struct exynos_drm_crtc *exynos_crtc;
+
+		exynos_crtc = to_exynos_crtc(crtc);
+		if (exynos_crtc->manager->type == out_type)
+			return exynos_crtc->manager->pipe;
+	}
+
+	return -EPERM;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index c27b66c..9f74b10 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
 
+/* This function gets pipe value to crtc device matched with out_type. */
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type);
+
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 2b09c7c..c1f4b35 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -255,7 +255,7 @@ enum {
 	FIMD_PORT_WRB,
 };
 
-static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
 {
 	struct device_node *np, *ep;
 
@@ -308,7 +308,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 	return 0;
 }
 
-int exynos_dpi_probe(struct device *dev)
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
 {
 	struct exynos_dpi *ctx;
 	int ret;
@@ -325,15 +325,17 @@ int exynos_dpi_probe(struct device *dev)
 	if (ret < 0)
 		return ret;
 
-	exynos_drm_display_register(&exynos_dpi_display);
-
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
 }
 
-int exynos_dpi_remove(struct device *dev)
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
 {
+	struct drm_encoder *encoder = exynos_dpi_display.encoder;
+	struct exynos_dpi *ctx = exynos_dpi_display.ctx;
+
 	exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dpi_display);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2d27ba2..f065385 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -16,6 +16,7 @@
 #include <drm/drm_crtc_helper.h>
 
 #include <linux/anon_inodes.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -40,9 +41,6 @@
 
 #define VBLANK_OFF_DELAY	50000
 
-/* platform device pointer for eynos drm device. */
-static struct platform_device *exynos_drm_pdev;
-
 static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
 	struct exynos_drm_private *private;
@@ -73,38 +71,21 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	exynos_drm_mode_config_init(dev);
 
-	ret = exynos_drm_initialize_managers(dev);
-	if (ret)
-		goto err_mode_config_cleanup;
-
 	for (nr = 0; nr < MAX_PLANE; nr++) {
 		struct drm_plane *plane;
 		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
 		plane = exynos_plane_init(dev, possible_crtcs, false);
 		if (!plane)
-			goto err_manager_cleanup;
+			goto err_mode_config_cleanup;
 	}
 
-	ret = exynos_drm_initialize_displays(dev);
-	if (ret)
-		goto err_manager_cleanup;
-
 	/* init kms poll for handling hpd */
 	drm_kms_helper_poll_init(dev);
 
 	ret = drm_vblank_init(dev, MAX_CRTC);
 	if (ret)
-		goto err_display_cleanup;
-
-	/*
-	 * probe sub drivers such as display controller and hdmi driver,
-	 * that were registered at probe() of platform driver
-	 * to the sub driver and create encoder and connector for them.
-	 */
-	ret = exynos_drm_device_register(dev);
-	if (ret)
-		goto err_vblank;
+		goto err_mode_config_cleanup;
 
 	/* setup possible_clones. */
 	exynos_drm_encoder_setup(dev);
@@ -113,17 +94,35 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	platform_set_drvdata(dev->platformdev, dev);
 
+	/* Try to bind all sub drivers. */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto err_cleanup_vblank;
+
+	/* Probe non kms sub drivers. */
+	ret = exynos_drm_device_subdrv_probe(dev);
+	if (ret)
+		goto err_unbind_all;
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	ret = exynos_drm_probe_vidi(dev);
+	if (ret < 0)
+		goto err_remove_subdrv;
+#endif
+
 	/* force connectors detection */
 	drm_helper_hpd_irq_event(dev);
 
 	return 0;
 
-err_vblank:
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+err_remove_subdrv:
+	exynos_drm_device_subdrv_remove(dev);
+#endif
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
+err_cleanup_vblank:
 	drm_vblank_cleanup(dev);
-err_display_cleanup:
-	exynos_drm_remove_displays(dev);
-err_manager_cleanup:
-	exynos_drm_remove_managers(dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	drm_release_iommu_mapping(dev);
@@ -135,17 +134,17 @@ err_free_private:
 
 static int exynos_drm_unload(struct drm_device *dev)
 {
+	exynos_drm_device_subdrv_remove(dev);
+
 	exynos_drm_fbdev_fini(dev);
-	exynos_drm_device_unregister(dev);
 	drm_vblank_cleanup(dev);
 	drm_kms_helper_poll_fini(dev);
-	exynos_drm_remove_displays(dev);
-	exynos_drm_remove_managers(dev);
 	drm_mode_config_cleanup(dev);
 
 	drm_release_iommu_mapping(dev);
 	kfree(dev->dev_private);
 
+	component_unbind_all(dev->dev, dev);
 	dev->dev_private = NULL;
 
 	return 0;
@@ -355,27 +354,6 @@ static struct drm_driver exynos_drm_driver = {
 	.minor	= DRIVER_MINOR,
 };
 
-static int exynos_drm_platform_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	return drm_platform_init(&exynos_drm_driver, pdev);
-}
-
-static int exynos_drm_platform_remove(struct platform_device *pdev)
-{
-	drm_put_dev(platform_get_drvdata(pdev));
-
-	return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int exynos_drm_sys_suspend(struct device *dev)
 {
@@ -430,20 +408,66 @@ static const struct dev_pm_ops exynos_drm_pm_ops = {
 			exynos_drm_runtime_resume, NULL)
 };
 
-static struct platform_driver exynos_drm_platform_driver = {
-	.probe		= exynos_drm_platform_probe,
-	.remove		= exynos_drm_platform_remove,
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "exynos-drm",
-		.pm	= &exynos_drm_pm_ops,
-	},
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int exynos_drm_add_components(struct device *dev, struct master *m)
+{
+	struct device_node *np = dev->of_node;
+	unsigned int i;
+
+	for (i = 0;; i++) {
+		struct device_node *node;
+		int ret;
+
+		node = of_parse_phandle(np, "ports", i);
+		if (!node)
+			break;
+
+		ret = component_master_add_child(m, compare_of, node);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_drm_bind(struct device *dev)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
+}
+
+static void exynos_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops exynos_drm_ops = {
+	.add_components = exynos_drm_add_components,
+	.bind		= exynos_drm_bind,
+	.unbind		= exynos_drm_unbind,
 };
 
-static int __init exynos_drm_init(void)
+static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
 	int ret;
 
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
+
 #ifdef CONFIG_DRM_EXYNOS_DP
 	ret = platform_driver_register(&dp_driver);
 	if (ret < 0)
@@ -471,12 +495,6 @@ static int __init exynos_drm_init(void)
 		goto out_mixer;
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	ret = platform_driver_register(&vidi_driver);
-	if (ret < 0)
-		goto out_vidi;
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_G2D
 	ret = platform_driver_register(&g2d_driver);
 	if (ret < 0)
@@ -511,23 +529,12 @@ static int __init exynos_drm_init(void)
 		goto out_ipp_dev;
 #endif
 
-	ret = platform_driver_register(&exynos_drm_platform_driver);
+	ret = component_master_add(&pdev->dev, &exynos_drm_ops);
 	if (ret < 0)
-		goto out_drm;
-
-	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
-				NULL, 0);
-	if (IS_ERR(exynos_drm_pdev)) {
-		ret = PTR_ERR(exynos_drm_pdev);
-		goto out;
-	}
+		DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
 
 	return 0;
 
-out:
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
-out_drm:
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 out_ipp_dev:
@@ -555,11 +562,6 @@ out_fimc:
 out_g2d:
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-out_vidi:
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&mixer_driver);
 out_mixer:
@@ -584,12 +586,8 @@ out_dp:
 	return ret;
 }
 
-static void __exit exynos_drm_exit(void)
+static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(exynos_drm_pdev);
-
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 	platform_driver_unregister(&ipp_driver);
@@ -616,10 +614,6 @@ static void __exit exynos_drm_exit(void)
 	platform_driver_unregister(&hdmi_driver);
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	platform_driver_unregister(&fimd_driver);
 #endif
@@ -631,10 +625,28 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_DP
 	platform_driver_unregister(&dp_driver);
 #endif
+	component_master_del(&pdev->dev, &exynos_drm_ops);
+	return 0;
 }
 
-module_init(exynos_drm_init);
-module_exit(exynos_drm_exit);
+static const struct of_device_id exynos_drm_dt_match[] = {
+	{ .compatible = "samsung,exynos-display-subsystem", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, exynos_drm_dt_match);
+
+static struct platform_driver exynos_drm_platform_driver = {
+	.probe	= exynos_drm_platform_probe,
+	.remove	= exynos_drm_platform_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "exynos-drm",
+		.pm	= &exynos_drm_pm_ops,
+		.of_match_table	= exynos_drm_dt_match,
+	},
+};
+module_platform_driver(exynos_drm_platform_driver);
 
 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 4c5cf68..25d562f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -122,7 +122,6 @@ struct exynos_drm_overlay {
  * Exynos DRM Display Structure.
  *	- this structure is common to analog tv, digital tv and lcd panel.
  *
- * @initialize: initializes the display with drm_dev
  * @remove: cleans up the display for removal
  * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
@@ -133,8 +132,6 @@ struct exynos_drm_overlay {
  */
 struct exynos_drm_display;
 struct exynos_drm_display_ops {
-	int (*initialize)(struct exynos_drm_display *display,
-				struct drm_device *drm_dev);
 	int (*create_connector)(struct exynos_drm_display *display,
 				struct drm_encoder *encoder);
 	void (*remove)(struct exynos_drm_display *display);
@@ -172,8 +169,6 @@ struct exynos_drm_display {
 /*
  * Exynos drm manager ops
  *
- * @initialize: initializes the manager with drm_dev
- * @remove: cleans up the manager for removal
  * @dpms: control device power.
  * @mode_fixup: fix mode data before applying it
  * @mode_set: set the given mode to the manager
@@ -189,9 +184,6 @@ struct exynos_drm_display {
  */
 struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
-	int (*initialize)(struct exynos_drm_manager *mgr,
-				struct drm_device *drm_dev, int pipe);
-	void (*remove)(struct exynos_drm_manager *mgr);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
 	bool (*mode_fixup)(struct exynos_drm_manager *mgr,
 				const struct drm_display_mode *mode,
@@ -215,6 +207,7 @@ struct exynos_drm_manager_ops {
  * @list: the list entry for this manager
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @drm_dev: pointer to the drm device
+ * @crtc: crtc object.
  * @pipe: the pipe number for this crtc/manager
  * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the manager's implementation specific context
@@ -223,6 +216,7 @@ struct exynos_drm_manager {
 	struct list_head list;
 	enum exynos_drm_output_type type;
 	struct drm_device *drm_dev;
+	struct drm_crtc *crtc;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
 	void *ctx;
@@ -255,6 +249,7 @@ struct drm_exynos_file_private {
  * @da_space_size: size of device address space.
  *	if 0 then default value is used for it.
  * @da_space_order: order to device address space.
+ * @pipe: the pipe number for this crtc/manager.
  */
 struct exynos_drm_private {
 	struct drm_fb_helper *fb_helper;
@@ -273,6 +268,8 @@ struct exynos_drm_private {
 	unsigned long da_start;
 	unsigned long da_space_size;
 	unsigned long da_space_order;
+
+	unsigned int pipe;
 };
 
 /*
@@ -283,11 +280,11 @@ struct exynos_drm_private {
  * @drm_dev: pointer to drm_device and this pointer would be set
  *	when sub driver calls exynos_drm_subdrv_register().
  * @manager: subdrv has its own manager to control a hardware appropriately
- *	and we can access a hardware drawing on this manager.
+ *     and we can access a hardware drawing on this manager.
  * @probe: this callback would be called by exynos drm driver after
- *	subdrv is registered to it.
+ *     subdrv is registered to it.
  * @remove: this callback is used to release resources created
- *	by probe callback.
+ *     by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
  */
@@ -304,39 +301,14 @@ struct exynos_drm_subdrv {
 			struct drm_file *file);
 };
 
-/*
- * this function calls a probe callback registered to sub driver list and
- * create its own encoder and connector and then set drm_device object
- * to global one.
- */
-int exynos_drm_device_register(struct drm_device *dev);
-/*
- * this function calls a remove callback registered to sub driver list and
- * destroy its own encoder and connetor.
- */
-int exynos_drm_device_unregister(struct drm_device *dev);
-
-int exynos_drm_initialize_managers(struct drm_device *dev);
-void exynos_drm_remove_managers(struct drm_device *dev);
-int exynos_drm_initialize_displays(struct drm_device *dev);
-void exynos_drm_remove_displays(struct drm_device *dev);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager);
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
-int exynos_drm_display_register(struct exynos_drm_display *display);
-int exynos_drm_display_unregister(struct exynos_drm_display *display);
-
-/*
- * this function would be called by sub drivers such as display controller
- * or hdmi driver to register this sub driver object to exynos drm driver
- * and when a sub driver is registered to exynos drm driver a probe callback
- * of the sub driver is called and creates its own encoder and connector.
- */
+ /* This function would be called by non kms drivers such as g2d and ipp. */
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 
 /* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+int exynos_drm_device_subdrv_probe(struct drm_device *dev);
+int exynos_drm_device_subdrv_remove(struct drm_device *dev);
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
 
@@ -362,13 +334,28 @@ int exynos_platform_device_ipp_register(void);
 void exynos_platform_device_ipp_unregister(void);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
-int exynos_dpi_probe(struct device *dev);
-int exynos_dpi_remove(struct device *dev);
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
 #else
-static inline int exynos_dpi_probe(struct device *dev) { return 0; }
-static inline int exynos_dpi_remove(struct device *dev) { return 0; }
+static inline int exynos_dpi_probe(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline struct device_node
+			*exynos_dpi_of_find_panel_node(struct device *dev)
+{ return NULL; }
 #endif
 
+/*
+ * this function registers exynos drm vidi platform device.
+ */
+int exynos_drm_probe_vidi(struct drm_device *dev);
+
+/* This function creates a encoder and a connector, and initializes them. */
+int exynos_drm_create_enc_conn(struct drm_device *dev,
+				struct exynos_drm_display *display);
+
 extern struct platform_driver dp_driver;
 extern struct platform_driver dsi_driver;
 extern struct platform_driver fimd_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 697228e..8f48f52 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
+#include <linux/component.h>
 
 #include <video/mipi_display.h>
 #include <video/videomode.h>
@@ -1378,8 +1379,11 @@ end:
 	return ret;
 }
 
-static int exynos_dsi_probe(struct platform_device *pdev)
+static int exynos_dsi_bind(struct device *dev, struct device *master,
+				void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct resource *res;
 	struct exynos_dsi *dsi;
 	int ret;
@@ -1454,22 +1458,30 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 	exynos_dsi_display.ctx = dsi;
 
+	ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
+	if (ret) {
+		DRM_ERROR("Encoder create [%d] failed with %d\n",
+				exynos_dsi_display.type, ret);
+		return ret;
+	}
+
 	platform_set_drvdata(pdev, &exynos_dsi_display);
-	exynos_drm_display_register(&exynos_dsi_display);
 
 	return mipi_dsi_host_register(&dsi->dsi_host);
 }
 
-static int exynos_dsi_remove(struct platform_device *pdev)
+static void exynos_dsi_unbind(struct device *dev, struct device *master,
+				void *data)
 {
 	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+	struct drm_encoder *encoder = dsi->encoder;
 
 	exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
 
-	exynos_drm_display_unregister(&exynos_dsi_display);
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 
-	return 0;
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dsi->connector);
 }
 
 #if CONFIG_PM_SLEEP
@@ -1502,6 +1514,22 @@ static const struct dev_pm_ops exynos_dsi_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
 };
 
+static const struct component_ops exynos_dsi_component_ops = {
+	.bind	= exynos_dsi_bind,
+	.unbind	= exynos_dsi_unbind,
+};
+
+static int exynos_dsi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &exynos_dsi_component_ops);
+}
+
+static int exynos_dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &exynos_dsi_component_ops);
+	return 0;
+}
+
 static struct of_device_id exynos_dsi_of_match[] = {
 	{ .compatible = "samsung,exynos4210-mipi-dsi" },
 	{ }
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;
+	}
+
+	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;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 7afead9..22076e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -65,6 +65,8 @@ struct vidi_context {
 	int				pipe;
 };
 
+static struct drm_device *drm_dev;
+
 static const char fake_edid_info[] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
 	0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
@@ -294,14 +296,15 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 }
 
 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	struct vidi_context *ctx = mgr->ctx;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
 
-	DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
+	DRM_DEBUG_KMS("vidi initialize ctx=%p dev=%p\n", ctx, drm_dev);
 
-	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.
@@ -324,7 +327,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
 }
 
 static struct exynos_drm_manager_ops vidi_manager_ops = {
-	.initialize = vidi_mgr_initialize,
 	.dpms = vidi_dpms,
 	.commit = vidi_commit,
 	.enable_vblank = vidi_enable_vblank,
@@ -588,11 +590,14 @@ static struct exynos_drm_display vidi_display = {
 
 static int vidi_probe(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
 	struct vidi_context *ctx;
 	int ret;
 
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	/* drm_dev shouldn't be NULL. */
+	if (!drm_dev)
+		return -EFAULT;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -603,32 +608,40 @@ static int vidi_probe(struct platform_device *pdev)
 	vidi_manager.ctx = ctx;
 	vidi_display.ctx = ctx;
 
+	vidi_mgr_initialize(&vidi_manager, drm_dev);
+
 	mutex_init(&ctx->lock);
 
 	platform_set_drvdata(pdev, &vidi_manager);
 
-	ret = device_create_file(dev, &dev_attr_connection);
+	ret = device_create_file(&pdev->dev, &dev_attr_connection);
 	if (ret < 0)
 		DRM_INFO("failed to create connection sysfs.\n");
 
-	exynos_drm_manager_register(&vidi_manager);
-	exynos_drm_display_register(&vidi_display);
+	exynos_drm_crtc_create(&vidi_manager);
+	exynos_drm_create_enc_conn(drm_dev, &vidi_display);
 
 	return 0;
 }
 
 static int vidi_remove(struct platform_device *pdev)
 {
-	struct vidi_context *ctx = platform_get_drvdata(pdev);
-
-	exynos_drm_display_unregister(&vidi_display);
-	exynos_drm_manager_unregister(&vidi_manager);
+	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
+	struct vidi_context *ctx = mgr->ctx;
+	struct drm_encoder *encoder = ctx->encoder;
+	struct drm_crtc *crtc = mgr->crtc;
 
 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 		kfree(ctx->raw_edid);
 		ctx->raw_edid = NULL;
+
+		return -EINVAL;
 	}
 
+	crtc->funcs->destroy(crtc);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
+
 	return 0;
 }
 
@@ -640,3 +653,23 @@ struct platform_driver vidi_driver = {
 		.owner	= THIS_MODULE,
 	},
 };
+
+int exynos_drm_probe_vidi(struct drm_device *dev)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	drm_dev = dev;
+
+	pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	ret = platform_driver_register(&vidi_driver);
+	if (ret) {
+		platform_device_unregister(pdev);
+		return ret;
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 9a6d652..3620d44 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -36,10 +36,12 @@
 #include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/hdmi.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_mixer.h"
 
 #include <linux/gpio.h>
@@ -928,16 +930,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
 	return 0;
 }
 
-static int hdmi_initialize(struct exynos_drm_display *display,
-			struct drm_device *drm_dev)
-{
-	struct hdmi_context *hdata = display->ctx;
-
-	hdata->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static void hdmi_mode_fixup(struct exynos_drm_display *display,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
@@ -1913,7 +1905,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops hdmi_display_ops = {
-	.initialize	= hdmi_initialize,
 	.create_connector = hdmi_create_connector,
 	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
@@ -2047,9 +2038,10 @@ static struct of_device_id hdmi_match_types[] = {
 	}
 };
 
-static int hdmi_probe(struct platform_device *pdev)
+static int hdmi_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 hdmi_context *hdata;
 	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
@@ -2150,10 +2142,10 @@ static int hdmi_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(dev);
 
+	hdata->drm_dev = drm_dev;
 	hdmi_display.ctx = hdata;
-	exynos_drm_display_register(&hdmi_display);
 
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
 
 err_hdmiphy:
 	put_device(&hdata->hdmiphy_port->dev);
@@ -2162,16 +2154,33 @@ err_ddc:
 	return ret;
 }
 
-static int hdmi_remove(struct platform_device *pdev)
+static void hdmi_unbind(struct device *dev, struct device *master, void *data)
 {
-	struct device *dev = &pdev->dev;
 	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct drm_encoder *encoder = display->encoder;
 	struct hdmi_context *hdata = display->ctx;
 
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&hdata->connector);
+
 	put_device(&hdata->hdmiphy_port->dev);
 	put_device(&hdata->ddc_adpt->dev);
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
+}
 
+static const struct component_ops hdmi_component_ops = {
+	.bind	= hdmi_bind,
+	.unbind = hdmi_unbind,
+};
+
+static int hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &hdmi_component_ops);
+}
+
+static int hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &hdmi_component_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ce28881..d46a262 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -31,6 +31,7 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
 }
 
 static int mixer_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	int ret;
 	struct mixer_context *mixer_ctx = mgr->ctx;
+	struct exynos_drm_private *priv;
+	priv = drm_dev->dev_private;
 
-	mixer_ctx->drm_dev = drm_dev;
-	mixer_ctx->pipe = pipe;
+	mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
+	mgr->pipe = mixer_ctx->pipe = priv->pipe++;
 
 	/* acquire resources: regs, irqs, clocks */
 	ret = mixer_resources_init(mixer_ctx);
@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode)
 }
 
 static struct exynos_drm_manager_ops mixer_manager_ops = {
-	.initialize		= mixer_initialize,
-	.remove			= mixer_mgr_remove,
 	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = {
 	}
 };
 
-static int mixer_probe(struct platform_device *pdev)
+static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
-	struct device *dev = &pdev->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct mixer_context *ctx;
 	struct mixer_drv_data *drv;
+	int ret;
 
 	dev_info(dev, "probe start\n");
 
@@ -1233,20 +1236,49 @@ static int mixer_probe(struct platform_device *pdev)
 	atomic_set(&ctx->wait_vsync_event, 0);
 
 	mixer_manager.ctx = ctx;
+	ret = mixer_initialize(&mixer_manager, drm_dev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, &mixer_manager);
-	exynos_drm_manager_register(&mixer_manager);
+	ret = exynos_drm_crtc_create(&mixer_manager);
+	if (ret) {
+		mixer_mgr_remove(&mixer_manager);
+		return ret;
+	}
 
 	pm_runtime_enable(dev);
 
 	return 0;
 }
 
-static int mixer_remove(struct platform_device *pdev)
+static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
-	dev_info(&pdev->dev, "remove successful\n");
+	struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
+	struct drm_crtc *crtc = mgr->crtc;
+
+	dev_info(dev, "remove successful\n");
+
+	mixer_mgr_remove(mgr);
 
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
 
+	crtc->funcs->destroy(crtc);
+}
+
+static const struct component_ops mixer_component_ops = {
+	.bind	= mixer_bind,
+	.unbind	= mixer_unbind,
+};
+
+static int mixer_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &mixer_component_ops);
+}
+
+static int mixer_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &mixer_component_ops);
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 2/7] drm/exynos: dpi: fix hotplug fail issue
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
@ 2014-04-01 12:37 ` Inki Dae
  2014-04-01 12:37 ` [PATCH v2 3/7] drm/exynos: register platform driver at each kms sub drivers Inki Dae
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:37 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

When connector is created, if connector->polled is
DRM_CONNECTOR_POLL_CONNECT then drm_kms_helper_hotplug_event
function isn't called at drm_helper_hpd_irq_event because the
function will be called only in case of DRM_CONNECTOR_POLL_HPD.

So this patch sets always DRM_CONNECTOR_POLL_HPD flag to
connector->polled of parallel panel driver at connector creation.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_dpi.c |    5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index c1f4b35..ac206e7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -123,10 +123,7 @@ static int exynos_dpi_create_connector(struct exynos_drm_display *display,
 
 	ctx->encoder = encoder;
 
-	if (ctx->panel_node)
-		connector->polled = DRM_CONNECTOR_POLL_CONNECT;
-	else
-		connector->polled = DRM_CONNECTOR_POLL_HPD;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
 
 	ret = drm_connector_init(encoder->dev, connector,
 				 &exynos_dpi_connector_funcs,
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH v2 3/7] drm/exynos: register platform driver at each kms sub drivers
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
  2014-04-01 12:37 ` [PATCH 2/7] drm/exynos: dpi: fix hotplug fail issue Inki Dae
@ 2014-04-01 12:37 ` Inki Dae
  2014-04-01 12:37 ` [PATCH 4/7] ARM: dts: exynos4210-universal: add super device node for exynos drm Inki Dae
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:37 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

This patch removes platform_driver_register() calls from
exynos_drm_drv module, and calls module_platform_driver()
at each kms sub drivers instead.

Previous RFC patch,
	http://www.spinics.net/lists/dri-devel/msg54672.html

Changelog since RFC patch:
- remove unnecessary platform_driver declarations to each sub driver.

Changelog v2:
- remove unnecessary platform_driver for mipi dsi driver.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c  |    1 +
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |   64 ------------------------------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |    6 ---
 drivers/gpu/drm/exynos/exynos_drm_dsi.c  |    1 +
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |    1 +
 drivers/gpu/drm/exynos/exynos_hdmi.c     |    1 +
 drivers/gpu/drm/exynos/exynos_mixer.c    |    1 +
 7 files changed, 5 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index cb9aa58..bf4996f 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -1362,6 +1362,7 @@ struct platform_driver dp_driver = {
 		.of_match_table = exynos_dp_match,
 	},
 };
+module_platform_driver(dp_driver);
 
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
 MODULE_DESCRIPTION("Samsung SoC DP Driver");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index f065385..c2f444a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -468,33 +468,6 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
 	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 	exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
 
-#ifdef CONFIG_DRM_EXYNOS_DP
-	ret = platform_driver_register(&dp_driver);
-	if (ret < 0)
-		goto out_dp;
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DSI
-	ret = platform_driver_register(&dsi_driver);
-	if (ret < 0)
-		goto out_dsi;
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMD
-	ret = platform_driver_register(&fimd_driver);
-	if (ret < 0)
-		goto out_fimd;
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_HDMI
-	ret = platform_driver_register(&hdmi_driver);
-	if (ret < 0)
-		goto out_hdmi;
-	ret = platform_driver_register(&mixer_driver);
-	if (ret < 0)
-		goto out_mixer;
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_G2D
 	ret = platform_driver_register(&g2d_driver);
 	if (ret < 0)
@@ -562,27 +535,6 @@ out_fimc:
 out_g2d:
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_HDMI
-	platform_driver_unregister(&mixer_driver);
-out_mixer:
-	platform_driver_unregister(&hdmi_driver);
-out_hdmi:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMD
-	platform_driver_unregister(&fimd_driver);
-out_fimd:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DSI
-	platform_driver_unregister(&dsi_driver);
-out_dsi:
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DP
-	platform_driver_unregister(&dp_driver);
-out_dp:
-#endif
 	return ret;
 }
 
@@ -609,22 +561,6 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
 	platform_driver_unregister(&g2d_driver);
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_HDMI
-	platform_driver_unregister(&mixer_driver);
-	platform_driver_unregister(&hdmi_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_FIMD
-	platform_driver_unregister(&fimd_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DSI
-	platform_driver_unregister(&dsi_driver);
-#endif
-
-#ifdef CONFIG_DRM_EXYNOS_DP
-	platform_driver_unregister(&dp_driver);
-#endif
 	component_master_del(&pdev->dev, &exynos_drm_ops);
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 25d562f..2b87eb7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -356,12 +356,6 @@ int exynos_drm_probe_vidi(struct drm_device *dev);
 int exynos_drm_create_enc_conn(struct drm_device *dev,
 				struct exynos_drm_display *display);
 
-extern struct platform_driver dp_driver;
-extern struct platform_driver dsi_driver;
-extern struct platform_driver fimd_driver;
-extern struct platform_driver hdmi_driver;
-extern struct platform_driver mixer_driver;
-extern struct platform_driver exynos_drm_common_hdmi_driver;
 extern struct platform_driver vidi_driver;
 extern struct platform_driver g2d_driver;
 extern struct platform_driver fimc_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 8f48f52..0005527 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1546,6 +1546,7 @@ struct platform_driver dsi_driver = {
 		   .of_match_table = exynos_dsi_of_match,
 	},
 };
+module_platform_driver(dsi_driver);
 
 MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
 MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 7ebfe15..aea4dbd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -992,3 +992,4 @@ struct platform_driver fimd_driver = {
 		.of_match_table = fimd_driver_dt_match,
 	},
 };
+module_platform_driver(fimd_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 3620d44..5db1b2d 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2193,3 +2193,4 @@ struct platform_driver hdmi_driver = {
 		.of_match_table = hdmi_match_types,
 	},
 };
+module_platform_driver(hdmi_driver);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index d46a262..12ef887 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -1292,3 +1292,4 @@ struct platform_driver mixer_driver = {
 	.remove = mixer_remove,
 	.id_table	= mixer_driver_types,
 };
+module_platform_driver(mixer_driver);
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 4/7] ARM: dts: exynos4210-universal: add super device node for exynos drm
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
                   ` (2 preceding siblings ...)
  2014-04-01 12:37 ` [PATCH v2 3/7] drm/exynos: register platform driver at each kms sub drivers Inki Dae
@ 2014-04-01 12:37 ` Inki Dae
  2014-04-01 12:38 ` [PATCH 5/7] ARM: dts: exynos4210-trats: " Inki Dae
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:37 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/boot/dts/exynos4210-universal_c210.dts |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index 0a80a72..5351ac4 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -409,6 +409,11 @@
 		};
 	};
 
+	display-subsystem {
+		compatible = "samsung,exynos-display-subsystem";
+		ports = <&fimd>;
+	};
+
 	pwm@139D0000 {
 		compatible = "samsung,s5p6440-pwm";
 		status = "okay";
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 5/7] ARM: dts: exynos4210-trats: add super device node for exynos drm
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
                   ` (3 preceding siblings ...)
  2014-04-01 12:37 ` [PATCH 4/7] ARM: dts: exynos4210-universal: add super device node for exynos drm Inki Dae
@ 2014-04-01 12:38 ` Inki Dae
  2014-04-01 12:38 ` [PATCH 6/7] ARM: dts: exynos4412-trats2: " Inki Dae
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:38 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/boot/dts/exynos4210-trats.dts |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index 02c6768..a41c109 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -414,6 +414,11 @@
 		status = "okay";
 	};
 
+	display-subsystem {
+		compatible = "samsung,exynos-display-subsystem";
+		ports = <&fimd>, <&dsi_0>;
+	};
+
 	camera {
 		pinctrl-names = "default";
 		pinctrl-0 = <>;
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 6/7] ARM: dts: exynos4412-trats2: add super device node for exynos drm
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
                   ` (4 preceding siblings ...)
  2014-04-01 12:38 ` [PATCH 5/7] ARM: dts: exynos4210-trats: " Inki Dae
@ 2014-04-01 12:38 ` Inki Dae
  2014-04-01 12:38 ` [PATCH 7/7] exynos/drm: add DT bindings Inki Dae
  2014-04-03  7:43 ` [PATCH v2 0/7] drm/exynos: more cleanup with super device support Andrzej Hajda
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:38 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 arch/arm/boot/dts/exynos4412-trats2.dts |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 53c717b..115b9ed 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -581,6 +581,11 @@
 		status = "okay";
 	};
 
+	display-subsystem {
+		compatible = "samsung,exynos-display-subsystem";
+		ports = <&fimd>, <&dsi_0>;
+	};
+
 	camera {
 		pinctrl-0 = <&cam_port_b_clk_active>;
 		pinctrl-names = "default";
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH 7/7] exynos/drm: add DT bindings
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
                   ` (5 preceding siblings ...)
  2014-04-01 12:38 ` [PATCH 6/7] ARM: dts: exynos4412-trats2: " Inki Dae
@ 2014-04-01 12:38 ` Inki Dae
  2014-04-03  7:43 ` [PATCH v2 0/7] drm/exynos: more cleanup with super device support Andrzej Hajda
  7 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-01 12:38 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

This patch adds bindings for Exynos drm display subsystem.
The bindings describes ports containing a list of phandles
pointing to display controller, image enhancer, and display
interfaces nodes.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 .../bindings/drm/exynos/samsung-exynos-drm.txt     |   32 ++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt

diff --git a/Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt b/Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt
new file mode 100644
index 0000000..6f7fae0
--- /dev/null
+++ b/Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt
@@ -0,0 +1,32 @@
+Samsung Exynos DRM master device
+================================
+
+The Samsung Exynos DRM master device is a virtual device needed to list all
+display controller, image enhancer, and display interface nodes that comprise
+the graphics subsystem.
+
+Required properties:
+- compatible: Should be "samsung,exynos-display-subsystem"
+- ports: Should contain a list of phandles pointing to display controller,
+  image enhancer, and display interface ports.
+
+Examples:
+
+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>;
+};
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
@ 2014-04-02 14:06   ` Andrzej Hajda
  2014-04-03  7:43     ` Inki Dae
  2014-04-03  8:36   ` [PATCH v3] " Inki Dae
  2014-04-04 13:55   ` [PATCH v2 1/7] drm/exynos: add super device support Tomasz Figa
  2 siblings, 1 reply; 47+ messages in thread
From: Andrzej Hajda @ 2014-04-02 14:06 UTC (permalink / raw)
  To: Inki Dae, airlied, dri-devel; +Cc: kyungmin.park

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

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-02 14:06   ` Andrzej Hajda
@ 2014-04-03  7:43     ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-03  7:43 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: kyungmin.park, dri-devel

2014-04-02 23:06 GMT+09:00, Andrzej Hajda <a.hajda@samsung.com>:
> 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.
>

That was what I tried to do but cannot do it because of below issues,

exynos_drm_crtc_create and exynos_dpi_probe functions need
fimd_manager with *drm_device* but fimd_probe cannot get drm_device
object.

I am typing on my smart phone because of ugly outlook so It is not
easy to comment enough. :(

Thinks,
Inki Dae

> 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;
>>  }
>>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 0/7] drm/exynos: more cleanup with super device support
  2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
                   ` (6 preceding siblings ...)
  2014-04-01 12:38 ` [PATCH 7/7] exynos/drm: add DT bindings Inki Dae
@ 2014-04-03  7:43 ` Andrzej Hajda
  7 siblings, 0 replies; 47+ messages in thread
From: Andrzej Hajda @ 2014-04-03  7:43 UTC (permalink / raw)
  To: Inki Dae, airlied, dri-devel; +Cc: kyungmin.park

Hi Inki,

On 04/01/2014 02:37 PM, Inki Dae wrote:
> This patch series cleans up exynos drm framework and kms sub drivers
> using the component framework[1].

I have tested it on trats platform (fimd + dsi), it works.
However it seems to be suboptimal.
In case of deferred probing of any of components (due to lack of some
resources, ex. clock, regulator, phy), all components
which were already bound are unbound and re-bound later when another
driver is added, this causes multiple unnecessary free/re-allocate cycles.
Maybe I miss something, but I guess registration list(s) + DT super-node
should perform better.

Here is sample log from trats with mipi-phy driver delayed probe:

 binding 11c00000.fimd (ops fimd_component_ops)
 bound 11c00000.fimd (ops fimd_component_ops)
 binding 11c80000.dsi (ops exynos_dsi_component_ops)
 failed to bind 11c80000.dsi (ops exynos_dsi_component_ops): -517
 unbinding 11c00000.fimd (ops fimd_component_ops)
 master bind failed: -517
 binding 11c00000.fimd (ops fimd_component_ops)
 bound 11c00000.fimd (ops fimd_component_ops)
 binding 11c80000.dsi (ops exynos_dsi_component_ops)
 failed to bind 11c80000.dsi (ops exynos_dsi_component_ops): -517
 unbinding 11c00000.fimd (ops fimd_component_ops)
 master bind failed: -517
 binding 11c00000.fimd (ops fimd_component_ops)
 bound 11c00000.fimd (ops fimd_component_ops)
 binding 11c80000.dsi (ops exynos_dsi_component_ops)
 failed to bind 11c80000.dsi (ops exynos_dsi_component_ops): -517
 unbinding 11c00000.fimd (ops fimd_component_ops)
 master bind failed: -517
 binding 11c00000.fimd (ops fimd_component_ops)
 bound 11c00000.fimd (ops fimd_component_ops)
 binding 11c80000.dsi (ops exynos_dsi_component_ops)
 failed to bind 11c80000.dsi (ops exynos_dsi_component_ops): -517
 unbinding 11c00000.fimd (ops fimd_component_ops)
 master bind failed: -517
 binding 11c00000.fimd (ops fimd_component_ops)
 bound 11c00000.fimd (ops fimd_component_ops)
 binding 11c80000.dsi (ops exynos_dsi_component_ops)
 bound 11c80000.dsi (ops exynos_dsi_component_ops)

This log will grow with number of devices probed in-between.

Regards
Andrzej

> 
> And this patch series had been posted for RFC[2].
> 
> Thanks,
> Inki Dae
> 
> [1] http://lists.freedesktop.org/archives/dri-devel/2014-January/051249.html
> [2] http://comments.gmane.org/gmane.comp.video.dri.devel/101200
> 
> 
> Inki Dae (7):
>   drm/exynos: add super device support
>   drm/exynos: dpi: fix hotplug fail issue
>   drm/exynos: register platform driver at each kms sub drivers
>   ARM: dts: exynos4210-universal: add super device node for exynos drm
>   ARM: dts: exynos4210-trats: add super device node for exynos drm
>   ARM: dts: exynos4412-trats2: add super device node for exynos drm
>   exynos/drm: add DT bindings
> 
>  .../bindings/drm/exynos/samsung-exynos-drm.txt     |   32 +++
>  arch/arm/boot/dts/exynos4210-trats.dts             |    5 +
>  arch/arm/boot/dts/exynos4210-universal_c210.dts    |    5 +
>  arch/arm/boot/dts/exynos4412-trats2.dts            |    5 +
>  drivers/gpu/drm/exynos/exynos_dp_core.c            |   46 ++--
>  drivers/gpu/drm/exynos/exynos_drm_core.c           |  216 +++--------------
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c           |   17 ++
>  drivers/gpu/drm/exynos/exynos_drm_crtc.h           |    4 +
>  drivers/gpu/drm/exynos/exynos_drm_dpi.c            |   21 +-
>  drivers/gpu/drm/exynos/exynos_drm_drv.c            |  256 ++++++++------------
>  drivers/gpu/drm/exynos/exynos_drm_drv.h            |   79 +++---
>  drivers/gpu/drm/exynos/exynos_drm_dsi.c            |   39 ++-
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c           |   77 ++++--
>  drivers/gpu/drm/exynos/exynos_drm_vidi.c           |   61 +++--
>  drivers/gpu/drm/exynos/exynos_hdmi.c               |   46 ++--
>  drivers/gpu/drm/exynos/exynos_mixer.c              |   55 ++++-
>  16 files changed, 490 insertions(+), 474 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/drm/exynos/samsung-exynos-drm.txt
> 

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v3] drm/exynos: add super device support
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
  2014-04-02 14:06   ` Andrzej Hajda
@ 2014-04-03  8:36   ` Inki Dae
  2014-04-03 11:47     ` [PATCH v4] " Inki Dae
  2014-04-04 13:55   ` [PATCH v2 1/7] drm/exynos: add super device support Tomasz Figa
  2 siblings, 1 reply; 47+ messages in thread
From: Inki Dae @ 2014-04-03  8:36 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

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.

Previous RFC patch,
	 http://www.spinics.net/lists/dri-devel/msg54671.html

Changelog since RFC patch:
- Register sub drivers and probe them at load(). In case of non sub
  drivers, sub driver probe is needed.
- Enable runtime pm at fimd_probe() instead of fimd_bind(). runtime pm
  should be enabled before iommu device is attached to fimd device.
- Do not return an error with component_master_add fail.
- Remove super device support from mipi dsi driver which was in RFC.
- Add super device support to parallel driver.

Changelog v2:
- Add super device support to mipi dsi driver.
- Bind fimd driver only in case that a drm_panel for parallel panel driver
  is added to panel_list of drm_panel module.
- Change super node name to 'display-subsystem'
  . 'exynos-drm' is specific to Linux so change it to generic name.
- Change propery name of super node to 'ports'
  . crtcs and connectors propery names are also specific to Linux so
    change them to generic name.

Changlog v3:
- Do not probe/remove dpi module if fimd node has no port node.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c  |   45 ++++---
 drivers/gpu/drm/exynos/exynos_drm_core.c |  216 +++++-------------------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c |   17 +++
 drivers/gpu/drm/exynos/exynos_drm_crtc.h |    4 +
 drivers/gpu/drm/exynos/exynos_drm_dpi.c  |   16 ++-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  202 +++++++++++++++-------------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |   73 +++++-----
 drivers/gpu/drm/exynos/exynos_drm_dsi.c  |   38 +++++-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |   87 +++++++++---
 drivers/gpu/drm/exynos/exynos_drm_vidi.c |   61 +++++++--
 drivers/gpu/drm/exynos/exynos_hdmi.c     |   45 ++++---
 drivers/gpu/drm/exynos/exynos_mixer.c    |   54 ++++++--
 12 files changed, 451 insertions(+), 407 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index a59bca9..cb9aa58 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <linux/component.h>
 #include <linux/phy/phy.h>
 #include <video/of_display_timing.h>
 #include <video/of_videomode.h>
@@ -969,16 +970,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static int exynos_dp_initialize(struct exynos_drm_display *display,
-				struct drm_device *drm_dev)
-{
-	struct exynos_dp_device *dp = display->ctx;
-
-	dp->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static bool find_bridge(const char *compat, struct bridge_init *bridge)
 {
 	bridge->client = NULL;
@@ -1106,7 +1097,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops exynos_dp_display_ops = {
-	.initialize = exynos_dp_initialize,
 	.create_connector = exynos_dp_create_connector,
 	.dpms = exynos_dp_dpms,
 };
@@ -1230,8 +1220,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 	return 0;
 }
 
-static int exynos_dp_probe(struct platform_device *pdev)
+static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct resource *res;
 	struct exynos_dp_device *dp;
 
@@ -1293,21 +1285,40 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	}
 	disable_irq(dp->irq);
 
+	dp->drm_dev = drm_dev;
 	exynos_dp_display.ctx = dp;
 
 	platform_set_drvdata(pdev, &exynos_dp_display);
-	exynos_drm_display_register(&exynos_dp_display);
 
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
 }
 
-static int exynos_dp_remove(struct platform_device *pdev)
+static void exynos_dp_unbind(struct device *dev, struct device *master,
+				void *data)
 {
-	struct exynos_drm_display *display = platform_get_drvdata(pdev);
+	struct exynos_drm_display *display = dev_get_drvdata(dev);
+	struct exynos_dp_device *dp = display->ctx;
+	struct drm_encoder *encoder = dp->encoder;
 
 	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dp_display);
 
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dp->connector);
+}
+
+static const struct component_ops exynos_dp_ops = {
+	.bind	= exynos_dp_bind,
+	.unbind	= exynos_dp_unbind,
+};
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &exynos_dp_ops);
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &exynos_dp_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 0e9e06c..4c9f972 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -19,21 +19,19 @@
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
-static LIST_HEAD(exynos_drm_manager_list);
-static LIST_HEAD(exynos_drm_display_list);
 
-static int exynos_drm_create_enc_conn(struct drm_device *dev,
+int exynos_drm_create_enc_conn(struct drm_device *dev,
 					struct exynos_drm_display *display)
 {
 	struct drm_encoder *encoder;
-	struct exynos_drm_manager *manager;
 	int ret;
 	unsigned long possible_crtcs = 0;
 
-	/* Find possible crtcs for this display */
-	list_for_each_entry(manager, &exynos_drm_manager_list, list)
-		if (manager->type == display->type)
-			possible_crtcs |= 1 << manager->pipe;
+	ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
+	if (ret < 0)
+		return ret;
+
+	possible_crtcs |= 1 << ret;
 
 	/* create and initialize a encoder for this sub driver. */
 	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
@@ -57,127 +55,29 @@ err_destroy_encoder:
 	return ret;
 }
 
-static int exynos_drm_subdrv_probe(struct drm_device *dev,
-					struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->probe) {
-		int ret;
-
-		subdrv->drm_dev = dev;
-
-		/*
-		 * this probe callback would be called by sub driver
-		 * after setting of all resources to this sub driver,
-		 * such as clock, irq and register map are done or by load()
-		 * of exynos drm driver.
-		 *
-		 * P.S. note that this driver is considered for modularization.
-		 */
-		ret = subdrv->probe(dev, subdrv->dev);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void exynos_drm_subdrv_remove(struct drm_device *dev,
-				      struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->remove)
-		subdrv->remove(dev, subdrv->dev);
-}
-
-int exynos_drm_initialize_managers(struct drm_device *dev)
+int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_manager *manager, *n;
-	int ret, pipe = 0;
-
-	list_for_each_entry(manager, &exynos_drm_manager_list, list) {
-		if (manager->ops->initialize) {
-			ret = manager->ops->initialize(manager, dev, pipe);
-			if (ret) {
-				DRM_ERROR("Mgr init [%d] failed with %d\n",
-						manager->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		manager->drm_dev = dev;
-		manager->pipe = pipe++;
+	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
 
-		ret = exynos_drm_crtc_create(manager);
-		if (ret) {
-			DRM_ERROR("CRTC create [%d] failed with %d\n",
-					manager->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
-		if (pipe-- > 0)
-			exynos_drm_manager_unregister(manager);
-		else
-			list_del(&manager->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_managers(struct drm_device *dev)
-{
-	struct exynos_drm_manager *manager, *n;
-
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
-		exynos_drm_manager_unregister(manager);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
 
-int exynos_drm_initialize_displays(struct drm_device *dev)
+int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_display *display, *n;
-	int ret, initialized = 0;
-
-	list_for_each_entry(display, &exynos_drm_display_list, list) {
-		if (display->ops->initialize) {
-			ret = display->ops->initialize(display, dev);
-			if (ret) {
-				DRM_ERROR("Display init [%d] failed with %d\n",
-						display->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		initialized++;
+	list_del(&subdrv->list);
 
-		ret = exynos_drm_create_enc_conn(dev, display);
-		if (ret) {
-			DRM_ERROR("Encoder create [%d] failed with %d\n",
-					display->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
-		if (initialized-- > 0)
-			exynos_drm_display_unregister(display);
-		else
-			list_del(&display->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_displays(struct drm_device *dev)
-{
-	struct exynos_drm_display *display, *n;
-
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
-		exynos_drm_display_unregister(display);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
 
-int exynos_drm_device_register(struct drm_device *dev)
+int exynos_drm_device_subdrv_probe(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv, *n;
 	int err;
@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev)
 		return -EINVAL;
 
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
-		err = exynos_drm_subdrv_probe(dev, subdrv);
-		if (err) {
-			DRM_DEBUG("exynos drm subdrv probe failed.\n");
-			list_del(&subdrv->list);
-			continue;
+		if (subdrv->probe) {
+			subdrv->drm_dev = dev;
+
+			/*
+			 * this probe callback would be called by sub driver
+			 * after setting of all resources to this sub driver,
+			 * such as clock, irq and register map are done.
+			 */
+			err = subdrv->probe(dev, subdrv->dev);
+			if (err) {
+				DRM_DEBUG("exynos drm subdrv probe failed.\n");
+				list_del(&subdrv->list);
+				continue;
+			}
 		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_register);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
 
-int exynos_drm_device_unregister(struct drm_device *dev)
+int exynos_drm_device_subdrv_remove(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv;
 
@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 	}
 
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		exynos_drm_subdrv_remove(dev, subdrv);
+		if (subdrv->remove)
+			subdrv->remove(dev, subdrv->dev);
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager)
-{
-	BUG_ON(!manager->ops);
-	list_add_tail(&manager->list, &exynos_drm_manager_list);
-	return 0;
-}
-
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
-{
-	if (manager->ops->remove)
-		manager->ops->remove(manager);
-
-	list_del(&manager->list);
-	return 0;
-}
-
-int exynos_drm_display_register(struct exynos_drm_display *display)
-{
-	BUG_ON(!display->ops);
-	list_add_tail(&display->list, &exynos_drm_display_list);
-	return 0;
-}
-
-int exynos_drm_display_unregister(struct exynos_drm_display *display)
-{
-	if (display->ops->remove)
-		display->ops->remove(display);
-
-	list_del(&display->list);
-	return 0;
-}
-
-int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
-
-int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_del(&subdrv->list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
 
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
 {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 9cc92ae..c197b99 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -367,6 +367,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 		return -ENOMEM;
 	}
 
+	manager->crtc = &exynos_crtc->drm_crtc;
 	crtc = &exynos_crtc->drm_crtc;
 
 	private->crtc[manager->pipe] = crtc;
@@ -490,3 +491,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
 			manager->ops->wait_for_vblank(manager);
 	}
 }
+
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
+		struct exynos_drm_crtc *exynos_crtc;
+
+		exynos_crtc = to_exynos_crtc(crtc);
+		if (exynos_crtc->manager->type == out_type)
+			return exynos_crtc->manager->pipe;
+	}
+
+	return -EPERM;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index c27b66c..9f74b10 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
 
+/* This function gets pipe value to crtc device matched with out_type. */
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type);
+
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 2b09c7c..c1f4b35 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -255,7 +255,7 @@ enum {
 	FIMD_PORT_WRB,
 };
 
-static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
 {
 	struct device_node *np, *ep;
 
@@ -308,7 +308,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 	return 0;
 }
 
-int exynos_dpi_probe(struct device *dev)
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
 {
 	struct exynos_dpi *ctx;
 	int ret;
@@ -325,15 +325,17 @@ int exynos_dpi_probe(struct device *dev)
 	if (ret < 0)
 		return ret;
 
-	exynos_drm_display_register(&exynos_dpi_display);
-
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
 }
 
-int exynos_dpi_remove(struct device *dev)
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
 {
+	struct drm_encoder *encoder = exynos_dpi_display.encoder;
+	struct exynos_dpi *ctx = exynos_dpi_display.ctx;
+
 	exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dpi_display);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2d27ba2..f065385 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -16,6 +16,7 @@
 #include <drm/drm_crtc_helper.h>
 
 #include <linux/anon_inodes.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -40,9 +41,6 @@
 
 #define VBLANK_OFF_DELAY	50000
 
-/* platform device pointer for eynos drm device. */
-static struct platform_device *exynos_drm_pdev;
-
 static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
 	struct exynos_drm_private *private;
@@ -73,38 +71,21 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	exynos_drm_mode_config_init(dev);
 
-	ret = exynos_drm_initialize_managers(dev);
-	if (ret)
-		goto err_mode_config_cleanup;
-
 	for (nr = 0; nr < MAX_PLANE; nr++) {
 		struct drm_plane *plane;
 		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
 		plane = exynos_plane_init(dev, possible_crtcs, false);
 		if (!plane)
-			goto err_manager_cleanup;
+			goto err_mode_config_cleanup;
 	}
 
-	ret = exynos_drm_initialize_displays(dev);
-	if (ret)
-		goto err_manager_cleanup;
-
 	/* init kms poll for handling hpd */
 	drm_kms_helper_poll_init(dev);
 
 	ret = drm_vblank_init(dev, MAX_CRTC);
 	if (ret)
-		goto err_display_cleanup;
-
-	/*
-	 * probe sub drivers such as display controller and hdmi driver,
-	 * that were registered at probe() of platform driver
-	 * to the sub driver and create encoder and connector for them.
-	 */
-	ret = exynos_drm_device_register(dev);
-	if (ret)
-		goto err_vblank;
+		goto err_mode_config_cleanup;
 
 	/* setup possible_clones. */
 	exynos_drm_encoder_setup(dev);
@@ -113,17 +94,35 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	platform_set_drvdata(dev->platformdev, dev);
 
+	/* Try to bind all sub drivers. */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto err_cleanup_vblank;
+
+	/* Probe non kms sub drivers. */
+	ret = exynos_drm_device_subdrv_probe(dev);
+	if (ret)
+		goto err_unbind_all;
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	ret = exynos_drm_probe_vidi(dev);
+	if (ret < 0)
+		goto err_remove_subdrv;
+#endif
+
 	/* force connectors detection */
 	drm_helper_hpd_irq_event(dev);
 
 	return 0;
 
-err_vblank:
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+err_remove_subdrv:
+	exynos_drm_device_subdrv_remove(dev);
+#endif
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
+err_cleanup_vblank:
 	drm_vblank_cleanup(dev);
-err_display_cleanup:
-	exynos_drm_remove_displays(dev);
-err_manager_cleanup:
-	exynos_drm_remove_managers(dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	drm_release_iommu_mapping(dev);
@@ -135,17 +134,17 @@ err_free_private:
 
 static int exynos_drm_unload(struct drm_device *dev)
 {
+	exynos_drm_device_subdrv_remove(dev);
+
 	exynos_drm_fbdev_fini(dev);
-	exynos_drm_device_unregister(dev);
 	drm_vblank_cleanup(dev);
 	drm_kms_helper_poll_fini(dev);
-	exynos_drm_remove_displays(dev);
-	exynos_drm_remove_managers(dev);
 	drm_mode_config_cleanup(dev);
 
 	drm_release_iommu_mapping(dev);
 	kfree(dev->dev_private);
 
+	component_unbind_all(dev->dev, dev);
 	dev->dev_private = NULL;
 
 	return 0;
@@ -355,27 +354,6 @@ static struct drm_driver exynos_drm_driver = {
 	.minor	= DRIVER_MINOR,
 };
 
-static int exynos_drm_platform_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	return drm_platform_init(&exynos_drm_driver, pdev);
-}
-
-static int exynos_drm_platform_remove(struct platform_device *pdev)
-{
-	drm_put_dev(platform_get_drvdata(pdev));
-
-	return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int exynos_drm_sys_suspend(struct device *dev)
 {
@@ -430,20 +408,66 @@ static const struct dev_pm_ops exynos_drm_pm_ops = {
 			exynos_drm_runtime_resume, NULL)
 };
 
-static struct platform_driver exynos_drm_platform_driver = {
-	.probe		= exynos_drm_platform_probe,
-	.remove		= exynos_drm_platform_remove,
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "exynos-drm",
-		.pm	= &exynos_drm_pm_ops,
-	},
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int exynos_drm_add_components(struct device *dev, struct master *m)
+{
+	struct device_node *np = dev->of_node;
+	unsigned int i;
+
+	for (i = 0;; i++) {
+		struct device_node *node;
+		int ret;
+
+		node = of_parse_phandle(np, "ports", i);
+		if (!node)
+			break;
+
+		ret = component_master_add_child(m, compare_of, node);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_drm_bind(struct device *dev)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
+}
+
+static void exynos_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops exynos_drm_ops = {
+	.add_components = exynos_drm_add_components,
+	.bind		= exynos_drm_bind,
+	.unbind		= exynos_drm_unbind,
 };
 
-static int __init exynos_drm_init(void)
+static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
 	int ret;
 
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
+
 #ifdef CONFIG_DRM_EXYNOS_DP
 	ret = platform_driver_register(&dp_driver);
 	if (ret < 0)
@@ -471,12 +495,6 @@ static int __init exynos_drm_init(void)
 		goto out_mixer;
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	ret = platform_driver_register(&vidi_driver);
-	if (ret < 0)
-		goto out_vidi;
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_G2D
 	ret = platform_driver_register(&g2d_driver);
 	if (ret < 0)
@@ -511,23 +529,12 @@ static int __init exynos_drm_init(void)
 		goto out_ipp_dev;
 #endif
 
-	ret = platform_driver_register(&exynos_drm_platform_driver);
+	ret = component_master_add(&pdev->dev, &exynos_drm_ops);
 	if (ret < 0)
-		goto out_drm;
-
-	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
-				NULL, 0);
-	if (IS_ERR(exynos_drm_pdev)) {
-		ret = PTR_ERR(exynos_drm_pdev);
-		goto out;
-	}
+		DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
 
 	return 0;
 
-out:
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
-out_drm:
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 out_ipp_dev:
@@ -555,11 +562,6 @@ out_fimc:
 out_g2d:
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-out_vidi:
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&mixer_driver);
 out_mixer:
@@ -584,12 +586,8 @@ out_dp:
 	return ret;
 }
 
-static void __exit exynos_drm_exit(void)
+static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(exynos_drm_pdev);
-
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 	platform_driver_unregister(&ipp_driver);
@@ -616,10 +614,6 @@ static void __exit exynos_drm_exit(void)
 	platform_driver_unregister(&hdmi_driver);
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	platform_driver_unregister(&fimd_driver);
 #endif
@@ -631,10 +625,28 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_DP
 	platform_driver_unregister(&dp_driver);
 #endif
+	component_master_del(&pdev->dev, &exynos_drm_ops);
+	return 0;
 }
 
-module_init(exynos_drm_init);
-module_exit(exynos_drm_exit);
+static const struct of_device_id exynos_drm_dt_match[] = {
+	{ .compatible = "samsung,exynos-display-subsystem", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, exynos_drm_dt_match);
+
+static struct platform_driver exynos_drm_platform_driver = {
+	.probe	= exynos_drm_platform_probe,
+	.remove	= exynos_drm_platform_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "exynos-drm",
+		.pm	= &exynos_drm_pm_ops,
+		.of_match_table	= exynos_drm_dt_match,
+	},
+};
+module_platform_driver(exynos_drm_platform_driver);
 
 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 4c5cf68..25d562f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -122,7 +122,6 @@ struct exynos_drm_overlay {
  * Exynos DRM Display Structure.
  *	- this structure is common to analog tv, digital tv and lcd panel.
  *
- * @initialize: initializes the display with drm_dev
  * @remove: cleans up the display for removal
  * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
@@ -133,8 +132,6 @@ struct exynos_drm_overlay {
  */
 struct exynos_drm_display;
 struct exynos_drm_display_ops {
-	int (*initialize)(struct exynos_drm_display *display,
-				struct drm_device *drm_dev);
 	int (*create_connector)(struct exynos_drm_display *display,
 				struct drm_encoder *encoder);
 	void (*remove)(struct exynos_drm_display *display);
@@ -172,8 +169,6 @@ struct exynos_drm_display {
 /*
  * Exynos drm manager ops
  *
- * @initialize: initializes the manager with drm_dev
- * @remove: cleans up the manager for removal
  * @dpms: control device power.
  * @mode_fixup: fix mode data before applying it
  * @mode_set: set the given mode to the manager
@@ -189,9 +184,6 @@ struct exynos_drm_display {
  */
 struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
-	int (*initialize)(struct exynos_drm_manager *mgr,
-				struct drm_device *drm_dev, int pipe);
-	void (*remove)(struct exynos_drm_manager *mgr);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
 	bool (*mode_fixup)(struct exynos_drm_manager *mgr,
 				const struct drm_display_mode *mode,
@@ -215,6 +207,7 @@ struct exynos_drm_manager_ops {
  * @list: the list entry for this manager
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @drm_dev: pointer to the drm device
+ * @crtc: crtc object.
  * @pipe: the pipe number for this crtc/manager
  * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the manager's implementation specific context
@@ -223,6 +216,7 @@ struct exynos_drm_manager {
 	struct list_head list;
 	enum exynos_drm_output_type type;
 	struct drm_device *drm_dev;
+	struct drm_crtc *crtc;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
 	void *ctx;
@@ -255,6 +249,7 @@ struct drm_exynos_file_private {
  * @da_space_size: size of device address space.
  *	if 0 then default value is used for it.
  * @da_space_order: order to device address space.
+ * @pipe: the pipe number for this crtc/manager.
  */
 struct exynos_drm_private {
 	struct drm_fb_helper *fb_helper;
@@ -273,6 +268,8 @@ struct exynos_drm_private {
 	unsigned long da_start;
 	unsigned long da_space_size;
 	unsigned long da_space_order;
+
+	unsigned int pipe;
 };
 
 /*
@@ -283,11 +280,11 @@ struct exynos_drm_private {
  * @drm_dev: pointer to drm_device and this pointer would be set
  *	when sub driver calls exynos_drm_subdrv_register().
  * @manager: subdrv has its own manager to control a hardware appropriately
- *	and we can access a hardware drawing on this manager.
+ *     and we can access a hardware drawing on this manager.
  * @probe: this callback would be called by exynos drm driver after
- *	subdrv is registered to it.
+ *     subdrv is registered to it.
  * @remove: this callback is used to release resources created
- *	by probe callback.
+ *     by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
  */
@@ -304,39 +301,14 @@ struct exynos_drm_subdrv {
 			struct drm_file *file);
 };
 
-/*
- * this function calls a probe callback registered to sub driver list and
- * create its own encoder and connector and then set drm_device object
- * to global one.
- */
-int exynos_drm_device_register(struct drm_device *dev);
-/*
- * this function calls a remove callback registered to sub driver list and
- * destroy its own encoder and connetor.
- */
-int exynos_drm_device_unregister(struct drm_device *dev);
-
-int exynos_drm_initialize_managers(struct drm_device *dev);
-void exynos_drm_remove_managers(struct drm_device *dev);
-int exynos_drm_initialize_displays(struct drm_device *dev);
-void exynos_drm_remove_displays(struct drm_device *dev);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager);
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
-int exynos_drm_display_register(struct exynos_drm_display *display);
-int exynos_drm_display_unregister(struct exynos_drm_display *display);
-
-/*
- * this function would be called by sub drivers such as display controller
- * or hdmi driver to register this sub driver object to exynos drm driver
- * and when a sub driver is registered to exynos drm driver a probe callback
- * of the sub driver is called and creates its own encoder and connector.
- */
+ /* This function would be called by non kms drivers such as g2d and ipp. */
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 
 /* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+int exynos_drm_device_subdrv_probe(struct drm_device *dev);
+int exynos_drm_device_subdrv_remove(struct drm_device *dev);
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
 
@@ -362,13 +334,28 @@ int exynos_platform_device_ipp_register(void);
 void exynos_platform_device_ipp_unregister(void);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
-int exynos_dpi_probe(struct device *dev);
-int exynos_dpi_remove(struct device *dev);
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
 #else
-static inline int exynos_dpi_probe(struct device *dev) { return 0; }
-static inline int exynos_dpi_remove(struct device *dev) { return 0; }
+static inline int exynos_dpi_probe(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline struct device_node
+			*exynos_dpi_of_find_panel_node(struct device *dev)
+{ return NULL; }
 #endif
 
+/*
+ * this function registers exynos drm vidi platform device.
+ */
+int exynos_drm_probe_vidi(struct drm_device *dev);
+
+/* This function creates a encoder and a connector, and initializes them. */
+int exynos_drm_create_enc_conn(struct drm_device *dev,
+				struct exynos_drm_display *display);
+
 extern struct platform_driver dp_driver;
 extern struct platform_driver dsi_driver;
 extern struct platform_driver fimd_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 697228e..8f48f52 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
+#include <linux/component.h>
 
 #include <video/mipi_display.h>
 #include <video/videomode.h>
@@ -1378,8 +1379,11 @@ end:
 	return ret;
 }
 
-static int exynos_dsi_probe(struct platform_device *pdev)
+static int exynos_dsi_bind(struct device *dev, struct device *master,
+				void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct resource *res;
 	struct exynos_dsi *dsi;
 	int ret;
@@ -1454,22 +1458,30 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 
 	exynos_dsi_display.ctx = dsi;
 
+	ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
+	if (ret) {
+		DRM_ERROR("Encoder create [%d] failed with %d\n",
+				exynos_dsi_display.type, ret);
+		return ret;
+	}
+
 	platform_set_drvdata(pdev, &exynos_dsi_display);
-	exynos_drm_display_register(&exynos_dsi_display);
 
 	return mipi_dsi_host_register(&dsi->dsi_host);
 }
 
-static int exynos_dsi_remove(struct platform_device *pdev)
+static void exynos_dsi_unbind(struct device *dev, struct device *master,
+				void *data)
 {
 	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+	struct drm_encoder *encoder = dsi->encoder;
 
 	exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
 
-	exynos_drm_display_unregister(&exynos_dsi_display);
 	mipi_dsi_host_unregister(&dsi->dsi_host);
 
-	return 0;
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dsi->connector);
 }
 
 #if CONFIG_PM_SLEEP
@@ -1502,6 +1514,22 @@ static const struct dev_pm_ops exynos_dsi_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
 };
 
+static const struct component_ops exynos_dsi_component_ops = {
+	.bind	= exynos_dsi_bind,
+	.unbind	= exynos_dsi_unbind,
+};
+
+static int exynos_dsi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &exynos_dsi_component_ops);
+}
+
+static int exynos_dsi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &exynos_dsi_component_ops);
+	return 0;
+}
+
 static struct of_device_id exynos_dsi_of_match[] = {
 	{ .compatible = "samsung,exynos4210-mipi-dsi" },
 	{ }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 40fd6cc..b26b27e 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,10 +851,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;
@@ -910,11 +914,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);
-
-	exynos_dpi_probe(ctx->dev);
-
-	pm_runtime_enable(dev);
+	fimd_mgr_initialize(&fimd_manager, drm_dev);
+
+	exynos_drm_crtc_create(&fimd_manager);
+
+	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);
@@ -922,18 +934,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;
 
-	exynos_dpi_remove(&pdev->dev);
+	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
-	exynos_drm_manager_unregister(&fimd_manager);
+	dn = exynos_dpi_of_find_panel_node(dev);
+	if (dn)
+		exynos_dpi_remove(mgr->drm_dev, dev);
 
-	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
+	fimd_mgr_remove(mgr);
+
+	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 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;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 7afead9..22076e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -65,6 +65,8 @@ struct vidi_context {
 	int				pipe;
 };
 
+static struct drm_device *drm_dev;
+
 static const char fake_edid_info[] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
 	0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
@@ -294,14 +296,15 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 }
 
 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	struct vidi_context *ctx = mgr->ctx;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
 
-	DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
+	DRM_DEBUG_KMS("vidi initialize ctx=%p dev=%p\n", ctx, drm_dev);
 
-	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.
@@ -324,7 +327,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
 }
 
 static struct exynos_drm_manager_ops vidi_manager_ops = {
-	.initialize = vidi_mgr_initialize,
 	.dpms = vidi_dpms,
 	.commit = vidi_commit,
 	.enable_vblank = vidi_enable_vblank,
@@ -588,11 +590,14 @@ static struct exynos_drm_display vidi_display = {
 
 static int vidi_probe(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
 	struct vidi_context *ctx;
 	int ret;
 
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	/* drm_dev shouldn't be NULL. */
+	if (!drm_dev)
+		return -EFAULT;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -603,32 +608,40 @@ static int vidi_probe(struct platform_device *pdev)
 	vidi_manager.ctx = ctx;
 	vidi_display.ctx = ctx;
 
+	vidi_mgr_initialize(&vidi_manager, drm_dev);
+
 	mutex_init(&ctx->lock);
 
 	platform_set_drvdata(pdev, &vidi_manager);
 
-	ret = device_create_file(dev, &dev_attr_connection);
+	ret = device_create_file(&pdev->dev, &dev_attr_connection);
 	if (ret < 0)
 		DRM_INFO("failed to create connection sysfs.\n");
 
-	exynos_drm_manager_register(&vidi_manager);
-	exynos_drm_display_register(&vidi_display);
+	exynos_drm_crtc_create(&vidi_manager);
+	exynos_drm_create_enc_conn(drm_dev, &vidi_display);
 
 	return 0;
 }
 
 static int vidi_remove(struct platform_device *pdev)
 {
-	struct vidi_context *ctx = platform_get_drvdata(pdev);
-
-	exynos_drm_display_unregister(&vidi_display);
-	exynos_drm_manager_unregister(&vidi_manager);
+	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
+	struct vidi_context *ctx = mgr->ctx;
+	struct drm_encoder *encoder = ctx->encoder;
+	struct drm_crtc *crtc = mgr->crtc;
 
 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 		kfree(ctx->raw_edid);
 		ctx->raw_edid = NULL;
+
+		return -EINVAL;
 	}
 
+	crtc->funcs->destroy(crtc);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
+
 	return 0;
 }
 
@@ -640,3 +653,23 @@ struct platform_driver vidi_driver = {
 		.owner	= THIS_MODULE,
 	},
 };
+
+int exynos_drm_probe_vidi(struct drm_device *dev)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	drm_dev = dev;
+
+	pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	ret = platform_driver_register(&vidi_driver);
+	if (ret) {
+		platform_device_unregister(pdev);
+		return ret;
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 9a6d652..3620d44 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -36,10 +36,12 @@
 #include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/hdmi.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_mixer.h"
 
 #include <linux/gpio.h>
@@ -928,16 +930,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
 	return 0;
 }
 
-static int hdmi_initialize(struct exynos_drm_display *display,
-			struct drm_device *drm_dev)
-{
-	struct hdmi_context *hdata = display->ctx;
-
-	hdata->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static void hdmi_mode_fixup(struct exynos_drm_display *display,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
@@ -1913,7 +1905,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops hdmi_display_ops = {
-	.initialize	= hdmi_initialize,
 	.create_connector = hdmi_create_connector,
 	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
@@ -2047,9 +2038,10 @@ static struct of_device_id hdmi_match_types[] = {
 	}
 };
 
-static int hdmi_probe(struct platform_device *pdev)
+static int hdmi_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 hdmi_context *hdata;
 	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
@@ -2150,10 +2142,10 @@ static int hdmi_probe(struct platform_device *pdev)
 
 	pm_runtime_enable(dev);
 
+	hdata->drm_dev = drm_dev;
 	hdmi_display.ctx = hdata;
-	exynos_drm_display_register(&hdmi_display);
 
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
 
 err_hdmiphy:
 	put_device(&hdata->hdmiphy_port->dev);
@@ -2162,16 +2154,33 @@ err_ddc:
 	return ret;
 }
 
-static int hdmi_remove(struct platform_device *pdev)
+static void hdmi_unbind(struct device *dev, struct device *master, void *data)
 {
-	struct device *dev = &pdev->dev;
 	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct drm_encoder *encoder = display->encoder;
 	struct hdmi_context *hdata = display->ctx;
 
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&hdata->connector);
+
 	put_device(&hdata->hdmiphy_port->dev);
 	put_device(&hdata->ddc_adpt->dev);
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
+}
 
+static const struct component_ops hdmi_component_ops = {
+	.bind	= hdmi_bind,
+	.unbind = hdmi_unbind,
+};
+
+static int hdmi_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &hdmi_component_ops);
+}
+
+static int hdmi_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &hdmi_component_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ce28881..d46a262 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -31,6 +31,7 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
 }
 
 static int mixer_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	int ret;
 	struct mixer_context *mixer_ctx = mgr->ctx;
+	struct exynos_drm_private *priv;
+	priv = drm_dev->dev_private;
 
-	mixer_ctx->drm_dev = drm_dev;
-	mixer_ctx->pipe = pipe;
+	mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
+	mgr->pipe = mixer_ctx->pipe = priv->pipe++;
 
 	/* acquire resources: regs, irqs, clocks */
 	ret = mixer_resources_init(mixer_ctx);
@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode)
 }
 
 static struct exynos_drm_manager_ops mixer_manager_ops = {
-	.initialize		= mixer_initialize,
-	.remove			= mixer_mgr_remove,
 	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = {
 	}
 };
 
-static int mixer_probe(struct platform_device *pdev)
+static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
-	struct device *dev = &pdev->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct mixer_context *ctx;
 	struct mixer_drv_data *drv;
+	int ret;
 
 	dev_info(dev, "probe start\n");
 
@@ -1233,20 +1236,49 @@ static int mixer_probe(struct platform_device *pdev)
 	atomic_set(&ctx->wait_vsync_event, 0);
 
 	mixer_manager.ctx = ctx;
+	ret = mixer_initialize(&mixer_manager, drm_dev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, &mixer_manager);
-	exynos_drm_manager_register(&mixer_manager);
+	ret = exynos_drm_crtc_create(&mixer_manager);
+	if (ret) {
+		mixer_mgr_remove(&mixer_manager);
+		return ret;
+	}
 
 	pm_runtime_enable(dev);
 
 	return 0;
 }
 
-static int mixer_remove(struct platform_device *pdev)
+static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
-	dev_info(&pdev->dev, "remove successful\n");
+	struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
+	struct drm_crtc *crtc = mgr->crtc;
+
+	dev_info(dev, "remove successful\n");
+
+	mixer_mgr_remove(mgr);
 
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
 
+	crtc->funcs->destroy(crtc);
+}
+
+static const struct component_ops mixer_component_ops = {
+	.bind	= mixer_bind,
+	.unbind	= mixer_unbind,
+};
+
+static int mixer_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &mixer_component_ops);
+}
+
+static int mixer_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &mixer_component_ops);
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH v4] drm/exynos: add super device support
  2014-04-03  8:36   ` [PATCH v3] " Inki Dae
@ 2014-04-03 11:47     ` Inki Dae
  2014-04-03 14:26       ` [PATCH] drm/exynos: separate dpi from fimd Andrzej Hajda
  0 siblings, 1 reply; 47+ messages in thread
From: Inki Dae @ 2014-04-03 11:47 UTC (permalink / raw)
  To: airlied, dri-devel; +Cc: a.hajda, kyungmin.park

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.

Previous RFC patch,
	 http://www.spinics.net/lists/dri-devel/msg54671.html

Changelog since RFC patch:
- Register sub drivers and probe them at load(). In case of non sub
  drivers, sub driver probe is needed.
- Enable runtime pm at fimd_probe() instead of fimd_bind(). runtime pm
  should be enabled before iommu device is attached to fimd device.
- Do not return an error with component_master_add fail.
- Remove super device support from mipi dsi driver which was in RFC.
- Add super device support to parallel driver.

Changelog v2:
- Add super device support to mipi dsi driver.
- Bind fimd driver only in case that a drm_panel for parallel panel driver
  is added to panel_list of drm_panel module.
- Change super node name to 'display-subsystem'
  . 'exynos-drm' is specific to Linux so change it to generic name.
- Change propery name of super node to 'ports'
  . crtcs and connectors propery names are also specific to Linux so
    change them to generic name.

Changlog v3:
- Do not probe/remove dpi module if fimd node has no port node.

Changelog v4:
- Move some codes for getting resources from each bind function to
  each probe function.
  . if -EPROBE_DEFER is returned at bind context, components will be
    bound and unbound repeatedly by deferred probe feature.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
 drivers/gpu/drm/exynos/exynos_dp_core.c  |   45 ++++---
 drivers/gpu/drm/exynos/exynos_drm_core.c |  216 +++++-------------------------
 drivers/gpu/drm/exynos/exynos_drm_crtc.c |   17 +++
 drivers/gpu/drm/exynos/exynos_drm_crtc.h |    4 +
 drivers/gpu/drm/exynos/exynos_drm_dpi.c  |   16 ++-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  202 +++++++++++++++-------------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |   73 +++++-----
 drivers/gpu/drm/exynos/exynos_drm_dsi.c  |  110 +++++++++------
 drivers/gpu/drm/exynos/exynos_drm_fimd.c |   87 +++++++++---
 drivers/gpu/drm/exynos/exynos_drm_vidi.c |   61 +++++++--
 drivers/gpu/drm/exynos/exynos_hdmi.c     |   59 +++++---
 drivers/gpu/drm/exynos/exynos_mixer.c    |   54 ++++++--
 12 files changed, 499 insertions(+), 445 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index a59bca9..cb9aa58 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <linux/component.h>
 #include <linux/phy/phy.h>
 #include <video/of_display_timing.h>
 #include <video/of_videomode.h>
@@ -969,16 +970,6 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
 	.best_encoder = exynos_dp_best_encoder,
 };
 
-static int exynos_dp_initialize(struct exynos_drm_display *display,
-				struct drm_device *drm_dev)
-{
-	struct exynos_dp_device *dp = display->ctx;
-
-	dp->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static bool find_bridge(const char *compat, struct bridge_init *bridge)
 {
 	bridge->client = NULL;
@@ -1106,7 +1097,6 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops exynos_dp_display_ops = {
-	.initialize = exynos_dp_initialize,
 	.create_connector = exynos_dp_create_connector,
 	.dpms = exynos_dp_dpms,
 };
@@ -1230,8 +1220,10 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 	return 0;
 }
 
-static int exynos_dp_probe(struct platform_device *pdev)
+static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct resource *res;
 	struct exynos_dp_device *dp;
 
@@ -1293,21 +1285,40 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	}
 	disable_irq(dp->irq);
 
+	dp->drm_dev = drm_dev;
 	exynos_dp_display.ctx = dp;
 
 	platform_set_drvdata(pdev, &exynos_dp_display);
-	exynos_drm_display_register(&exynos_dp_display);
 
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dp_display);
 }
 
-static int exynos_dp_remove(struct platform_device *pdev)
+static void exynos_dp_unbind(struct device *dev, struct device *master,
+				void *data)
 {
-	struct exynos_drm_display *display = platform_get_drvdata(pdev);
+	struct exynos_drm_display *display = dev_get_drvdata(dev);
+	struct exynos_dp_device *dp = display->ctx;
+	struct drm_encoder *encoder = dp->encoder;
 
 	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dp_display);
 
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dp->connector);
+}
+
+static const struct component_ops exynos_dp_ops = {
+	.bind	= exynos_dp_bind,
+	.unbind	= exynos_dp_unbind,
+};
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &exynos_dp_ops);
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &exynos_dp_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 0e9e06c..4c9f972 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -19,21 +19,19 @@
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
-static LIST_HEAD(exynos_drm_manager_list);
-static LIST_HEAD(exynos_drm_display_list);
 
-static int exynos_drm_create_enc_conn(struct drm_device *dev,
+int exynos_drm_create_enc_conn(struct drm_device *dev,
 					struct exynos_drm_display *display)
 {
 	struct drm_encoder *encoder;
-	struct exynos_drm_manager *manager;
 	int ret;
 	unsigned long possible_crtcs = 0;
 
-	/* Find possible crtcs for this display */
-	list_for_each_entry(manager, &exynos_drm_manager_list, list)
-		if (manager->type == display->type)
-			possible_crtcs |= 1 << manager->pipe;
+	ret = exynos_drm_crtc_get_pipe_from_type(dev, display->type);
+	if (ret < 0)
+		return ret;
+
+	possible_crtcs |= 1 << ret;
 
 	/* create and initialize a encoder for this sub driver. */
 	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
@@ -57,127 +55,29 @@ err_destroy_encoder:
 	return ret;
 }
 
-static int exynos_drm_subdrv_probe(struct drm_device *dev,
-					struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->probe) {
-		int ret;
-
-		subdrv->drm_dev = dev;
-
-		/*
-		 * this probe callback would be called by sub driver
-		 * after setting of all resources to this sub driver,
-		 * such as clock, irq and register map are done or by load()
-		 * of exynos drm driver.
-		 *
-		 * P.S. note that this driver is considered for modularization.
-		 */
-		ret = subdrv->probe(dev, subdrv->dev);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
-static void exynos_drm_subdrv_remove(struct drm_device *dev,
-				      struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->remove)
-		subdrv->remove(dev, subdrv->dev);
-}
-
-int exynos_drm_initialize_managers(struct drm_device *dev)
+int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_manager *manager, *n;
-	int ret, pipe = 0;
-
-	list_for_each_entry(manager, &exynos_drm_manager_list, list) {
-		if (manager->ops->initialize) {
-			ret = manager->ops->initialize(manager, dev, pipe);
-			if (ret) {
-				DRM_ERROR("Mgr init [%d] failed with %d\n",
-						manager->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		manager->drm_dev = dev;
-		manager->pipe = pipe++;
+	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
 
-		ret = exynos_drm_crtc_create(manager);
-		if (ret) {
-			DRM_ERROR("CRTC create [%d] failed with %d\n",
-					manager->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
-		if (pipe-- > 0)
-			exynos_drm_manager_unregister(manager);
-		else
-			list_del(&manager->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_managers(struct drm_device *dev)
-{
-	struct exynos_drm_manager *manager, *n;
-
-	list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
-		exynos_drm_manager_unregister(manager);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
 
-int exynos_drm_initialize_displays(struct drm_device *dev)
+int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
 {
-	struct exynos_drm_display *display, *n;
-	int ret, initialized = 0;
-
-	list_for_each_entry(display, &exynos_drm_display_list, list) {
-		if (display->ops->initialize) {
-			ret = display->ops->initialize(display, dev);
-			if (ret) {
-				DRM_ERROR("Display init [%d] failed with %d\n",
-						display->type, ret);
-				goto err;
-			}
-		}
+	if (!subdrv)
+		return -EINVAL;
 
-		initialized++;
+	list_del(&subdrv->list);
 
-		ret = exynos_drm_create_enc_conn(dev, display);
-		if (ret) {
-			DRM_ERROR("Encoder create [%d] failed with %d\n",
-					display->type, ret);
-			goto err;
-		}
-	}
 	return 0;
-
-err:
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
-		if (initialized-- > 0)
-			exynos_drm_display_unregister(display);
-		else
-			list_del(&display->list);
-	}
-	return ret;
-}
-
-void exynos_drm_remove_displays(struct drm_device *dev)
-{
-	struct exynos_drm_display *display, *n;
-
-	list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
-		exynos_drm_display_unregister(display);
 }
+EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
 
-int exynos_drm_device_register(struct drm_device *dev)
+int exynos_drm_device_subdrv_probe(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv, *n;
 	int err;
@@ -186,19 +86,28 @@ int exynos_drm_device_register(struct drm_device *dev)
 		return -EINVAL;
 
 	list_for_each_entry_safe(subdrv, n, &exynos_drm_subdrv_list, list) {
-		err = exynos_drm_subdrv_probe(dev, subdrv);
-		if (err) {
-			DRM_DEBUG("exynos drm subdrv probe failed.\n");
-			list_del(&subdrv->list);
-			continue;
+		if (subdrv->probe) {
+			subdrv->drm_dev = dev;
+
+			/*
+			 * this probe callback would be called by sub driver
+			 * after setting of all resources to this sub driver,
+			 * such as clock, irq and register map are done.
+			 */
+			err = subdrv->probe(dev, subdrv->dev);
+			if (err) {
+				DRM_DEBUG("exynos drm subdrv probe failed.\n");
+				list_del(&subdrv->list);
+				continue;
+			}
 		}
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_register);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_probe);
 
-int exynos_drm_device_unregister(struct drm_device *dev)
+int exynos_drm_device_subdrv_remove(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv;
 
@@ -208,66 +117,13 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 	}
 
 	list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
-		exynos_drm_subdrv_remove(dev, subdrv);
+		if (subdrv->remove)
+			subdrv->remove(dev, subdrv->dev);
 	}
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager)
-{
-	BUG_ON(!manager->ops);
-	list_add_tail(&manager->list, &exynos_drm_manager_list);
-	return 0;
-}
-
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
-{
-	if (manager->ops->remove)
-		manager->ops->remove(manager);
-
-	list_del(&manager->list);
-	return 0;
-}
-
-int exynos_drm_display_register(struct exynos_drm_display *display)
-{
-	BUG_ON(!display->ops);
-	list_add_tail(&display->list, &exynos_drm_display_list);
-	return 0;
-}
-
-int exynos_drm_display_unregister(struct exynos_drm_display *display)
-{
-	if (display->ops->remove)
-		display->ops->remove(display);
-
-	list_del(&display->list);
-	return 0;
-}
-
-int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_add_tail(&subdrv->list, &exynos_drm_subdrv_list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_register);
-
-int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
-{
-	if (!subdrv)
-		return -EINVAL;
-
-	list_del(&subdrv->list);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(exynos_drm_subdrv_unregister);
+EXPORT_SYMBOL_GPL(exynos_drm_device_subdrv_remove);
 
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file)
 {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 9cc92ae..c197b99 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -367,6 +367,7 @@ int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 		return -ENOMEM;
 	}
 
+	manager->crtc = &exynos_crtc->drm_crtc;
 	crtc = &exynos_crtc->drm_crtc;
 
 	private->crtc[manager->pipe] = crtc;
@@ -490,3 +491,19 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
 			manager->ops->wait_for_vblank(manager);
 	}
 }
+
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type)
+{
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
+		struct exynos_drm_crtc *exynos_crtc;
+
+		exynos_crtc = to_exynos_crtc(crtc);
+		if (exynos_crtc->manager->type == out_type)
+			return exynos_crtc->manager->pipe;
+	}
+
+	return -EPERM;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index c27b66c..9f74b10 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -32,4 +32,8 @@ void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
 void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
 
+/* This function gets pipe value to crtc device matched with out_type. */
+int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
+					unsigned int out_type);
+
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index 2b09c7c..c1f4b35 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -255,7 +255,7 @@ enum {
 	FIMD_PORT_WRB,
 };
 
-static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
 {
 	struct device_node *np, *ep;
 
@@ -308,7 +308,7 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 	return 0;
 }
 
-int exynos_dpi_probe(struct device *dev)
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
 {
 	struct exynos_dpi *ctx;
 	int ret;
@@ -325,15 +325,17 @@ int exynos_dpi_probe(struct device *dev)
 	if (ret < 0)
 		return ret;
 
-	exynos_drm_display_register(&exynos_dpi_display);
-
-	return 0;
+	return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
 }
 
-int exynos_dpi_remove(struct device *dev)
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
 {
+	struct drm_encoder *encoder = exynos_dpi_display.encoder;
+	struct exynos_dpi *ctx = exynos_dpi_display.ctx;
+
 	exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
-	exynos_drm_display_unregister(&exynos_dpi_display);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 2d27ba2..f065385 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -16,6 +16,7 @@
 #include <drm/drm_crtc_helper.h>
 
 #include <linux/anon_inodes.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -40,9 +41,6 @@
 
 #define VBLANK_OFF_DELAY	50000
 
-/* platform device pointer for eynos drm device. */
-static struct platform_device *exynos_drm_pdev;
-
 static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 {
 	struct exynos_drm_private *private;
@@ -73,38 +71,21 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	exynos_drm_mode_config_init(dev);
 
-	ret = exynos_drm_initialize_managers(dev);
-	if (ret)
-		goto err_mode_config_cleanup;
-
 	for (nr = 0; nr < MAX_PLANE; nr++) {
 		struct drm_plane *plane;
 		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
 		plane = exynos_plane_init(dev, possible_crtcs, false);
 		if (!plane)
-			goto err_manager_cleanup;
+			goto err_mode_config_cleanup;
 	}
 
-	ret = exynos_drm_initialize_displays(dev);
-	if (ret)
-		goto err_manager_cleanup;
-
 	/* init kms poll for handling hpd */
 	drm_kms_helper_poll_init(dev);
 
 	ret = drm_vblank_init(dev, MAX_CRTC);
 	if (ret)
-		goto err_display_cleanup;
-
-	/*
-	 * probe sub drivers such as display controller and hdmi driver,
-	 * that were registered at probe() of platform driver
-	 * to the sub driver and create encoder and connector for them.
-	 */
-	ret = exynos_drm_device_register(dev);
-	if (ret)
-		goto err_vblank;
+		goto err_mode_config_cleanup;
 
 	/* setup possible_clones. */
 	exynos_drm_encoder_setup(dev);
@@ -113,17 +94,35 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	platform_set_drvdata(dev->platformdev, dev);
 
+	/* Try to bind all sub drivers. */
+	ret = component_bind_all(dev->dev, dev);
+	if (ret)
+		goto err_cleanup_vblank;
+
+	/* Probe non kms sub drivers. */
+	ret = exynos_drm_device_subdrv_probe(dev);
+	if (ret)
+		goto err_unbind_all;
+
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+	ret = exynos_drm_probe_vidi(dev);
+	if (ret < 0)
+		goto err_remove_subdrv;
+#endif
+
 	/* force connectors detection */
 	drm_helper_hpd_irq_event(dev);
 
 	return 0;
 
-err_vblank:
+#ifdef CONFIG_DRM_EXYNOS_VIDI
+err_remove_subdrv:
+	exynos_drm_device_subdrv_remove(dev);
+#endif
+err_unbind_all:
+	component_unbind_all(dev->dev, dev);
+err_cleanup_vblank:
 	drm_vblank_cleanup(dev);
-err_display_cleanup:
-	exynos_drm_remove_displays(dev);
-err_manager_cleanup:
-	exynos_drm_remove_managers(dev);
 err_mode_config_cleanup:
 	drm_mode_config_cleanup(dev);
 	drm_release_iommu_mapping(dev);
@@ -135,17 +134,17 @@ err_free_private:
 
 static int exynos_drm_unload(struct drm_device *dev)
 {
+	exynos_drm_device_subdrv_remove(dev);
+
 	exynos_drm_fbdev_fini(dev);
-	exynos_drm_device_unregister(dev);
 	drm_vblank_cleanup(dev);
 	drm_kms_helper_poll_fini(dev);
-	exynos_drm_remove_displays(dev);
-	exynos_drm_remove_managers(dev);
 	drm_mode_config_cleanup(dev);
 
 	drm_release_iommu_mapping(dev);
 	kfree(dev->dev_private);
 
+	component_unbind_all(dev->dev, dev);
 	dev->dev_private = NULL;
 
 	return 0;
@@ -355,27 +354,6 @@ static struct drm_driver exynos_drm_driver = {
 	.minor	= DRIVER_MINOR,
 };
 
-static int exynos_drm_platform_probe(struct platform_device *pdev)
-{
-	int ret;
-
-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	pm_runtime_enable(&pdev->dev);
-	pm_runtime_get_sync(&pdev->dev);
-
-	return drm_platform_init(&exynos_drm_driver, pdev);
-}
-
-static int exynos_drm_platform_remove(struct platform_device *pdev)
-{
-	drm_put_dev(platform_get_drvdata(pdev));
-
-	return 0;
-}
-
 #ifdef CONFIG_PM_SLEEP
 static int exynos_drm_sys_suspend(struct device *dev)
 {
@@ -430,20 +408,66 @@ static const struct dev_pm_ops exynos_drm_pm_ops = {
 			exynos_drm_runtime_resume, NULL)
 };
 
-static struct platform_driver exynos_drm_platform_driver = {
-	.probe		= exynos_drm_platform_probe,
-	.remove		= exynos_drm_platform_remove,
-	.driver		= {
-		.owner	= THIS_MODULE,
-		.name	= "exynos-drm",
-		.pm	= &exynos_drm_pm_ops,
-	},
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int exynos_drm_add_components(struct device *dev, struct master *m)
+{
+	struct device_node *np = dev->of_node;
+	unsigned int i;
+
+	for (i = 0;; i++) {
+		struct device_node *node;
+		int ret;
+
+		node = of_parse_phandle(np, "ports", i);
+		if (!node)
+			break;
+
+		ret = component_master_add_child(m, compare_of, node);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int exynos_drm_bind(struct device *dev)
+{
+	int ret;
+
+	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	pm_runtime_enable(dev);
+	pm_runtime_get_sync(dev);
+
+	return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
+}
+
+static void exynos_drm_unbind(struct device *dev)
+{
+	drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops exynos_drm_ops = {
+	.add_components = exynos_drm_add_components,
+	.bind		= exynos_drm_bind,
+	.unbind		= exynos_drm_unbind,
 };
 
-static int __init exynos_drm_init(void)
+static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
 	int ret;
 
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+	exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls);
+
 #ifdef CONFIG_DRM_EXYNOS_DP
 	ret = platform_driver_register(&dp_driver);
 	if (ret < 0)
@@ -471,12 +495,6 @@ static int __init exynos_drm_init(void)
 		goto out_mixer;
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	ret = platform_driver_register(&vidi_driver);
-	if (ret < 0)
-		goto out_vidi;
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_G2D
 	ret = platform_driver_register(&g2d_driver);
 	if (ret < 0)
@@ -511,23 +529,12 @@ static int __init exynos_drm_init(void)
 		goto out_ipp_dev;
 #endif
 
-	ret = platform_driver_register(&exynos_drm_platform_driver);
+	ret = component_master_add(&pdev->dev, &exynos_drm_ops);
 	if (ret < 0)
-		goto out_drm;
-
-	exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
-				NULL, 0);
-	if (IS_ERR(exynos_drm_pdev)) {
-		ret = PTR_ERR(exynos_drm_pdev);
-		goto out;
-	}
+		DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
 
 	return 0;
 
-out:
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
-out_drm:
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 out_ipp_dev:
@@ -555,11 +562,6 @@ out_fimc:
 out_g2d:
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-out_vidi:
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_HDMI
 	platform_driver_unregister(&mixer_driver);
 out_mixer:
@@ -584,12 +586,8 @@ out_dp:
 	return ret;
 }
 
-static void __exit exynos_drm_exit(void)
+static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-	platform_device_unregister(exynos_drm_pdev);
-
-	platform_driver_unregister(&exynos_drm_platform_driver);
-
 #ifdef CONFIG_DRM_EXYNOS_IPP
 	exynos_platform_device_ipp_unregister();
 	platform_driver_unregister(&ipp_driver);
@@ -616,10 +614,6 @@ static void __exit exynos_drm_exit(void)
 	platform_driver_unregister(&hdmi_driver);
 #endif
 
-#ifdef CONFIG_DRM_EXYNOS_VIDI
-	platform_driver_unregister(&vidi_driver);
-#endif
-
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	platform_driver_unregister(&fimd_driver);
 #endif
@@ -631,10 +625,28 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_DP
 	platform_driver_unregister(&dp_driver);
 #endif
+	component_master_del(&pdev->dev, &exynos_drm_ops);
+	return 0;
 }
 
-module_init(exynos_drm_init);
-module_exit(exynos_drm_exit);
+static const struct of_device_id exynos_drm_dt_match[] = {
+	{ .compatible = "samsung,exynos-display-subsystem", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, exynos_drm_dt_match);
+
+static struct platform_driver exynos_drm_platform_driver = {
+	.probe	= exynos_drm_platform_probe,
+	.remove	= exynos_drm_platform_remove,
+	.driver	= {
+		.owner	= THIS_MODULE,
+		.name	= "exynos-drm",
+		.pm	= &exynos_drm_pm_ops,
+		.of_match_table	= exynos_drm_dt_match,
+	},
+};
+module_platform_driver(exynos_drm_platform_driver);
 
 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 4c5cf68..25d562f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -122,7 +122,6 @@ struct exynos_drm_overlay {
  * Exynos DRM Display Structure.
  *	- this structure is common to analog tv, digital tv and lcd panel.
  *
- * @initialize: initializes the display with drm_dev
  * @remove: cleans up the display for removal
  * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
@@ -133,8 +132,6 @@ struct exynos_drm_overlay {
  */
 struct exynos_drm_display;
 struct exynos_drm_display_ops {
-	int (*initialize)(struct exynos_drm_display *display,
-				struct drm_device *drm_dev);
 	int (*create_connector)(struct exynos_drm_display *display,
 				struct drm_encoder *encoder);
 	void (*remove)(struct exynos_drm_display *display);
@@ -172,8 +169,6 @@ struct exynos_drm_display {
 /*
  * Exynos drm manager ops
  *
- * @initialize: initializes the manager with drm_dev
- * @remove: cleans up the manager for removal
  * @dpms: control device power.
  * @mode_fixup: fix mode data before applying it
  * @mode_set: set the given mode to the manager
@@ -189,9 +184,6 @@ struct exynos_drm_display {
  */
 struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
-	int (*initialize)(struct exynos_drm_manager *mgr,
-				struct drm_device *drm_dev, int pipe);
-	void (*remove)(struct exynos_drm_manager *mgr);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
 	bool (*mode_fixup)(struct exynos_drm_manager *mgr,
 				const struct drm_display_mode *mode,
@@ -215,6 +207,7 @@ struct exynos_drm_manager_ops {
  * @list: the list entry for this manager
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @drm_dev: pointer to the drm device
+ * @crtc: crtc object.
  * @pipe: the pipe number for this crtc/manager
  * @ops: pointer to callbacks for exynos drm specific functionality
  * @ctx: A pointer to the manager's implementation specific context
@@ -223,6 +216,7 @@ struct exynos_drm_manager {
 	struct list_head list;
 	enum exynos_drm_output_type type;
 	struct drm_device *drm_dev;
+	struct drm_crtc *crtc;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
 	void *ctx;
@@ -255,6 +249,7 @@ struct drm_exynos_file_private {
  * @da_space_size: size of device address space.
  *	if 0 then default value is used for it.
  * @da_space_order: order to device address space.
+ * @pipe: the pipe number for this crtc/manager.
  */
 struct exynos_drm_private {
 	struct drm_fb_helper *fb_helper;
@@ -273,6 +268,8 @@ struct exynos_drm_private {
 	unsigned long da_start;
 	unsigned long da_space_size;
 	unsigned long da_space_order;
+
+	unsigned int pipe;
 };
 
 /*
@@ -283,11 +280,11 @@ struct exynos_drm_private {
  * @drm_dev: pointer to drm_device and this pointer would be set
  *	when sub driver calls exynos_drm_subdrv_register().
  * @manager: subdrv has its own manager to control a hardware appropriately
- *	and we can access a hardware drawing on this manager.
+ *     and we can access a hardware drawing on this manager.
  * @probe: this callback would be called by exynos drm driver after
- *	subdrv is registered to it.
+ *     subdrv is registered to it.
  * @remove: this callback is used to release resources created
- *	by probe callback.
+ *     by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
  */
@@ -304,39 +301,14 @@ struct exynos_drm_subdrv {
 			struct drm_file *file);
 };
 
-/*
- * this function calls a probe callback registered to sub driver list and
- * create its own encoder and connector and then set drm_device object
- * to global one.
- */
-int exynos_drm_device_register(struct drm_device *dev);
-/*
- * this function calls a remove callback registered to sub driver list and
- * destroy its own encoder and connetor.
- */
-int exynos_drm_device_unregister(struct drm_device *dev);
-
-int exynos_drm_initialize_managers(struct drm_device *dev);
-void exynos_drm_remove_managers(struct drm_device *dev);
-int exynos_drm_initialize_displays(struct drm_device *dev);
-void exynos_drm_remove_displays(struct drm_device *dev);
-
-int exynos_drm_manager_register(struct exynos_drm_manager *manager);
-int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
-int exynos_drm_display_register(struct exynos_drm_display *display);
-int exynos_drm_display_unregister(struct exynos_drm_display *display);
-
-/*
- * this function would be called by sub drivers such as display controller
- * or hdmi driver to register this sub driver object to exynos drm driver
- * and when a sub driver is registered to exynos drm driver a probe callback
- * of the sub driver is called and creates its own encoder and connector.
- */
+ /* This function would be called by non kms drivers such as g2d and ipp. */
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *drm_subdrv);
 
 /* this function removes subdrv list from exynos drm driver */
 int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *drm_subdrv);
 
+int exynos_drm_device_subdrv_probe(struct drm_device *dev);
+int exynos_drm_device_subdrv_remove(struct drm_device *dev);
 int exynos_drm_subdrv_open(struct drm_device *dev, struct drm_file *file);
 void exynos_drm_subdrv_close(struct drm_device *dev, struct drm_file *file);
 
@@ -362,13 +334,28 @@ int exynos_platform_device_ipp_register(void);
 void exynos_platform_device_ipp_unregister(void);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
-int exynos_dpi_probe(struct device *dev);
-int exynos_dpi_remove(struct device *dev);
+int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
+int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
+struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
 #else
-static inline int exynos_dpi_probe(struct device *dev) { return 0; }
-static inline int exynos_dpi_remove(struct device *dev) { return 0; }
+static inline int exynos_dpi_probe(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct drm_device *drm_dev,
+					struct device *dev) { return 0; }
+static inline struct device_node
+			*exynos_dpi_of_find_panel_node(struct device *dev)
+{ return NULL; }
 #endif
 
+/*
+ * this function registers exynos drm vidi platform device.
+ */
+int exynos_drm_probe_vidi(struct drm_device *dev);
+
+/* This function creates a encoder and a connector, and initializes them. */
+int exynos_drm_create_enc_conn(struct drm_device *dev,
+				struct exynos_drm_display *display);
+
 extern struct platform_driver dp_driver;
 extern struct platform_driver dsi_driver;
 extern struct platform_driver fimd_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index 697228e..9cdfbc8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -19,6 +19,7 @@
 #include <linux/irq.h>
 #include <linux/phy/phy.h>
 #include <linux/regulator/consumer.h>
+#include <linux/component.h>
 
 #include <video/mipi_display.h>
 #include <video/videomode.h>
@@ -1378,6 +1379,74 @@ end:
 	return ret;
 }
 
+static int exynos_dsi_bind(struct device *dev, struct device *master,
+				void *data)
+{
+	struct drm_device *drm_dev = data;
+	struct exynos_dsi *dsi;
+	int ret;
+
+	ret = exynos_drm_create_enc_conn(drm_dev, &exynos_dsi_display);
+	if (ret) {
+		DRM_ERROR("Encoder create [%d] failed with %d\n",
+				exynos_dsi_display.type, ret);
+		return ret;
+	}
+
+	dsi = exynos_dsi_display.ctx;
+
+	return mipi_dsi_host_register(&dsi->dsi_host);
+}
+
+static void exynos_dsi_unbind(struct device *dev, struct device *master,
+				void *data)
+{
+	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+	struct drm_encoder *encoder = dsi->encoder;
+
+	exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
+
+	mipi_dsi_host_unregister(&dsi->dsi_host);
+
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&dsi->connector);
+}
+
+#if CONFIG_PM_SLEEP
+static int exynos_dsi_resume(struct device *dev)
+{
+	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+
+	if (dsi->state & DSIM_STATE_ENABLED) {
+		dsi->state &= ~DSIM_STATE_ENABLED;
+		exynos_dsi_enable(dsi);
+	}
+
+	return 0;
+}
+
+static int exynos_dsi_suspend(struct device *dev)
+{
+	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+
+	if (dsi->state & DSIM_STATE_ENABLED) {
+		exynos_dsi_disable(dsi);
+		dsi->state |= DSIM_STATE_ENABLED;
+	}
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dsi_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
+};
+
+static const struct component_ops exynos_dsi_component_ops = {
+	.bind	= exynos_dsi_bind,
+	.unbind	= exynos_dsi_unbind,
+};
+
 static int exynos_dsi_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1455,53 +1524,16 @@ static int exynos_dsi_probe(struct platform_device *pdev)
 	exynos_dsi_display.ctx = dsi;
 
 	platform_set_drvdata(pdev, &exynos_dsi_display);
-	exynos_drm_display_register(&exynos_dsi_display);
 
-	return mipi_dsi_host_register(&dsi->dsi_host);
+	return component_add(&pdev->dev, &exynos_dsi_component_ops);
 }
 
 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_display_unregister(&exynos_dsi_display);
-	mipi_dsi_host_unregister(&dsi->dsi_host);
-
+	component_del(&pdev->dev, &exynos_dsi_component_ops);
 	return 0;
 }
 
-#if CONFIG_PM_SLEEP
-static int exynos_dsi_resume(struct device *dev)
-{
-	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
-
-	if (dsi->state & DSIM_STATE_ENABLED) {
-		dsi->state &= ~DSIM_STATE_ENABLED;
-		exynos_dsi_enable(dsi);
-	}
-
-	return 0;
-}
-
-static int exynos_dsi_suspend(struct device *dev)
-{
-	struct exynos_dsi *dsi = exynos_dsi_display.ctx;
-
-	if (dsi->state & DSIM_STATE_ENABLED) {
-		exynos_dsi_disable(dsi);
-		dsi->state |= DSIM_STATE_ENABLED;
-	}
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops exynos_dsi_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
-};
-
 static struct of_device_id exynos_dsi_of_match[] = {
 	{ .compatible = "samsung,exynos4210-mipi-dsi" },
 	{ }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 40fd6cc..b26b27e 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,10 +851,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;
@@ -910,11 +914,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);
-
-	exynos_dpi_probe(ctx->dev);
-
-	pm_runtime_enable(dev);
+	fimd_mgr_initialize(&fimd_manager, drm_dev);
+
+	exynos_drm_crtc_create(&fimd_manager);
+
+	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);
@@ -922,18 +934,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;
 
-	exynos_dpi_remove(&pdev->dev);
+	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
-	exynos_drm_manager_unregister(&fimd_manager);
+	dn = exynos_dpi_of_find_panel_node(dev);
+	if (dn)
+		exynos_dpi_remove(mgr->drm_dev, dev);
 
-	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
+	fimd_mgr_remove(mgr);
+
+	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 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;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 7afead9..22076e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -65,6 +65,8 @@ struct vidi_context {
 	int				pipe;
 };
 
+static struct drm_device *drm_dev;
+
 static const char fake_edid_info[] = {
 	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
 	0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
@@ -294,14 +296,15 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
 }
 
 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	struct vidi_context *ctx = mgr->ctx;
+	struct exynos_drm_private *priv = drm_dev->dev_private;
 
-	DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
+	DRM_DEBUG_KMS("vidi initialize ctx=%p dev=%p\n", ctx, drm_dev);
 
-	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.
@@ -324,7 +327,6 @@ static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
 }
 
 static struct exynos_drm_manager_ops vidi_manager_ops = {
-	.initialize = vidi_mgr_initialize,
 	.dpms = vidi_dpms,
 	.commit = vidi_commit,
 	.enable_vblank = vidi_enable_vblank,
@@ -588,11 +590,14 @@ static struct exynos_drm_display vidi_display = {
 
 static int vidi_probe(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
 	struct vidi_context *ctx;
 	int ret;
 
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+	/* drm_dev shouldn't be NULL. */
+	if (!drm_dev)
+		return -EFAULT;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
 		return -ENOMEM;
 
@@ -603,32 +608,40 @@ static int vidi_probe(struct platform_device *pdev)
 	vidi_manager.ctx = ctx;
 	vidi_display.ctx = ctx;
 
+	vidi_mgr_initialize(&vidi_manager, drm_dev);
+
 	mutex_init(&ctx->lock);
 
 	platform_set_drvdata(pdev, &vidi_manager);
 
-	ret = device_create_file(dev, &dev_attr_connection);
+	ret = device_create_file(&pdev->dev, &dev_attr_connection);
 	if (ret < 0)
 		DRM_INFO("failed to create connection sysfs.\n");
 
-	exynos_drm_manager_register(&vidi_manager);
-	exynos_drm_display_register(&vidi_display);
+	exynos_drm_crtc_create(&vidi_manager);
+	exynos_drm_create_enc_conn(drm_dev, &vidi_display);
 
 	return 0;
 }
 
 static int vidi_remove(struct platform_device *pdev)
 {
-	struct vidi_context *ctx = platform_get_drvdata(pdev);
-
-	exynos_drm_display_unregister(&vidi_display);
-	exynos_drm_manager_unregister(&vidi_manager);
+	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
+	struct vidi_context *ctx = mgr->ctx;
+	struct drm_encoder *encoder = ctx->encoder;
+	struct drm_crtc *crtc = mgr->crtc;
 
 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
 		kfree(ctx->raw_edid);
 		ctx->raw_edid = NULL;
+
+		return -EINVAL;
 	}
 
+	crtc->funcs->destroy(crtc);
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&ctx->connector);
+
 	return 0;
 }
 
@@ -640,3 +653,23 @@ struct platform_driver vidi_driver = {
 		.owner	= THIS_MODULE,
 	},
 };
+
+int exynos_drm_probe_vidi(struct drm_device *dev)
+{
+	struct platform_device *pdev;
+	int ret;
+
+	drm_dev = dev;
+
+	pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
+	if (IS_ERR(pdev))
+		return PTR_ERR(pdev);
+
+	ret = platform_driver_register(&vidi_driver);
+	if (ret) {
+		platform_device_unregister(pdev);
+		return ret;
+	}
+
+	return ret;
+}
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 9a6d652..de23090 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -36,10 +36,12 @@
 #include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/hdmi.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_mixer.h"
 
 #include <linux/gpio.h>
@@ -928,16 +930,6 @@ static int hdmi_create_connector(struct exynos_drm_display *display,
 	return 0;
 }
 
-static int hdmi_initialize(struct exynos_drm_display *display,
-			struct drm_device *drm_dev)
-{
-	struct hdmi_context *hdata = display->ctx;
-
-	hdata->drm_dev = drm_dev;
-
-	return 0;
-}
-
 static void hdmi_mode_fixup(struct exynos_drm_display *display,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
@@ -1913,7 +1905,6 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 }
 
 static struct exynos_drm_display_ops hdmi_display_ops = {
-	.initialize	= hdmi_initialize,
 	.create_connector = hdmi_create_connector,
 	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
@@ -2047,18 +2038,44 @@ static struct of_device_id hdmi_match_types[] = {
 	}
 };
 
+static int hdmi_bind(struct device *dev, struct device *master, void *data)
+{
+	struct drm_device *drm_dev = data;
+	struct hdmi_context *hdata;
+
+	hdata = hdmi_display.ctx;
+	hdata->drm_dev = drm_dev;
+
+	return exynos_drm_create_enc_conn(drm_dev, &hdmi_display);
+}
+
+static void hdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct drm_encoder *encoder = display->encoder;
+	struct hdmi_context *hdata = display->ctx;
+
+	encoder->funcs->destroy(encoder);
+	drm_connector_cleanup(&hdata->connector);
+}
+
+static const struct component_ops hdmi_component_ops = {
+	.bind	= hdmi_bind,
+	.unbind = hdmi_unbind,
+};
+
 static int hdmi_probe(struct platform_device *pdev)
 {
+	struct device_node *ddc_node, *phy_node;
+	struct s5p_hdmi_platform_data *pdata;
+	struct hdmi_driver_data *drv_data;
+	const struct of_device_id *match;
 	struct device *dev = &pdev->dev;
 	struct hdmi_context *hdata;
-	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
-	const struct of_device_id *match;
-	struct device_node *ddc_node, *phy_node;
-	struct hdmi_driver_data *drv_data;
 	int ret;
 
-	 if (!dev->of_node)
+	if (!dev->of_node)
 		return -ENODEV;
 
 	pdata = drm_hdmi_dt_parse_pdata(dev);
@@ -2149,11 +2166,9 @@ static int hdmi_probe(struct platform_device *pdev)
 	}
 
 	pm_runtime_enable(dev);
-
 	hdmi_display.ctx = hdata;
-	exynos_drm_display_register(&hdmi_display);
 
-	return 0;
+	return component_add(&pdev->dev, &hdmi_component_ops);
 
 err_hdmiphy:
 	put_device(&hdata->hdmiphy_port->dev);
@@ -2164,14 +2179,14 @@ err_ddc:
 
 static int hdmi_remove(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
-	struct exynos_drm_display *display = get_hdmi_display(dev);
-	struct hdmi_context *hdata = display->ctx;
+	struct hdmi_context *hdata = hdmi_display.ctx;
 
 	put_device(&hdata->hdmiphy_port->dev);
 	put_device(&hdata->ddc_adpt->dev);
+
 	pm_runtime_disable(&pdev->dev);
 
+	component_del(&pdev->dev, &hdmi_component_ops);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index ce28881..d46a262 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -31,6 +31,7 @@
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/of.h>
+#include <linux/component.h>
 
 #include <drm/exynos_drm.h>
 
@@ -830,13 +831,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
 }
 
 static int mixer_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev, int pipe)
+			struct drm_device *drm_dev)
 {
 	int ret;
 	struct mixer_context *mixer_ctx = mgr->ctx;
+	struct exynos_drm_private *priv;
+	priv = drm_dev->dev_private;
 
-	mixer_ctx->drm_dev = drm_dev;
-	mixer_ctx->pipe = pipe;
+	mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
+	mgr->pipe = mixer_ctx->pipe = priv->pipe++;
 
 	/* acquire resources: regs, irqs, clocks */
 	ret = mixer_resources_init(mixer_ctx);
@@ -1142,8 +1145,6 @@ int mixer_check_mode(struct drm_display_mode *mode)
 }
 
 static struct exynos_drm_manager_ops mixer_manager_ops = {
-	.initialize		= mixer_initialize,
-	.remove			= mixer_mgr_remove,
 	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
@@ -1200,11 +1201,13 @@ static struct of_device_id mixer_match_types[] = {
 	}
 };
 
-static int mixer_probe(struct platform_device *pdev)
+static int mixer_bind(struct device *dev, struct device *manager, void *data)
 {
-	struct device *dev = &pdev->dev;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm_dev = data;
 	struct mixer_context *ctx;
 	struct mixer_drv_data *drv;
+	int ret;
 
 	dev_info(dev, "probe start\n");
 
@@ -1233,20 +1236,49 @@ static int mixer_probe(struct platform_device *pdev)
 	atomic_set(&ctx->wait_vsync_event, 0);
 
 	mixer_manager.ctx = ctx;
+	ret = mixer_initialize(&mixer_manager, drm_dev);
+	if (ret)
+		return ret;
+
 	platform_set_drvdata(pdev, &mixer_manager);
-	exynos_drm_manager_register(&mixer_manager);
+	ret = exynos_drm_crtc_create(&mixer_manager);
+	if (ret) {
+		mixer_mgr_remove(&mixer_manager);
+		return ret;
+	}
 
 	pm_runtime_enable(dev);
 
 	return 0;
 }
 
-static int mixer_remove(struct platform_device *pdev)
+static void mixer_unbind(struct device *dev, struct device *master, void *data)
 {
-	dev_info(&pdev->dev, "remove successful\n");
+	struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
+	struct drm_crtc *crtc = mgr->crtc;
+
+	dev_info(dev, "remove successful\n");
+
+	mixer_mgr_remove(mgr);
 
-	pm_runtime_disable(&pdev->dev);
+	pm_runtime_disable(dev);
 
+	crtc->funcs->destroy(crtc);
+}
+
+static const struct component_ops mixer_component_ops = {
+	.bind	= mixer_bind,
+	.unbind	= mixer_unbind,
+};
+
+static int mixer_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &mixer_component_ops);
+}
+
+static int mixer_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &mixer_component_ops);
 	return 0;
 }
 
-- 
1.7.9.5

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* [PATCH] drm/exynos: separate dpi from fimd
  2014-04-03 11:47     ` [PATCH v4] " Inki Dae
@ 2014-04-03 14:26       ` Andrzej Hajda
  2014-04-03 16:29         ` Inki Dae
  2014-04-03 16:35         ` Inki Dae
  0 siblings, 2 replies; 47+ messages in thread
From: Andrzej Hajda @ 2014-04-03 14:26 UTC (permalink / raw)
  To: Inki Dae; +Cc: Andrzej Hajda, dri-devel

The patch separates dpi related routines from fimd.

Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
---
Hi Inki,

This is my attempt to separate DPI from FIMD,
it requires putting real probe back into fimd_probe, but I
guess it should not be a problem, as it is done already for dsi.
It is based on v4 of your patch.

The patch was written quickly without proper review, I can
do it tomorrow if you are interested.
If it is OK for you, please merge it with your patch.
Anyway, I have made few tests - it works.

Regards
Andrzej
---
 drivers/gpu/drm/exynos/exynos_drm_dpi.c  |  40 ++++++------
 drivers/gpu/drm/exynos/exynos_drm_drv.h  |  15 ++---
 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 109 +++++++++++++------------------
 3 files changed, 69 insertions(+), 95 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
index ac206e7..03cb126 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
@@ -40,20 +40,10 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
 {
 	struct exynos_dpi *ctx = connector_to_dpi(connector);
 
-	/* panels supported only by boot-loader are always connected */
-	if (!ctx->panel_node)
-		return connector_status_connected;
-
-	if (!ctx->panel) {
-		ctx->panel = of_drm_find_panel(ctx->panel_node);
-		if (ctx->panel)
-			drm_panel_attach(ctx->panel, &ctx->connector);
-	}
+	if (!ctx->panel->connector)
+		drm_panel_attach(ctx->panel, &ctx->connector);
 
-	if (ctx->panel)
-		return connector_status_connected;
-
-	return connector_status_disconnected;
+	return connector_status_connected;
 }
 
 static void exynos_dpi_connector_destroy(struct drm_connector *connector)
@@ -291,8 +281,10 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 			return -ENOMEM;
 
 		ret = of_get_videomode(dn, vm, 0);
-		if (ret < 0)
+		if (ret < 0) {
+			devm_kfree(dev, vm);
 			return ret;
+		}
 
 		ctx->vm = vm;
 
@@ -305,27 +297,35 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
 	return 0;
 }
 
-int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
+struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
 {
 	struct exynos_dpi *ctx;
 	int ret;
 
 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
 	if (!ctx)
-		return -ENOMEM;
+		return NULL;
 
 	ctx->dev = dev;
 	exynos_dpi_display.ctx = ctx;
 	ctx->dpms_mode = DRM_MODE_DPMS_OFF;
 
 	ret = exynos_dpi_parse_dt(ctx);
-	if (ret < 0)
-		return ret;
+	if (ret < 0) {
+		devm_kfree(dev, ctx);
+		return NULL;
+	}
+
+	if (ctx->panel_node) {
+		ctx->panel = of_drm_find_panel(ctx->panel_node);
+		if (!ctx->panel)
+			return ERR_PTR(-EPROBE_DEFER);
+	}
 
-	return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
+	return &exynos_dpi_display;
 }
 
-int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
+int exynos_dpi_remove(struct device *dev)
 {
 	struct drm_encoder *encoder = exynos_dpi_display.encoder;
 	struct exynos_dpi *ctx = exynos_dpi_display.ctx;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 2b87eb7..583a0bd 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -334,17 +334,12 @@ int exynos_platform_device_ipp_register(void);
 void exynos_platform_device_ipp_unregister(void);
 
 #ifdef CONFIG_DRM_EXYNOS_DPI
-int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
-int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
-struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
+struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
+int exynos_dpi_remove(struct device *dev);
 #else
-static inline int exynos_dpi_probe(struct drm_device *drm_dev,
-					struct device *dev) { return 0; }
-static inline int exynos_dpi_remove(struct drm_device *drm_dev,
-					struct device *dev) { return 0; }
-static inline struct device_node
-			*exynos_dpi_of_find_panel_node(struct device *dev)
-{ return NULL; }
+static inline struct exynos_drm_display *
+exynos_dpi_probe(struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct device *dev) { return 0; }
 #endif
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 76282b3..11cce7b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -24,7 +24,6 @@
 #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"
@@ -124,6 +123,7 @@ struct fimd_context {
 
 	struct exynos_drm_panel_info panel;
 	struct fimd_driver_data *driver_data;
+	struct exynos_drm_display *dpi;
 };
 
 static const struct of_device_id fimd_driver_dt_match[] = {
@@ -853,12 +853,49 @@ out:
 
 static int fimd_bind(struct device *dev, struct device *master, void *data)
 {
-	struct platform_device *pdev = to_platform_device(dev);
+	struct fimd_context *ctx = fimd_manager.ctx;
 	struct drm_device *drm_dev = data;
+	int win;
+
+	fimd_mgr_initialize(&fimd_manager, drm_dev);
+	exynos_drm_crtc_create(&fimd_manager);
+	if (ctx->dpi)
+		exynos_drm_create_enc_conn(drm_dev, ctx->dpi);
+
+	for (win = 0; win < WINDOWS_NR; win++)
+		fimd_clear_win(ctx, win);
+
+	return 0;
+
+}
+
+static void fimd_unbind(struct device *dev, struct device *master,
+			void *data)
+{
+	struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
+	struct fimd_context *ctx = fimd_manager.ctx;
+	struct drm_crtc *crtc = mgr->crtc;
+
+	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
+
+	if (ctx->dpi)
+		exynos_dpi_remove(dev);
+
+	fimd_mgr_remove(mgr);
+
+	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 *dev = &pdev->dev;
 	struct fimd_context *ctx;
-	struct device_node *dn;
 	struct resource *res;
-	int win;
 	int ret = -EINVAL;
 
 	if (!dev->of_node)
@@ -914,68 +951,10 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
 	platform_set_drvdata(pdev, &fimd_manager);
 
 	fimd_manager.ctx = ctx;
-	fimd_mgr_initialize(&fimd_manager, drm_dev);
-
-	exynos_drm_crtc_create(&fimd_manager);
-
-	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);
-
-	return 0;
-}
-
-static void fimd_unbind(struct device *dev, struct device *master,
-			void *data)
-{
-	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);
-
-	dn = exynos_dpi_of_find_panel_node(dev);
-	if (dn)
-		exynos_dpi_remove(mgr->drm_dev, dev);
-
-	fimd_mgr_remove(mgr);
-
-	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;
-	}
+	ctx->dpi = exynos_dpi_probe(dev);
+	if (IS_ERR(ctx->dpi))
+		return PTR_ERR(ctx->dpi);
 
 	pm_runtime_enable(&pdev->dev);
 
-- 
1.8.3.2

^ permalink raw reply related	[flat|nested] 47+ messages in thread

* Re: [PATCH] drm/exynos: separate dpi from fimd
  2014-04-03 14:26       ` [PATCH] drm/exynos: separate dpi from fimd Andrzej Hajda
@ 2014-04-03 16:29         ` Inki Dae
  2014-04-03 16:35         ` Inki Dae
  1 sibling, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-03 16:29 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: DRI mailing list

Hi Andrzej,

2014-04-03 23:26 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
> The patch separates dpi related routines from fimd.
>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> Hi Inki,
>
> This is my attempt to separate DPI from FIMD,

Ah, I understood now. Right, if we can separate DPI from FIMD, we can
also move some codes for getting resources from fimd_bind to
fimd_probe.

Picked it up.

Thanks,
Inki Dae

> it requires putting real probe back into fimd_probe, but I
> guess it should not be a problem, as it is done already for dsi.
> It is based on v4 of your patch.
>
> The patch was written quickly without proper review, I can
> do it tomorrow if you are interested.
> If it is OK for you, please merge it with your patch.
> Anyway, I have made few tests - it works.
>
> Regards
> Andrzej
> ---
>  drivers/gpu/drm/exynos/exynos_drm_dpi.c  |  40 ++++++------
>  drivers/gpu/drm/exynos/exynos_drm_drv.h  |  15 ++---
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 109 +++++++++++++------------------
>  3 files changed, 69 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> index ac206e7..03cb126 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> @@ -40,20 +40,10 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
>  {
>         struct exynos_dpi *ctx = connector_to_dpi(connector);
>
> -       /* panels supported only by boot-loader are always connected */
> -       if (!ctx->panel_node)
> -               return connector_status_connected;
> -
> -       if (!ctx->panel) {
> -               ctx->panel = of_drm_find_panel(ctx->panel_node);
> -               if (ctx->panel)
> -                       drm_panel_attach(ctx->panel, &ctx->connector);
> -       }
> +       if (!ctx->panel->connector)
> +               drm_panel_attach(ctx->panel, &ctx->connector);
>
> -       if (ctx->panel)
> -               return connector_status_connected;
> -
> -       return connector_status_disconnected;
> +       return connector_status_connected;
>  }
>
>  static void exynos_dpi_connector_destroy(struct drm_connector *connector)
> @@ -291,8 +281,10 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>                         return -ENOMEM;
>
>                 ret = of_get_videomode(dn, vm, 0);
> -               if (ret < 0)
> +               if (ret < 0) {
> +                       devm_kfree(dev, vm);
>                         return ret;
> +               }
>
>                 ctx->vm = vm;
>
> @@ -305,27 +297,35 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>         return 0;
>  }
>
> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
> +struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
>  {
>         struct exynos_dpi *ctx;
>         int ret;
>
>         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>         if (!ctx)
> -               return -ENOMEM;
> +               return NULL;
>
>         ctx->dev = dev;
>         exynos_dpi_display.ctx = ctx;
>         ctx->dpms_mode = DRM_MODE_DPMS_OFF;
>
>         ret = exynos_dpi_parse_dt(ctx);
> -       if (ret < 0)
> -               return ret;
> +       if (ret < 0) {
> +               devm_kfree(dev, ctx);
> +               return NULL;
> +       }
> +
> +       if (ctx->panel_node) {
> +               ctx->panel = of_drm_find_panel(ctx->panel_node);
> +               if (!ctx->panel)
> +                       return ERR_PTR(-EPROBE_DEFER);
> +       }
>
> -       return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
> +       return &exynos_dpi_display;
>  }
>
> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
> +int exynos_dpi_remove(struct device *dev)
>  {
>         struct drm_encoder *encoder = exynos_dpi_display.encoder;
>         struct exynos_dpi *ctx = exynos_dpi_display.ctx;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index 2b87eb7..583a0bd 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -334,17 +334,12 @@ int exynos_platform_device_ipp_register(void);
>  void exynos_platform_device_ipp_unregister(void);
>
>  #ifdef CONFIG_DRM_EXYNOS_DPI
> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
> -struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
> +struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
> +int exynos_dpi_remove(struct device *dev);
>  #else
> -static inline int exynos_dpi_probe(struct drm_device *drm_dev,
> -                                       struct device *dev) { return 0; }
> -static inline int exynos_dpi_remove(struct drm_device *drm_dev,
> -                                       struct device *dev) { return 0; }
> -static inline struct device_node
> -                       *exynos_dpi_of_find_panel_node(struct device *dev)
> -{ return NULL; }
> +static inline struct exynos_drm_display *
> +exynos_dpi_probe(struct device *dev) { return 0; }
> +static inline int exynos_dpi_remove(struct device *dev) { return 0; }
>  #endif
>
>  /*
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 76282b3..11cce7b 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -24,7 +24,6 @@
>  #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"
> @@ -124,6 +123,7 @@ struct fimd_context {
>
>         struct exynos_drm_panel_info panel;
>         struct fimd_driver_data *driver_data;
> +       struct exynos_drm_display *dpi;
>  };
>
>  static const struct of_device_id fimd_driver_dt_match[] = {
> @@ -853,12 +853,49 @@ out:
>
>  static int fimd_bind(struct device *dev, struct device *master, void *data)
>  {
> -       struct platform_device *pdev = to_platform_device(dev);
> +       struct fimd_context *ctx = fimd_manager.ctx;
>         struct drm_device *drm_dev = data;
> +       int win;
> +
> +       fimd_mgr_initialize(&fimd_manager, drm_dev);
> +       exynos_drm_crtc_create(&fimd_manager);
> +       if (ctx->dpi)
> +               exynos_drm_create_enc_conn(drm_dev, ctx->dpi);
> +
> +       for (win = 0; win < WINDOWS_NR; win++)
> +               fimd_clear_win(ctx, win);
> +
> +       return 0;
> +
> +}
> +
> +static void fimd_unbind(struct device *dev, struct device *master,
> +                       void *data)
> +{
> +       struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
> +       struct fimd_context *ctx = fimd_manager.ctx;
> +       struct drm_crtc *crtc = mgr->crtc;
> +
> +       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
> +
> +       if (ctx->dpi)
> +               exynos_dpi_remove(dev);
> +
> +       fimd_mgr_remove(mgr);
> +
> +       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 *dev = &pdev->dev;
>         struct fimd_context *ctx;
> -       struct device_node *dn;
>         struct resource *res;
> -       int win;
>         int ret = -EINVAL;
>
>         if (!dev->of_node)
> @@ -914,68 +951,10 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
>         platform_set_drvdata(pdev, &fimd_manager);
>
>         fimd_manager.ctx = ctx;
> -       fimd_mgr_initialize(&fimd_manager, drm_dev);
> -
> -       exynos_drm_crtc_create(&fimd_manager);
> -
> -       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);
> -
> -       return 0;
> -}
> -
> -static void fimd_unbind(struct device *dev, struct device *master,
> -                       void *data)
> -{
> -       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);
> -
> -       dn = exynos_dpi_of_find_panel_node(dev);
> -       if (dn)
> -               exynos_dpi_remove(mgr->drm_dev, dev);
> -
> -       fimd_mgr_remove(mgr);
> -
> -       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;
> -       }
> +       ctx->dpi = exynos_dpi_probe(dev);
> +       if (IS_ERR(ctx->dpi))
> +               return PTR_ERR(ctx->dpi);
>
>         pm_runtime_enable(&pdev->dev);
>
> --
> 1.8.3.2
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH] drm/exynos: separate dpi from fimd
  2014-04-03 14:26       ` [PATCH] drm/exynos: separate dpi from fimd Andrzej Hajda
  2014-04-03 16:29         ` Inki Dae
@ 2014-04-03 16:35         ` Inki Dae
  2014-04-03 17:01           ` Inki Dae
  1 sibling, 1 reply; 47+ messages in thread
From: Inki Dae @ 2014-04-03 16:35 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: DRI mailing list

2014-04-03 23:26 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
> The patch separates dpi related routines from fimd.
>
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
> Hi Inki,
>
> This is my attempt to separate DPI from FIMD,
> it requires putting real probe back into fimd_probe, but I
> guess it should not be a problem, as it is done already for dsi.
> It is based on v4 of your patch.
>
> The patch was written quickly without proper review, I can
> do it tomorrow if you are interested.
> If it is OK for you, please merge it with your patch.
> Anyway, I have made few tests - it works.
>
> Regards
> Andrzej
> ---
>  drivers/gpu/drm/exynos/exynos_drm_dpi.c  |  40 ++++++------
>  drivers/gpu/drm/exynos/exynos_drm_drv.h  |  15 ++---
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 109 +++++++++++++------------------
>  3 files changed, 69 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> index ac206e7..03cb126 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
> @@ -40,20 +40,10 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
>  {
>         struct exynos_dpi *ctx = connector_to_dpi(connector);
>
> -       /* panels supported only by boot-loader are always connected */
> -       if (!ctx->panel_node)
> -               return connector_status_connected;
> -
> -       if (!ctx->panel) {
> -               ctx->panel = of_drm_find_panel(ctx->panel_node);
> -               if (ctx->panel)
> -                       drm_panel_attach(ctx->panel, &ctx->connector);
> -       }
> +       if (!ctx->panel->connector)
> +               drm_panel_attach(ctx->panel, &ctx->connector);
>
> -       if (ctx->panel)
> -               return connector_status_connected;
> -
> -       return connector_status_disconnected;
> +       return connector_status_connected;
>  }
>
>  static void exynos_dpi_connector_destroy(struct drm_connector *connector)
> @@ -291,8 +281,10 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>                         return -ENOMEM;
>
>                 ret = of_get_videomode(dn, vm, 0);
> -               if (ret < 0)
> +               if (ret < 0) {
> +                       devm_kfree(dev, vm);
>                         return ret;
> +               }
>
>                 ctx->vm = vm;
>
> @@ -305,27 +297,35 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>         return 0;
>  }
>
> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
> +struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
>  {
>         struct exynos_dpi *ctx;
>         int ret;
>
>         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>         if (!ctx)
> -               return -ENOMEM;
> +               return NULL;
>
>         ctx->dev = dev;
>         exynos_dpi_display.ctx = ctx;
>         ctx->dpms_mode = DRM_MODE_DPMS_OFF;
>
>         ret = exynos_dpi_parse_dt(ctx);
> -       if (ret < 0)
> -               return ret;
> +       if (ret < 0) {
> +               devm_kfree(dev, ctx);
> +               return NULL;
> +       }
> +
> +       if (ctx->panel_node) {
> +               ctx->panel = of_drm_find_panel(ctx->panel_node);
> +               if (!ctx->panel)
> +                       return ERR_PTR(-EPROBE_DEFER);
> +       }
>
> -       return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
> +       return &exynos_dpi_display;
>  }
>
> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
> +int exynos_dpi_remove(struct device *dev)
>  {
>         struct drm_encoder *encoder = exynos_dpi_display.encoder;
>         struct exynos_dpi *ctx = exynos_dpi_display.ctx;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> index 2b87eb7..583a0bd 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
> @@ -334,17 +334,12 @@ int exynos_platform_device_ipp_register(void);
>  void exynos_platform_device_ipp_unregister(void);
>
>  #ifdef CONFIG_DRM_EXYNOS_DPI
> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
> -struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
> +struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
> +int exynos_dpi_remove(struct device *dev);
>  #else
> -static inline int exynos_dpi_probe(struct drm_device *drm_dev,
> -                                       struct device *dev) { return 0; }
> -static inline int exynos_dpi_remove(struct drm_device *drm_dev,
> -                                       struct device *dev) { return 0; }
> -static inline struct device_node
> -                       *exynos_dpi_of_find_panel_node(struct device *dev)
> -{ return NULL; }
> +static inline struct exynos_drm_display *
> +exynos_dpi_probe(struct device *dev) { return 0; }
> +static inline int exynos_dpi_remove(struct device *dev) { return 0; }
>  #endif
>
>  /*
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index 76282b3..11cce7b 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -24,7 +24,6 @@
>  #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"
> @@ -124,6 +123,7 @@ struct fimd_context {
>
>         struct exynos_drm_panel_info panel;
>         struct fimd_driver_data *driver_data;
> +       struct exynos_drm_display *dpi;
>  };
>
>  static const struct of_device_id fimd_driver_dt_match[] = {
> @@ -853,12 +853,49 @@ out:
>
>  static int fimd_bind(struct device *dev, struct device *master, void *data)
>  {
> -       struct platform_device *pdev = to_platform_device(dev);
> +       struct fimd_context *ctx = fimd_manager.ctx;
>         struct drm_device *drm_dev = data;
> +       int win;
> +
> +       fimd_mgr_initialize(&fimd_manager, drm_dev);
> +       exynos_drm_crtc_create(&fimd_manager);
> +       if (ctx->dpi)
> +               exynos_drm_create_enc_conn(drm_dev, ctx->dpi);
> +
> +       for (win = 0; win < WINDOWS_NR; win++)
> +               fimd_clear_win(ctx, win);
> +
> +       return 0;
> +
> +}
> +
> +static void fimd_unbind(struct device *dev, struct device *master,
> +                       void *data)
> +{
> +       struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
> +       struct fimd_context *ctx = fimd_manager.ctx;
> +       struct drm_crtc *crtc = mgr->crtc;
> +
> +       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
> +
> +       if (ctx->dpi)
> +               exynos_dpi_remove(dev);

Above codes would better to move fimd_remove() because
exynos_dpi_remove is pair with exynos_dpi_probe, and exynos_dpi_probe
will be called at fimd_probe. So I just modified it.

Thanks,
Inki Dae

> +
> +       fimd_mgr_remove(mgr);
> +
> +       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 *dev = &pdev->dev;
>         struct fimd_context *ctx;
> -       struct device_node *dn;
>         struct resource *res;
> -       int win;
>         int ret = -EINVAL;
>
>         if (!dev->of_node)
> @@ -914,68 +951,10 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
>         platform_set_drvdata(pdev, &fimd_manager);
>
>         fimd_manager.ctx = ctx;
> -       fimd_mgr_initialize(&fimd_manager, drm_dev);
> -
> -       exynos_drm_crtc_create(&fimd_manager);
> -
> -       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);
> -
> -       return 0;
> -}
> -
> -static void fimd_unbind(struct device *dev, struct device *master,
> -                       void *data)
> -{
> -       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);
> -
> -       dn = exynos_dpi_of_find_panel_node(dev);
> -       if (dn)
> -               exynos_dpi_remove(mgr->drm_dev, dev);
> -
> -       fimd_mgr_remove(mgr);
> -
> -       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;
> -       }
> +       ctx->dpi = exynos_dpi_probe(dev);
> +       if (IS_ERR(ctx->dpi))
> +               return PTR_ERR(ctx->dpi);
>
>         pm_runtime_enable(&pdev->dev);
>
> --
> 1.8.3.2
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH] drm/exynos: separate dpi from fimd
  2014-04-03 16:35         ` Inki Dae
@ 2014-04-03 17:01           ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-03 17:01 UTC (permalink / raw)
  To: Andrzej Hajda; +Cc: DRI mailing list

2014-04-04 1:35 GMT+09:00 Inki Dae <inki.dae@samsung.com>:
> 2014-04-03 23:26 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
>> The patch separates dpi related routines from fimd.
>>
>> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
>> ---
>> Hi Inki,
>>
>> This is my attempt to separate DPI from FIMD,
>> it requires putting real probe back into fimd_probe, but I
>> guess it should not be a problem, as it is done already for dsi.
>> It is based on v4 of your patch.
>>
>> The patch was written quickly without proper review, I can
>> do it tomorrow if you are interested.
>> If it is OK for you, please merge it with your patch.
>> Anyway, I have made few tests - it works.
>>
>> Regards
>> Andrzej
>> ---
>>  drivers/gpu/drm/exynos/exynos_drm_dpi.c  |  40 ++++++------
>>  drivers/gpu/drm/exynos/exynos_drm_drv.h  |  15 ++---
>>  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 109 +++++++++++++------------------
>>  3 files changed, 69 insertions(+), 95 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
>> index ac206e7..03cb126 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_dpi.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
>> @@ -40,20 +40,10 @@ exynos_dpi_detect(struct drm_connector *connector, bool force)
>>  {
>>         struct exynos_dpi *ctx = connector_to_dpi(connector);
>>
>> -       /* panels supported only by boot-loader are always connected */
>> -       if (!ctx->panel_node)
>> -               return connector_status_connected;
>> -
>> -       if (!ctx->panel) {
>> -               ctx->panel = of_drm_find_panel(ctx->panel_node);
>> -               if (ctx->panel)
>> -                       drm_panel_attach(ctx->panel, &ctx->connector);
>> -       }
>> +       if (!ctx->panel->connector)
>> +               drm_panel_attach(ctx->panel, &ctx->connector);
>>
>> -       if (ctx->panel)
>> -               return connector_status_connected;
>> -
>> -       return connector_status_disconnected;
>> +       return connector_status_connected;
>>  }
>>
>>  static void exynos_dpi_connector_destroy(struct drm_connector *connector)
>> @@ -291,8 +281,10 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>>                         return -ENOMEM;
>>
>>                 ret = of_get_videomode(dn, vm, 0);
>> -               if (ret < 0)
>> +               if (ret < 0) {
>> +                       devm_kfree(dev, vm);
>>                         return ret;
>> +               }
>>
>>                 ctx->vm = vm;
>>
>> @@ -305,27 +297,35 @@ static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
>>         return 0;
>>  }
>>
>> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev)
>> +struct exynos_drm_display *exynos_dpi_probe(struct device *dev)
>>  {
>>         struct exynos_dpi *ctx;
>>         int ret;
>>
>>         ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
>>         if (!ctx)
>> -               return -ENOMEM;
>> +               return NULL;
>>
>>         ctx->dev = dev;
>>         exynos_dpi_display.ctx = ctx;
>>         ctx->dpms_mode = DRM_MODE_DPMS_OFF;
>>
>>         ret = exynos_dpi_parse_dt(ctx);
>> -       if (ret < 0)
>> -               return ret;
>> +       if (ret < 0) {
>> +               devm_kfree(dev, ctx);
>> +               return NULL;
>> +       }
>> +
>> +       if (ctx->panel_node) {
>> +               ctx->panel = of_drm_find_panel(ctx->panel_node);
>> +               if (!ctx->panel)
>> +                       return ERR_PTR(-EPROBE_DEFER);
>> +       }
>>
>> -       return exynos_drm_create_enc_conn(drm_dev, &exynos_dpi_display);
>> +       return &exynos_dpi_display;
>>  }
>>
>> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev)
>> +int exynos_dpi_remove(struct device *dev)
>>  {
>>         struct drm_encoder *encoder = exynos_dpi_display.encoder;
>>         struct exynos_dpi *ctx = exynos_dpi_display.ctx;
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> index 2b87eb7..583a0bd 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
>> @@ -334,17 +334,12 @@ int exynos_platform_device_ipp_register(void);
>>  void exynos_platform_device_ipp_unregister(void);
>>
>>  #ifdef CONFIG_DRM_EXYNOS_DPI
>> -int exynos_dpi_probe(struct drm_device *drm_dev, struct device *dev);
>> -int exynos_dpi_remove(struct drm_device *drm_dev, struct device *dev);
>> -struct device_node *exynos_dpi_of_find_panel_node(struct device *dev);
>> +struct exynos_drm_display * exynos_dpi_probe(struct device *dev);
>> +int exynos_dpi_remove(struct device *dev);
>>  #else
>> -static inline int exynos_dpi_probe(struct drm_device *drm_dev,
>> -                                       struct device *dev) { return 0; }
>> -static inline int exynos_dpi_remove(struct drm_device *drm_dev,
>> -                                       struct device *dev) { return 0; }
>> -static inline struct device_node
>> -                       *exynos_dpi_of_find_panel_node(struct device *dev)
>> -{ return NULL; }
>> +static inline struct exynos_drm_display *
>> +exynos_dpi_probe(struct device *dev) { return 0; }
>> +static inline int exynos_dpi_remove(struct device *dev) { return 0; }
>>  #endif
>>
>>  /*
>> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> index 76282b3..11cce7b 100644
>> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
>> @@ -24,7 +24,6 @@
>>  #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"
>> @@ -124,6 +123,7 @@ struct fimd_context {
>>
>>         struct exynos_drm_panel_info panel;
>>         struct fimd_driver_data *driver_data;
>> +       struct exynos_drm_display *dpi;

Changed dpi -> display.

>>  };
>>
>>  static const struct of_device_id fimd_driver_dt_match[] = {
>> @@ -853,12 +853,49 @@ out:
>>
>>  static int fimd_bind(struct device *dev, struct device *master, void *data)
>>  {
>> -       struct platform_device *pdev = to_platform_device(dev);
>> +       struct fimd_context *ctx = fimd_manager.ctx;
>>         struct drm_device *drm_dev = data;
>> +       int win;
>> +
>> +       fimd_mgr_initialize(&fimd_manager, drm_dev);
>> +       exynos_drm_crtc_create(&fimd_manager);
>> +       if (ctx->dpi)
>> +               exynos_drm_create_enc_conn(drm_dev, ctx->dpi);
>> +
>> +       for (win = 0; win < WINDOWS_NR; win++)
>> +               fimd_clear_win(ctx, win);
>> +
>> +       return 0;
>> +
>> +}
>> +
>> +static void fimd_unbind(struct device *dev, struct device *master,
>> +                       void *data)
>> +{
>> +       struct exynos_drm_manager *mgr = dev_get_drvdata(dev);
>> +       struct fimd_context *ctx = fimd_manager.ctx;
>> +       struct drm_crtc *crtc = mgr->crtc;
>> +
>> +       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
>> +
>> +       if (ctx->dpi)
>> +               exynos_dpi_remove(dev);
>
> Above codes would better to move fimd_remove() because
> exynos_dpi_remove is pair with exynos_dpi_probe, and exynos_dpi_probe
> will be called at fimd_probe. So I just modified it.
>

Hm.. there seems something unpaired. exynos_drm_create_enc_conn() is
called in fimd_bind but cleanup for it is done in exynos_dpi_remove so
it cannot move exynos_dpi_remove call to fimd_remove().

Thanks,
Inki Dae

> Thanks,
> Inki Dae
>
>> +
>> +       fimd_mgr_remove(mgr);
>> +
>> +       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 *dev = &pdev->dev;
>>         struct fimd_context *ctx;
>> -       struct device_node *dn;
>>         struct resource *res;
>> -       int win;
>>         int ret = -EINVAL;
>>
>>         if (!dev->of_node)
>> @@ -914,68 +951,10 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
>>         platform_set_drvdata(pdev, &fimd_manager);
>>
>>         fimd_manager.ctx = ctx;
>> -       fimd_mgr_initialize(&fimd_manager, drm_dev);
>> -
>> -       exynos_drm_crtc_create(&fimd_manager);
>> -
>> -       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);
>> -
>> -       return 0;
>> -}
>> -
>> -static void fimd_unbind(struct device *dev, struct device *master,
>> -                       void *data)
>> -{
>> -       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);
>> -
>> -       dn = exynos_dpi_of_find_panel_node(dev);
>> -       if (dn)
>> -               exynos_dpi_remove(mgr->drm_dev, dev);
>> -
>> -       fimd_mgr_remove(mgr);
>> -
>> -       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;
>> -       }
>> +       ctx->dpi = exynos_dpi_probe(dev);
>> +       if (IS_ERR(ctx->dpi))
>> +               return PTR_ERR(ctx->dpi);
>>
>>         pm_runtime_enable(&pdev->dev);
>>
>> --
>> 1.8.3.2
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
  2014-04-02 14:06   ` Andrzej Hajda
  2014-04-03  8:36   ` [PATCH v3] " Inki Dae
@ 2014-04-04 13:55   ` Tomasz Figa
  2014-04-04 15:44     ` Inki Dae
  2 siblings, 1 reply; 47+ messages in thread
From: Tomasz Figa @ 2014-04-04 13:55 UTC (permalink / raw)
  To: Inki Dae, airlied, dri-devel
  Cc: a.hajda, kyungmin.park, 'Marek Szyprowski'

Hi Inki,

On 01.04.2014 14:37, 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.

I can see several problems with this approach:

1) It breaks compatibility with existing DT. After this patch it is no 
longer possible to use old device trees and get a working DRM. However, 
in my opinion, this requirement can be relaxed if we make sure that any 
users are properly converted.

2) What happens if in Kconfig you disable a driver for a component that 
is listed in supernode? If I'm reading the code correctly, Exynos DRM 
will not register, which is completely wrong. Users should be able to 
select which drivers should be compiled into their kernels.

3) Such approach leads to complete integration of all Exynos DRM 
drivers, without possibility of loading some sub-drivers as modules. I 
know that current driver design doesn't support it either, but if this 
series is claimed to improve things, it should really do so.

4) Exactly the same can be achieved without changing the DT bindings at 
all. In fact even without adding any new single property or node to DT. 
We discussed this with Andrzej and Marek today and came to a solution in 
which just by adding a little bit of code to Exynos DRM subdrivers, you 
could guarantee correct registration of Exynos DRM platform and also get 
rid of #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after 
the weekend.

5) This series seems to break DPI display support with runtime PM 
enabled. Universal C210 just hangs on second FIMD probe, after first one 
fails with probe deferral. This needs more investigation, though.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-04 13:55   ` [PATCH v2 1/7] drm/exynos: add super device support Tomasz Figa
@ 2014-04-04 15:44     ` Inki Dae
  2014-04-05 17:32         ` Tomasz Figa
  0 siblings, 1 reply; 47+ messages in thread
From: Inki Dae @ 2014-04-04 15:44 UTC (permalink / raw)
  To: Tomasz Figa; +Cc: a.hajda, kyungmin.park, dri-devel, Marek Szyprowski

2014-04-04 22:55 GMT+09:00 Tomasz Figa <t.figa@samsung.com>:
> Hi Inki,
>
>
> On 01.04.2014 14:37, 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.
>
>
> I can see several problems with this approach:
>
> 1) It breaks compatibility with existing DT. After this patch it is no
> longer possible to use old device trees and get a working DRM. However, in
> my opinion, this requirement can be relaxed if we make sure that any users
> are properly converted.
>
> 2) What happens if in Kconfig you disable a driver for a component that is

I'm not sure what you meant but there wouldn't be no way that users
*cannot disable* the driver for a component. The driver would be
exynos_drm_drv, not separated module, and would always be built as
long as users want to use *exynos drm driver*.

> listed in supernode? If I'm reading the code correctly, Exynos DRM will not

And the only case a component isn't added to the list is when users
disabled sub driver.

> register, which is completely wrong. Users should be able to select which
> drivers should be compiled into their kernels.

So users are be able to select drivers they want to use, and will be
compiled correctly. So no, the only thing users can disable is each
sub driver, not core module.

>
> 3) Such approach leads to complete integration of all Exynos DRM drivers,
> without possibility of loading some sub-drivers as modules. I know that
> current driver design doesn't support it either, but if this series is

No, current drm driver *must also be built* as one integrated single
drm driver without super device approach. So the super device approach
*has no any effect on existing design*,  and what the super device
approch tries to do is to resolve the probe order issue to sub drivers
*without some codes specific to Exynos drm*.

> claimed to improve things, it should really do so.
>
> 4) Exactly the same can be achieved without changing the DT bindings at all.
> In fact even without adding any new single property or node to DT. We
> discussed this with Andrzej and Marek today and came to a solution in which
> just by adding a little bit of code to Exynos DRM subdrivers, you could
> guarantee correct registration of Exynos DRM platform and also get rid of
> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the weekend.

I'm not sure but I had implemented below prototype codes for that, see
the below link,
https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e

I guess what you said would be similler approach.

And I still think the use of the component framework would be the best
solution and *Linux generic way* for resolving the probe order issue
without any specific codes. So I'm not advocating the compoent
framework but I tend not to want to use specific codes.

>
> 5) This series seems to break DPI display support with runtime PM enabled.
> Universal C210 just hangs on second FIMD probe, after first one fails with
> probe deferral. This needs more investigation, though.

For -next, I never expect that pm operations would be operated
perfactly. They are really not for product. Just adding new feature
and drivers to -next, and then fixing them while in RC. And RC process
would also be for it. Actually, I see pm interfaces of exynos_drm_dsi
driver leads to break a single driver model because pm operations
should be done at top level of exynos drm, and some codes Sean didn't
fix. So such things are in my fix-todo-list. I tend to accept new
features and drivers for -next as long as they have no big problem,
And that is my style I maintain.

Thanks,
Inki Dae

>
> Best regards,
> Tomasz
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-04 15:44     ` Inki Dae
@ 2014-04-05 17:32         ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 17:32 UTC (permalink / raw)
  To: Inki Dae, Tomasz Figa
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski

[adding more people and MLs on Cc for further discussion]

On 04.04.2014 17:44, Inki Dae wrote:
> 2014-04-04 22:55 GMT+09:00 Tomasz Figa <t.figa@samsung.com>:
>> Hi Inki,
>>
>>
>> On 01.04.2014 14:37, 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.
>>
>>
>> I can see several problems with this approach:
>>
>> 1) It breaks compatibility with existing DT. After this patch it is no
>> longer possible to use old device trees and get a working DRM. However, in
>> my opinion, this requirement can be relaxed if we make sure that any users
>> are properly converted.
>>
>> 2) What happens if in Kconfig you disable a driver for a component that is
>
> I'm not sure what you meant but there wouldn't be no way that users
> *cannot disable* the driver for a component. The driver would be
> exynos_drm_drv, not separated module, and would always be built as
> long as users want to use *exynos drm driver*.

I think you don't understand what I mean. Let me show you an example:

You have a board with a DSI panel and also a HDMI output. So you have a 
supernode pointing to FIMD, DSI and HDMI.

Now, an user finds that he doesn't need HDMI in his system, so he turns 
off CONFIG_DRM_EXYNOS_HDMI. The supernode still points at hdmi node and 
Exynos DRM core will register it as a component, but HDMI driver is not 
available and will never probe, leading the whole Exynos DRM to never 
initialize. Is this a desired behavior?

>
>> listed in supernode? If I'm reading the code correctly, Exynos DRM will not
>
> And the only case a component isn't added to the list is when users
> disabled sub driver.

See above.

The code creating the list of components to wait for 
(exynos_drm_add_components()) doesn't seem to consider which sub-drivers 
are actually enabled in kernel config.

>> register, which is completely wrong. Users should be able to select which
>> drivers should be compiled into their kernels.
>
> So users are be able to select drivers they want to use, and will be
> compiled correctly. So no, the only thing users can disable is each
> sub driver, not core module.
>
>>
>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>> without possibility of loading some sub-drivers as modules. I know that
>> current driver design doesn't support it either, but if this series is
>
> No, current drm driver *must also be built* as one integrated single
> drm driver without super device approach.

As I wrote, I know that current design before this patch isn't modular 
either, but this is not my concern here. See below.

> So the super device approach
> *has no any effect on existing design*,  and what the super device
> approch tries to do is to resolve the probe order issue to sub drivers
> *without some codes specific to Exynos drm*.

My concern is that the supernode design is actually carving such broken 
non-modular design in stone. Remember that we are currently heading 
towards a fully multi-platform kernel where it is critical for such 
subsystems to be modular, because the same zImage is going to be running 
on completely different machines.

>
>> claimed to improve things, it should really do so.
>>
>> 4) Exactly the same can be achieved without changing the DT bindings at all.
>> In fact even without adding any new single property or node to DT. We
>> discussed this with Andrzej and Marek today and came to a solution in which
>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>> guarantee correct registration of Exynos DRM platform and also get rid of
>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the weekend.
>
> I'm not sure but I had implemented below prototype codes for that, see
> the below link,
> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>
> I guess what you said would be similler approach.

Not exactly. The approach we found does mostly the same as componentized 
subsystem framework but without _any_ extra data in Device Tree. Just 
based on the list of subsystem sub-drivers that is already available to 
the master driver.

>
> And I still think the use of the component framework would be the best
> solution and *Linux generic way* for resolving the probe order issue
> without any specific codes. So I'm not advocating the compoent
> framework but I tend not to want to use specific codes.
>

I understand your concern. I also believe that generic frameworks should 
be reused wherever possible. However the componentized subsystem 
framework is a bit of overkill for this simple problem. Moreover, Device 
Tree is not a trash can where any data that can be thought of can be 
thrown as you go, but rather a hardware description that is supposed to 
be a stable ABI and needs to be well-thought. So, if something can be 
done in a way that doesn't require additional data, it's better to do it 
that way.

>>
>> 5) This series seems to break DPI display support with runtime PM enabled.
>> Universal C210 just hangs on second FIMD probe, after first one fails with
>> probe deferral. This needs more investigation, though.
>
> For -next, I never expect that pm operations would be operated
> perfactly. They are really not for product. Just adding new feature
> and drivers to -next, and then fixing them while in RC. And RC process
> would also be for it. Actually, I see pm interfaces of exynos_drm_dsi
> driver leads to break a single driver model because pm operations
> should be done at top level of exynos drm, and some codes Sean didn't
> fix. So such things are in my fix-todo-list. I tend to accept new
> features and drivers for -next as long as they have no big problem,
> And that is my style I maintain.

Unless it breaks so much that the system is unable to boot at all, which 
is the case. As I said, the system just hangs, like something would 
access hardware that is not properly initialized, e.g. without power 
domain or clocks enabled.

Anyway, I don't agree that regressions are allowed in linux-next, 
especially if found before applying a patch. Linux-next is a tree in 
which patches that are supposed to be ready to be pulled by Linus should 
be pushed. Of course nobody can spot all the regressions before the 
patches hitting -next and that's fine, as -next is an integration 
_testing_ tree. However even if already in -next, regressions should be 
fixed ASAP to minimize the number of fix patches needed during -rc period.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-05 17:32         ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 17:32 UTC (permalink / raw)
  To: linux-arm-kernel

[adding more people and MLs on Cc for further discussion]

On 04.04.2014 17:44, Inki Dae wrote:
> 2014-04-04 22:55 GMT+09:00 Tomasz Figa <t.figa@samsung.com>:
>> Hi Inki,
>>
>>
>> On 01.04.2014 14:37, 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.
>>
>>
>> I can see several problems with this approach:
>>
>> 1) It breaks compatibility with existing DT. After this patch it is no
>> longer possible to use old device trees and get a working DRM. However, in
>> my opinion, this requirement can be relaxed if we make sure that any users
>> are properly converted.
>>
>> 2) What happens if in Kconfig you disable a driver for a component that is
>
> I'm not sure what you meant but there wouldn't be no way that users
> *cannot disable* the driver for a component. The driver would be
> exynos_drm_drv, not separated module, and would always be built as
> long as users want to use *exynos drm driver*.

I think you don't understand what I mean. Let me show you an example:

You have a board with a DSI panel and also a HDMI output. So you have a 
supernode pointing to FIMD, DSI and HDMI.

Now, an user finds that he doesn't need HDMI in his system, so he turns 
off CONFIG_DRM_EXYNOS_HDMI. The supernode still points at hdmi node and 
Exynos DRM core will register it as a component, but HDMI driver is not 
available and will never probe, leading the whole Exynos DRM to never 
initialize. Is this a desired behavior?

>
>> listed in supernode? If I'm reading the code correctly, Exynos DRM will not
>
> And the only case a component isn't added to the list is when users
> disabled sub driver.

See above.

The code creating the list of components to wait for 
(exynos_drm_add_components()) doesn't seem to consider which sub-drivers 
are actually enabled in kernel config.

>> register, which is completely wrong. Users should be able to select which
>> drivers should be compiled into their kernels.
>
> So users are be able to select drivers they want to use, and will be
> compiled correctly. So no, the only thing users can disable is each
> sub driver, not core module.
>
>>
>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>> without possibility of loading some sub-drivers as modules. I know that
>> current driver design doesn't support it either, but if this series is
>
> No, current drm driver *must also be built* as one integrated single
> drm driver without super device approach.

As I wrote, I know that current design before this patch isn't modular 
either, but this is not my concern here. See below.

> So the super device approach
> *has no any effect on existing design*,  and what the super device
> approch tries to do is to resolve the probe order issue to sub drivers
> *without some codes specific to Exynos drm*.

My concern is that the supernode design is actually carving such broken 
non-modular design in stone. Remember that we are currently heading 
towards a fully multi-platform kernel where it is critical for such 
subsystems to be modular, because the same zImage is going to be running 
on completely different machines.

>
>> claimed to improve things, it should really do so.
>>
>> 4) Exactly the same can be achieved without changing the DT bindings at all.
>> In fact even without adding any new single property or node to DT. We
>> discussed this with Andrzej and Marek today and came to a solution in which
>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>> guarantee correct registration of Exynos DRM platform and also get rid of
>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the weekend.
>
> I'm not sure but I had implemented below prototype codes for that, see
> the below link,
> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>
> I guess what you said would be similler approach.

Not exactly. The approach we found does mostly the same as componentized 
subsystem framework but without _any_ extra data in Device Tree. Just 
based on the list of subsystem sub-drivers that is already available to 
the master driver.

>
> And I still think the use of the component framework would be the best
> solution and *Linux generic way* for resolving the probe order issue
> without any specific codes. So I'm not advocating the compoent
> framework but I tend not to want to use specific codes.
>

I understand your concern. I also believe that generic frameworks should 
be reused wherever possible. However the componentized subsystem 
framework is a bit of overkill for this simple problem. Moreover, Device 
Tree is not a trash can where any data that can be thought of can be 
thrown as you go, but rather a hardware description that is supposed to 
be a stable ABI and needs to be well-thought. So, if something can be 
done in a way that doesn't require additional data, it's better to do it 
that way.

>>
>> 5) This series seems to break DPI display support with runtime PM enabled.
>> Universal C210 just hangs on second FIMD probe, after first one fails with
>> probe deferral. This needs more investigation, though.
>
> For -next, I never expect that pm operations would be operated
> perfactly. They are really not for product. Just adding new feature
> and drivers to -next, and then fixing them while in RC. And RC process
> would also be for it. Actually, I see pm interfaces of exynos_drm_dsi
> driver leads to break a single driver model because pm operations
> should be done at top level of exynos drm, and some codes Sean didn't
> fix. So such things are in my fix-todo-list. I tend to accept new
> features and drivers for -next as long as they have no big problem,
> And that is my style I maintain.

Unless it breaks so much that the system is unable to boot at all, which 
is the case. As I said, the system just hangs, like something would 
access hardware that is not properly initialized, e.g. without power 
domain or clocks enabled.

Anyway, I don't agree that regressions are allowed in linux-next, 
especially if found before applying a patch. Linux-next is a tree in 
which patches that are supposed to be ready to be pulled by Linus should 
be pushed. Of course nobody can spot all the regressions before the 
patches hitting -next and that's fine, as -next is an integration 
_testing_ tree. However even if already in -next, regressions should be 
fixed ASAP to minimize the number of fix patches needed during -rc period.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 17:32         ` Tomasz Figa
@ 2014-04-05 18:24           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-05 18:24 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski

On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
> Not exactly. The approach we found does mostly the same as componentized  
> subsystem framework but without _any_ extra data in Device Tree. Just  
> based on the list of subsystem sub-drivers that is already available to  
> the master driver.

The existing approach is fundamentally broken.  Yes, your solution may
work for the probing case, but have you tried unbinding any of your
sub-drivers?

>From what I can see, that causes a kernel oops for one very simple reason -
you destroy stuff while it's still in use.  Let's look at an example:

struct platform_driver ipp_driver = {
        .probe          = ipp_probe,
        .remove         = ipp_remove,
        .driver         = {
                .name   = "exynos-drm-ipp",
                .owner  = THIS_MODULE,
                .pm     = &ipp_pm_ops,
        },
};

static int ipp_remove(struct platform_device *pdev)
{
        struct ipp_context *ctx = platform_get_drvdata(pdev);

        /* unregister sub driver */
        exynos_drm_subdrv_unregister(&ctx->subdrv);

        /* remove,destroy ipp idr */
        idr_destroy(&ctx->ipp_idr);
        idr_destroy(&ctx->prop_idr);

        mutex_destroy(&ctx->ipp_lock);
        mutex_destroy(&ctx->prop_lock);

        /* destroy command, event work queue */
        destroy_workqueue(ctx->cmd_workq);
        destroy_workqueue(ctx->event_workq);

        return 0;
}

int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
        if (!subdrv)
                return -EINVAL;

        list_del(&subdrv->list);

        return 0;
}

Oh dear, that destroys a whole pile of resources which could already
be in use without telling anything that it's about to do that.

I'm sure if I continue looking at the exynos stuff, it'll show similar
crap all over the place.

What you have now in mainline is not a solution.  It's a crappy bodge.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-05 18:24           ` Russell King - ARM Linux
  0 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-05 18:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
> Not exactly. The approach we found does mostly the same as componentized  
> subsystem framework but without _any_ extra data in Device Tree. Just  
> based on the list of subsystem sub-drivers that is already available to  
> the master driver.

The existing approach is fundamentally broken.  Yes, your solution may
work for the probing case, but have you tried unbinding any of your
sub-drivers?

>From what I can see, that causes a kernel oops for one very simple reason -
you destroy stuff while it's still in use.  Let's look at an example:

struct platform_driver ipp_driver = {
        .probe          = ipp_probe,
        .remove         = ipp_remove,
        .driver         = {
                .name   = "exynos-drm-ipp",
                .owner  = THIS_MODULE,
                .pm     = &ipp_pm_ops,
        },
};

static int ipp_remove(struct platform_device *pdev)
{
        struct ipp_context *ctx = platform_get_drvdata(pdev);

        /* unregister sub driver */
        exynos_drm_subdrv_unregister(&ctx->subdrv);

        /* remove,destroy ipp idr */
        idr_destroy(&ctx->ipp_idr);
        idr_destroy(&ctx->prop_idr);

        mutex_destroy(&ctx->ipp_lock);
        mutex_destroy(&ctx->prop_lock);

        /* destroy command, event work queue */
        destroy_workqueue(ctx->cmd_workq);
        destroy_workqueue(ctx->event_workq);

        return 0;
}

int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
{
        if (!subdrv)
                return -EINVAL;

        list_del(&subdrv->list);

        return 0;
}

Oh dear, that destroys a whole pile of resources which could already
be in use without telling anything that it's about to do that.

I'm sure if I continue looking at the exynos stuff, it'll show similar
crap all over the place.

What you have now in mainline is not a solution.  It's a crappy bodge.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 18:24           ` Russell King - ARM Linux
@ 2014-04-05 18:31             ` Tomasz Figa
  -1 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 18:31 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski



On 05.04.2014 20:24, Russell King - ARM Linux wrote:
> On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
>> Not exactly. The approach we found does mostly the same as componentized
>> subsystem framework but without _any_ extra data in Device Tree. Just
>> based on the list of subsystem sub-drivers that is already available to
>> the master driver.
>
> The existing approach is fundamentally broken.  Yes, your solution may
> work for the probing case, but have you tried unbinding any of your
> sub-drivers?
>
>  From what I can see, that causes a kernel oops for one very simple reason -
> you destroy stuff while it's still in use.  Let's look at an example:
>
> struct platform_driver ipp_driver = {
>          .probe          = ipp_probe,
>          .remove         = ipp_remove,
>          .driver         = {
>                  .name   = "exynos-drm-ipp",
>                  .owner  = THIS_MODULE,
>                  .pm     = &ipp_pm_ops,
>          },
> };
>
> static int ipp_remove(struct platform_device *pdev)
> {
>          struct ipp_context *ctx = platform_get_drvdata(pdev);
>
>          /* unregister sub driver */
>          exynos_drm_subdrv_unregister(&ctx->subdrv);
>
>          /* remove,destroy ipp idr */
>          idr_destroy(&ctx->ipp_idr);
>          idr_destroy(&ctx->prop_idr);
>
>          mutex_destroy(&ctx->ipp_lock);
>          mutex_destroy(&ctx->prop_lock);
>
>          /* destroy command, event work queue */
>          destroy_workqueue(ctx->cmd_workq);
>          destroy_workqueue(ctx->event_workq);
>
>          return 0;
> }
>
> int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
> {
>          if (!subdrv)
>                  return -EINVAL;
>
>          list_del(&subdrv->list);
>
>          return 0;
> }
>
> Oh dear, that destroys a whole pile of resources which could already
> be in use without telling anything that it's about to do that.
>
> I'm sure if I continue looking at the exynos stuff, it'll show similar
> crap all over the place.
>
> What you have now in mainline is not a solution.  It's a crappy bodge.
>

Undoubtedly. Nobody here is trying to state the opposite.

Maybe my words have been misinterpreted, but all I'm suggesting here is 
that there is no need to add any new data to DT to solve the same issue 
to the same extent as componentized subsystem framework, at least in 
Exynos case.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-05 18:31             ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 18:31 UTC (permalink / raw)
  To: linux-arm-kernel



On 05.04.2014 20:24, Russell King - ARM Linux wrote:
> On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
>> Not exactly. The approach we found does mostly the same as componentized
>> subsystem framework but without _any_ extra data in Device Tree. Just
>> based on the list of subsystem sub-drivers that is already available to
>> the master driver.
>
> The existing approach is fundamentally broken.  Yes, your solution may
> work for the probing case, but have you tried unbinding any of your
> sub-drivers?
>
>  From what I can see, that causes a kernel oops for one very simple reason -
> you destroy stuff while it's still in use.  Let's look at an example:
>
> struct platform_driver ipp_driver = {
>          .probe          = ipp_probe,
>          .remove         = ipp_remove,
>          .driver         = {
>                  .name   = "exynos-drm-ipp",
>                  .owner  = THIS_MODULE,
>                  .pm     = &ipp_pm_ops,
>          },
> };
>
> static int ipp_remove(struct platform_device *pdev)
> {
>          struct ipp_context *ctx = platform_get_drvdata(pdev);
>
>          /* unregister sub driver */
>          exynos_drm_subdrv_unregister(&ctx->subdrv);
>
>          /* remove,destroy ipp idr */
>          idr_destroy(&ctx->ipp_idr);
>          idr_destroy(&ctx->prop_idr);
>
>          mutex_destroy(&ctx->ipp_lock);
>          mutex_destroy(&ctx->prop_lock);
>
>          /* destroy command, event work queue */
>          destroy_workqueue(ctx->cmd_workq);
>          destroy_workqueue(ctx->event_workq);
>
>          return 0;
> }
>
> int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
> {
>          if (!subdrv)
>                  return -EINVAL;
>
>          list_del(&subdrv->list);
>
>          return 0;
> }
>
> Oh dear, that destroys a whole pile of resources which could already
> be in use without telling anything that it's about to do that.
>
> I'm sure if I continue looking at the exynos stuff, it'll show similar
> crap all over the place.
>
> What you have now in mainline is not a solution.  It's a crappy bodge.
>

Undoubtedly. Nobody here is trying to state the opposite.

Maybe my words have been misinterpreted, but all I'm suggesting here is 
that there is no need to add any new data to DT to solve the same issue 
to the same extent as componentized subsystem framework, at least in 
Exynos case.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 18:31             ` Tomasz Figa
@ 2014-04-05 18:52               ` Russell King - ARM Linux
  -1 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-05 18:52 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Inki Dae, Tomasz Figa, linux-samsung-soc, Arnd Bergmann,
	Dave Airlie, dri-devel, a.hajda, kyungmin.park, Daniel Vetter,
	Olof Johansson, linux-arm-kernel, Marek Szyprowski

On Sat, Apr 05, 2014 at 08:31:15PM +0200, Tomasz Figa wrote:
> Maybe my words have been misinterpreted, but all I'm suggesting here is  
> that there is no need to add any new data to DT to solve the same issue  
> to the same extent as componentized subsystem framework, at least in  
> Exynos case.

Right, so we seem to have agreement that what exynos is currently doing
is fundamentally broken.

So the next question is, how is it going to get fixed?

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-05 18:52               ` Russell King - ARM Linux
  0 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-05 18:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Apr 05, 2014 at 08:31:15PM +0200, Tomasz Figa wrote:
> Maybe my words have been misinterpreted, but all I'm suggesting here is  
> that there is no need to add any new data to DT to solve the same issue  
> to the same extent as componentized subsystem framework, at least in  
> Exynos case.

Right, so we seem to have agreement that what exynos is currently doing
is fundamentally broken.

So the next question is, how is it going to get fixed?

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 18:52               ` Russell King - ARM Linux
@ 2014-04-05 19:01                 ` Tomasz Figa
  -1 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 19:01 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski

On 05.04.2014 20:52, Russell King - ARM Linux wrote:
> On Sat, Apr 05, 2014 at 08:31:15PM +0200, Tomasz Figa wrote:
>> Maybe my words have been misinterpreted, but all I'm suggesting here is
>> that there is no need to add any new data to DT to solve the same issue
>> to the same extent as componentized subsystem framework, at least in
>> Exynos case.
>
> Right, so we seem to have agreement that what exynos is currently doing
> is fundamentally broken.
>
> So the next question is, how is it going to get fixed?
>

I believe this is a separate issue from what is being discussed in this 
thread, but anyway, I'd wait with this until Monday, so we could discuss 
this with Inki and Andrzej, who is the person responsible for Exynos DRM 
in my team. I was just passing by. ;)

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-05 19:01                 ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-05 19:01 UTC (permalink / raw)
  To: linux-arm-kernel

On 05.04.2014 20:52, Russell King - ARM Linux wrote:
> On Sat, Apr 05, 2014 at 08:31:15PM +0200, Tomasz Figa wrote:
>> Maybe my words have been misinterpreted, but all I'm suggesting here is
>> that there is no need to add any new data to DT to solve the same issue
>> to the same extent as componentized subsystem framework, at least in
>> Exynos case.
>
> Right, so we seem to have agreement that what exynos is currently doing
> is fundamentally broken.
>
> So the next question is, how is it going to get fixed?
>

I believe this is a separate issue from what is being discussed in this 
thread, but anyway, I'd wait with this until Monday, so we could discuss 
this with Inki and Andrzej, who is the person responsible for Exynos DRM 
in my team. I was just passing by. ;)

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 17:32         ` Tomasz Figa
@ 2014-04-06  3:15           ` Inki Dae
  -1 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  3:15 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Tomasz Figa, linux-samsung-soc, Arnd Bergmann, DRI mailing list,
	Andrzej Hajda, Kyungmin Park, linux-arm-kernel, Marek Szyprowski

I'd be really happy if you gave me such opinions before pull request.

Anyway, below is my comments.

2014-04-06 2:32 GMT+09:00 Tomasz Figa <tomasz.figa@gmail.com>:
> [adding more people and MLs on Cc for further discussion]
>
>
> On 04.04.2014 17:44, Inki Dae wrote:
>>
>> 2014-04-04 22:55 GMT+09:00 Tomasz Figa <t.figa@samsung.com>:
>>>
>>> Hi Inki,
>>>
>>>
>>> On 01.04.2014 14:37, 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.
>>>
>>>
>>>
>>> I can see several problems with this approach:
>>>
>>> 1) It breaks compatibility with existing DT. After this patch it is no
>>> longer possible to use old device trees and get a working DRM. However,
>>> in
>>> my opinion, this requirement can be relaxed if we make sure that any
>>> users
>>> are properly converted.
>>>
>>> 2) What happens if in Kconfig you disable a driver for a component that
>>> is
>>
>>
>> I'm not sure what you meant but there wouldn't be no way that users
>> *cannot disable* the driver for a component. The driver would be
>> exynos_drm_drv, not separated module, and would always be built as
>> long as users want to use *exynos drm driver*.
>
>
> I think you don't understand what I mean. Let me show you an example:
>
> You have a board with a DSI panel and also a HDMI output. So you have a
> supernode pointing to FIMD, DSI and HDMI.
>
> Now, an user finds that he doesn't need HDMI in his system, so he turns off
> CONFIG_DRM_EXYNOS_HDMI. The supernode still points at hdmi node and Exynos
> DRM core will register it as a component, but HDMI driver is not available
> and will never probe, leading the whole Exynos DRM to never initialize. Is
> this a desired behavior?
>

Ok, now I understood. Your comment was not enough to me.

First of all, if I see component codes correctly then it seems your
misunderstanding. See the below comments,

>
>>
>>> listed in supernode? If I'm reading the code correctly, Exynos DRM will
>>> not
>>
>>
>> And the only case a component isn't added to the list is when users
>> disabled sub driver.
>
>
> See above.
>
> The code creating the list of components to wait for
> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
> actually enabled in kernel config.
>

Are you sure?

exynos_drm_add_components() will try to attach components *added to
component_lists. And these components will be added by only
corresponding sub drivers to the component_lists and
master->components.

So in this case, if users disabled HDMI support then a commponent
object for HDMI sub driver doesn't exists in the component_lists and
master->components. This means that a component object for HDMI sub
driver *cannot be attached to master object*.

As a result, component_bind_add() will ignor component_bind call for
HDMI sub driver so HDMI driver will not be bounded. The only
components added by sub drivers will be bound, component->ops->bind().

For more understanding, it seems like you need to look into below codes,

static int exynos_drm_add_components(...)
{
        ...
        for (i == 0;; i++) {
                ...
                node = of_parse_phandle(np, "ports", i);
                ...
                ret = component_master_add_child(m, compare_of, node);
                ...
        }
}


And below codes,

int component_master_add_child(...)
{
        list_for_each_entry(c, &component_list, node) {
                if (c->master)
                        continue;

                if (compare(...)) {
                         component_attach_master(master, c);
                         ...
                }
        }
}

And below codes,

static void component_attach_master(master, c)
{
        c->master = master;
        list_add_tail(&c->master_node, &master->comonents);
}


As you can see above, the only components added to component_list can
be attached to master. And the important thing is that components can
be added by sub drivers to the component_list.

And below codes that actually tries to bind each sub drivers,

int component_bind_add(...)
{
        ....
        list_for_each_entry(c, &master->components, master_node) {
                   ret = component_bind(c, master, data);
                   ...
        }
        ...
}

The hdmi driver users disabled doesn't exist to master->components list.
How Exynos DRM cannot be initialized?

Of course, there may be my missing point, but I think I see them
correctly. Anyway I will test them tomorrow.

Thanks,
Inki Dae

>
>>> register, which is completely wrong. Users should be able to select which
>>> drivers should be compiled into their kernels.
>>
>>
>> So users are be able to select drivers they want to use, and will be
>> compiled correctly. So no, the only thing users can disable is each
>> sub driver, not core module.
>>
>>>
>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>> without possibility of loading some sub-drivers as modules. I know that
>>> current driver design doesn't support it either, but if this series is
>>
>>
>> No, current drm driver *must also be built* as one integrated single
>> drm driver without super device approach.
>
>
> As I wrote, I know that current design before this patch isn't modular
> either, but this is not my concern here. See below.
>
>
>> So the super device approach
>> *has no any effect on existing design*,  and what the super device
>> approch tries to do is to resolve the probe order issue to sub drivers
>> *without some codes specific to Exynos drm*.
>
>
> My concern is that the supernode design is actually carving such broken
> non-modular design in stone. Remember that we are currently heading towards
> a fully multi-platform kernel where it is critical for such subsystems to be
> modular, because the same zImage is going to be running on completely
> different machines.
>
>
>>
>>> claimed to improve things, it should really do so.
>>>
>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>> all.
>>> In fact even without adding any new single property or node to DT. We
>>> discussed this with Andrzej and Marek today and came to a solution in
>>> which
>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>> weekend.
>>
>>
>> I'm not sure but I had implemented below prototype codes for that, see
>> the below link,
>>
>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>
>> I guess what you said would be similler approach.
>
>
> Not exactly. The approach we found does mostly the same as componentized
> subsystem framework but without _any_ extra data in Device Tree. Just based
> on the list of subsystem sub-drivers that is already available to the master
> driver.
>
>
>>
>> And I still think the use of the component framework would be the best
>> solution and *Linux generic way* for resolving the probe order issue
>> without any specific codes. So I'm not advocating the compoent
>> framework but I tend not to want to use specific codes.
>>
>
> I understand your concern. I also believe that generic frameworks should be
> reused wherever possible. However the componentized subsystem framework is a
> bit of overkill for this simple problem. Moreover, Device Tree is not a
> trash can where any data that can be thought of can be thrown as you go, but
> rather a hardware description that is supposed to be a stable ABI and needs
> to be well-thought. So, if something can be done in a way that doesn't
> require additional data, it's better to do it that way.
>
>
>>>
>>> 5) This series seems to break DPI display support with runtime PM
>>> enabled.
>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>> with
>>> probe deferral. This needs more investigation, though.
>>
>>
>> For -next, I never expect that pm operations would be operated
>> perfactly. They are really not for product. Just adding new feature
>> and drivers to -next, and then fixing them while in RC. And RC process
>> would also be for it. Actually, I see pm interfaces of exynos_drm_dsi
>> driver leads to break a single driver model because pm operations
>> should be done at top level of exynos drm, and some codes Sean didn't
>> fix. So such things are in my fix-todo-list. I tend to accept new
>> features and drivers for -next as long as they have no big problem,
>> And that is my style I maintain.
>
>
> Unless it breaks so much that the system is unable to boot at all, which is
> the case. As I said, the system just hangs, like something would access
> hardware that is not properly initialized, e.g. without power domain or
> clocks enabled.
>
> Anyway, I don't agree that regressions are allowed in linux-next, especially
> if found before applying a patch. Linux-next is a tree in which patches that
> are supposed to be ready to be pulled by Linus should be pushed. Of course
> nobody can spot all the regressions before the patches hitting -next and
> that's fine, as -next is an integration _testing_ tree. However even if
> already in -next, regressions should be fixed ASAP to minimize the number of
> fix patches needed during -rc period.
>
>
> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-06  3:15           ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  3:15 UTC (permalink / raw)
  To: linux-arm-kernel

I'd be really happy if you gave me such opinions before pull request.

Anyway, below is my comments.

2014-04-06 2:32 GMT+09:00 Tomasz Figa <tomasz.figa@gmail.com>:
> [adding more people and MLs on Cc for further discussion]
>
>
> On 04.04.2014 17:44, Inki Dae wrote:
>>
>> 2014-04-04 22:55 GMT+09:00 Tomasz Figa <t.figa@samsung.com>:
>>>
>>> Hi Inki,
>>>
>>>
>>> On 01.04.2014 14:37, 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.
>>>
>>>
>>>
>>> I can see several problems with this approach:
>>>
>>> 1) It breaks compatibility with existing DT. After this patch it is no
>>> longer possible to use old device trees and get a working DRM. However,
>>> in
>>> my opinion, this requirement can be relaxed if we make sure that any
>>> users
>>> are properly converted.
>>>
>>> 2) What happens if in Kconfig you disable a driver for a component that
>>> is
>>
>>
>> I'm not sure what you meant but there wouldn't be no way that users
>> *cannot disable* the driver for a component. The driver would be
>> exynos_drm_drv, not separated module, and would always be built as
>> long as users want to use *exynos drm driver*.
>
>
> I think you don't understand what I mean. Let me show you an example:
>
> You have a board with a DSI panel and also a HDMI output. So you have a
> supernode pointing to FIMD, DSI and HDMI.
>
> Now, an user finds that he doesn't need HDMI in his system, so he turns off
> CONFIG_DRM_EXYNOS_HDMI. The supernode still points at hdmi node and Exynos
> DRM core will register it as a component, but HDMI driver is not available
> and will never probe, leading the whole Exynos DRM to never initialize. Is
> this a desired behavior?
>

Ok, now I understood. Your comment was not enough to me.

First of all, if I see component codes correctly then it seems your
misunderstanding. See the below comments,

>
>>
>>> listed in supernode? If I'm reading the code correctly, Exynos DRM will
>>> not
>>
>>
>> And the only case a component isn't added to the list is when users
>> disabled sub driver.
>
>
> See above.
>
> The code creating the list of components to wait for
> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
> actually enabled in kernel config.
>

Are you sure?

exynos_drm_add_components() will try to attach components *added to
component_lists. And these components will be added by only
corresponding sub drivers to the component_lists and
master->components.

So in this case, if users disabled HDMI support then a commponent
object for HDMI sub driver doesn't exists in the component_lists and
master->components. This means that a component object for HDMI sub
driver *cannot be attached to master object*.

As a result, component_bind_add() will ignor component_bind call for
HDMI sub driver so HDMI driver will not be bounded. The only
components added by sub drivers will be bound, component->ops->bind().

For more understanding, it seems like you need to look into below codes,

static int exynos_drm_add_components(...)
{
        ...
        for (i == 0;; i++) {
                ...
                node = of_parse_phandle(np, "ports", i);
                ...
                ret = component_master_add_child(m, compare_of, node);
                ...
        }
}


And below codes,

int component_master_add_child(...)
{
        list_for_each_entry(c, &component_list, node) {
                if (c->master)
                        continue;

                if (compare(...)) {
                         component_attach_master(master, c);
                         ...
                }
        }
}

And below codes,

static void component_attach_master(master, c)
{
        c->master = master;
        list_add_tail(&c->master_node, &master->comonents);
}


As you can see above, the only components added to component_list can
be attached to master. And the important thing is that components can
be added by sub drivers to the component_list.

And below codes that actually tries to bind each sub drivers,

int component_bind_add(...)
{
        ....
        list_for_each_entry(c, &master->components, master_node) {
                   ret = component_bind(c, master, data);
                   ...
        }
        ...
}

The hdmi driver users disabled doesn't exist to master->components list.
How Exynos DRM cannot be initialized?

Of course, there may be my missing point, but I think I see them
correctly. Anyway I will test them tomorrow.

Thanks,
Inki Dae

>
>>> register, which is completely wrong. Users should be able to select which
>>> drivers should be compiled into their kernels.
>>
>>
>> So users are be able to select drivers they want to use, and will be
>> compiled correctly. So no, the only thing users can disable is each
>> sub driver, not core module.
>>
>>>
>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>> without possibility of loading some sub-drivers as modules. I know that
>>> current driver design doesn't support it either, but if this series is
>>
>>
>> No, current drm driver *must also be built* as one integrated single
>> drm driver without super device approach.
>
>
> As I wrote, I know that current design before this patch isn't modular
> either, but this is not my concern here. See below.
>
>
>> So the super device approach
>> *has no any effect on existing design*,  and what the super device
>> approch tries to do is to resolve the probe order issue to sub drivers
>> *without some codes specific to Exynos drm*.
>
>
> My concern is that the supernode design is actually carving such broken
> non-modular design in stone. Remember that we are currently heading towards
> a fully multi-platform kernel where it is critical for such subsystems to be
> modular, because the same zImage is going to be running on completely
> different machines.
>
>
>>
>>> claimed to improve things, it should really do so.
>>>
>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>> all.
>>> In fact even without adding any new single property or node to DT. We
>>> discussed this with Andrzej and Marek today and came to a solution in
>>> which
>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>> weekend.
>>
>>
>> I'm not sure but I had implemented below prototype codes for that, see
>> the below link,
>>
>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>
>> I guess what you said would be similler approach.
>
>
> Not exactly. The approach we found does mostly the same as componentized
> subsystem framework but without _any_ extra data in Device Tree. Just based
> on the list of subsystem sub-drivers that is already available to the master
> driver.
>
>
>>
>> And I still think the use of the component framework would be the best
>> solution and *Linux generic way* for resolving the probe order issue
>> without any specific codes. So I'm not advocating the compoent
>> framework but I tend not to want to use specific codes.
>>
>
> I understand your concern. I also believe that generic frameworks should be
> reused wherever possible. However the componentized subsystem framework is a
> bit of overkill for this simple problem. Moreover, Device Tree is not a
> trash can where any data that can be thought of can be thrown as you go, but
> rather a hardware description that is supposed to be a stable ABI and needs
> to be well-thought. So, if something can be done in a way that doesn't
> require additional data, it's better to do it that way.
>
>
>>>
>>> 5) This series seems to break DPI display support with runtime PM
>>> enabled.
>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>> with
>>> probe deferral. This needs more investigation, though.
>>
>>
>> For -next, I never expect that pm operations would be operated
>> perfactly. They are really not for product. Just adding new feature
>> and drivers to -next, and then fixing them while in RC. And RC process
>> would also be for it. Actually, I see pm interfaces of exynos_drm_dsi
>> driver leads to break a single driver model because pm operations
>> should be done at top level of exynos drm, and some codes Sean didn't
>> fix. So such things are in my fix-todo-list. I tend to accept new
>> features and drivers for -next as long as they have no big problem,
>> And that is my style I maintain.
>
>
> Unless it breaks so much that the system is unable to boot at all, which is
> the case. As I said, the system just hangs, like something would access
> hardware that is not properly initialized, e.g. without power domain or
> clocks enabled.
>
> Anyway, I don't agree that regressions are allowed in linux-next, especially
> if found before applying a patch. Linux-next is a tree in which patches that
> are supposed to be ready to be pulled by Linus should be pushed. Of course
> nobody can spot all the regressions before the patches hitting -next and
> that's fine, as -next is an integration _testing_ tree. However even if
> already in -next, regressions should be fixed ASAP to minimize the number of
> fix patches needed during -rc period.
>
>
> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-05 18:31             ` Tomasz Figa
@ 2014-04-06  4:21               ` Inki Dae
  -1 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  4:21 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: linux-samsung-soc, Russell King - ARM Linux, Arnd Bergmann,
	dri-devel, a.hajda, kyungmin.park, linux-arm-kernel,
	Marek Szyprowski

2014-04-06 3:31 GMT+09:00, Tomasz Figa <tomasz.figa@gmail.com>:
>
>
> On 05.04.2014 20:24, Russell King - ARM Linux wrote:
>> On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just
>>> based on the list of subsystem sub-drivers that is already available to
>>> the master driver.
>>
>> The existing approach is fundamentally broken.  Yes, your solution may
>> work for the probing case, but have you tried unbinding any of your
>> sub-drivers?
>>
>>  From what I can see, that causes a kernel oops for one very simple reason
>> -
>> you destroy stuff while it's still in use.  Let's look at an example:
>>
>> struct platform_driver ipp_driver = {
>>          .probe          = ipp_probe,
>>          .remove         = ipp_remove,
>>          .driver         = {
>>                  .name   = "exynos-drm-ipp",
>>                  .owner  = THIS_MODULE,
>>                  .pm     = &ipp_pm_ops,
>>          },
>> };
>>
>> static int ipp_remove(struct platform_device *pdev)
>> {
>>          struct ipp_context *ctx = platform_get_drvdata(pdev);
>>
>>          /* unregister sub driver */
>>          exynos_drm_subdrv_unregister(&ctx->subdrv);
>>
>>          /* remove,destroy ipp idr */
>>          idr_destroy(&ctx->ipp_idr);
>>          idr_destroy(&ctx->prop_idr);
>>
>>          mutex_destroy(&ctx->ipp_lock);
>>          mutex_destroy(&ctx->prop_lock);
>>
>>          /* destroy command, event work queue */
>>          destroy_workqueue(ctx->cmd_workq);
>>          destroy_workqueue(ctx->event_workq);
>>
>>          return 0;
>> }
>>
>> int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
>> {
>>          if (!subdrv)
>>                  return -EINVAL;
>>
>>          list_del(&subdrv->list);
>>
>>          return 0;
>> }
>>
>> Oh dear, that destroys a whole pile of resources which could already
>> be in use without telling anything that it's about to do that.
>>
>> I'm sure if I continue looking at the exynos stuff, it'll show similar
>> crap all over the place.
>>
>> What you have now in mainline is not a solution.  It's a crappy bodge.
>>
>
> Undoubtedly. Nobody here is trying to state the opposite.
>
> Maybe my words have been misinterpreted, but all I'm suggesting here is
> that there is no need to add any new data to DT to solve the same issue
> to the same extent as componentized subsystem framework, at least in
> Exynos case.

As you may know, there is exynos chip that has two display
controllers. So it is possible to compose display pipe lines at same
time like below,

fimd0-----bridges..------Panel
fimd1-----maybe bridges..-----CPU Panel

How we can care such pipelines without component? Of course, it would
be possible somehow but I'm not sure there could be better and more
generic way than super device.

And super device will make existing dtb broken but this time it might
be good opportunity to more generic way before more users use existing
dt.

Thanks,
Inki Dae
>
> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-06  4:21               ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  4:21 UTC (permalink / raw)
  To: linux-arm-kernel

2014-04-06 3:31 GMT+09:00, Tomasz Figa <tomasz.figa@gmail.com>:
>
>
> On 05.04.2014 20:24, Russell King - ARM Linux wrote:
>> On Sat, Apr 05, 2014 at 07:32:50PM +0200, Tomasz Figa wrote:
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just
>>> based on the list of subsystem sub-drivers that is already available to
>>> the master driver.
>>
>> The existing approach is fundamentally broken.  Yes, your solution may
>> work for the probing case, but have you tried unbinding any of your
>> sub-drivers?
>>
>>  From what I can see, that causes a kernel oops for one very simple reason
>> -
>> you destroy stuff while it's still in use.  Let's look at an example:
>>
>> struct platform_driver ipp_driver = {
>>          .probe          = ipp_probe,
>>          .remove         = ipp_remove,
>>          .driver         = {
>>                  .name   = "exynos-drm-ipp",
>>                  .owner  = THIS_MODULE,
>>                  .pm     = &ipp_pm_ops,
>>          },
>> };
>>
>> static int ipp_remove(struct platform_device *pdev)
>> {
>>          struct ipp_context *ctx = platform_get_drvdata(pdev);
>>
>>          /* unregister sub driver */
>>          exynos_drm_subdrv_unregister(&ctx->subdrv);
>>
>>          /* remove,destroy ipp idr */
>>          idr_destroy(&ctx->ipp_idr);
>>          idr_destroy(&ctx->prop_idr);
>>
>>          mutex_destroy(&ctx->ipp_lock);
>>          mutex_destroy(&ctx->prop_lock);
>>
>>          /* destroy command, event work queue */
>>          destroy_workqueue(ctx->cmd_workq);
>>          destroy_workqueue(ctx->event_workq);
>>
>>          return 0;
>> }
>>
>> int exynos_drm_subdrv_unregister(struct exynos_drm_subdrv *subdrv)
>> {
>>          if (!subdrv)
>>                  return -EINVAL;
>>
>>          list_del(&subdrv->list);
>>
>>          return 0;
>> }
>>
>> Oh dear, that destroys a whole pile of resources which could already
>> be in use without telling anything that it's about to do that.
>>
>> I'm sure if I continue looking at the exynos stuff, it'll show similar
>> crap all over the place.
>>
>> What you have now in mainline is not a solution.  It's a crappy bodge.
>>
>
> Undoubtedly. Nobody here is trying to state the opposite.
>
> Maybe my words have been misinterpreted, but all I'm suggesting here is
> that there is no need to add any new data to DT to solve the same issue
> to the same extent as componentized subsystem framework, at least in
> Exynos case.

As you may know, there is exynos chip that has two display
controllers. So it is possible to compose display pipe lines at same
time like below,

fimd0-----bridges..------Panel
fimd1-----maybe bridges..-----CPU Panel

How we can care such pipelines without component? Of course, it would
be possible somehow but I'm not sure there could be better and more
generic way than super device.

And super device will make existing dtb broken but this time it might
be good opportunity to more generic way before more users use existing
dt.

Thanks,
Inki Dae
>
> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-06  4:21               ` Inki Dae
@ 2014-04-06  8:47                 ` Russell King - ARM Linux
  -1 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-06  8:47 UTC (permalink / raw)
  To: Inki Dae
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski

On Sun, Apr 06, 2014 at 01:21:24PM +0900, Inki Dae wrote:
> As you may know, there is exynos chip that has two display
> controllers. So it is possible to compose display pipe lines at same
> time like below,
> 
> fimd0-----bridges..------Panel
> fimd1-----maybe bridges..-----CPU Panel
> 
> How we can care such pipelines without component? Of course, it would
> be possible somehow but I'm not sure there could be better and more
> generic way than super device.
> 
> And super device will make existing dtb broken but this time it might
> be good opportunity to more generic way before more users use existing
> dt.

There has been a discussion ongoing about how to best represent display
(and capture) stuff in DT using graphs, which you may wish to consider
looking at.  That discussion never reached any kind of conclusion before
the merge window, but it does need to reach a conclusion for the next
window.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-06  8:47                 ` Russell King - ARM Linux
  0 siblings, 0 replies; 47+ messages in thread
From: Russell King - ARM Linux @ 2014-04-06  8:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Apr 06, 2014 at 01:21:24PM +0900, Inki Dae wrote:
> As you may know, there is exynos chip that has two display
> controllers. So it is possible to compose display pipe lines at same
> time like below,
> 
> fimd0-----bridges..------Panel
> fimd1-----maybe bridges..-----CPU Panel
> 
> How we can care such pipelines without component? Of course, it would
> be possible somehow but I'm not sure there could be better and more
> generic way than super device.
> 
> And super device will make existing dtb broken but this time it might
> be good opportunity to more generic way before more users use existing
> dt.

There has been a discussion ongoing about how to best represent display
(and capture) stuff in DT using graphs, which you may wish to consider
looking at.  That discussion never reached any kind of conclusion before
the merge window, but it does need to reach a conclusion for the next
window.

-- 
FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
improving, and getting towards what was expected from it.

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-06  8:47                 ` Russell King - ARM Linux
@ 2014-04-06  9:38                   ` Inki Dae
  -1 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  9:38 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-samsung-soc, Arnd Bergmann, dri-devel, a.hajda,
	kyungmin.park, linux-arm-kernel, Marek Szyprowski

Hi Russell,

2014-04-06 17:47 GMT+09:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Sun, Apr 06, 2014 at 01:21:24PM +0900, Inki Dae wrote:
>> As you may know, there is exynos chip that has two display
>> controllers. So it is possible to compose display pipe lines at same
>> time like below,
>>
>> fimd0-----bridges..------Panel
>> fimd1-----maybe bridges..-----CPU Panel
>>
>> How we can care such pipelines without component? Of course, it would
>> be possible somehow but I'm not sure there could be better and more
>> generic way than super device.
>>
>> And super device will make existing dtb broken but this time it might
>> be good opportunity to more generic way before more users use existing
>> dt.
>
> There has been a discussion ongoing about how to best represent display
> (and capture) stuff in DT using graphs, which you may wish to consider

Right, there was my wrong comments. Actually, I had made a discussion
about it. For this, you can refer to below link,
http://www.spinics.net/lists/dri-devel/msg55555.html

My intension there was that let's use super device approach to resolve
the probe order issue of drm drivers for embedded system, and the
graphs to compose their display pipelines. And for this, we need
generic common structure to handle various bridge devices that could
be controlled by crtc and encoder/connector drivers.

I'd be happy to get your opinions about it.

> looking at.  That discussion never reached any kind of conclusion before
> the merge window, but it does need to reach a conclusion for the next
> window.

Yes. I still think the super device approach is a best solution, and I
think the only problem here is backward compatibility.  I have a feel
that we might resolve that issue easier then we think. I think all we
have to do for it is to implement some codes for backward
compatibility on top of super device approach.

This way, we could have a better design for the future drm drivers
without being tied to the backward compatibility.

Thanks,
Inki Dae

>
> --
> FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
> improving, and getting towards what was expected from it.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-06  9:38                   ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-06  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

2014-04-06 17:47 GMT+09:00 Russell King - ARM Linux <linux@arm.linux.org.uk>:
> On Sun, Apr 06, 2014 at 01:21:24PM +0900, Inki Dae wrote:
>> As you may know, there is exynos chip that has two display
>> controllers. So it is possible to compose display pipe lines at same
>> time like below,
>>
>> fimd0-----bridges..------Panel
>> fimd1-----maybe bridges..-----CPU Panel
>>
>> How we can care such pipelines without component? Of course, it would
>> be possible somehow but I'm not sure there could be better and more
>> generic way than super device.
>>
>> And super device will make existing dtb broken but this time it might
>> be good opportunity to more generic way before more users use existing
>> dt.
>
> There has been a discussion ongoing about how to best represent display
> (and capture) stuff in DT using graphs, which you may wish to consider

Right, there was my wrong comments. Actually, I had made a discussion
about it. For this, you can refer to below link,
http://www.spinics.net/lists/dri-devel/msg55555.html

My intension there was that let's use super device approach to resolve
the probe order issue of drm drivers for embedded system, and the
graphs to compose their display pipelines. And for this, we need
generic common structure to handle various bridge devices that could
be controlled by crtc and encoder/connector drivers.

I'd be happy to get your opinions about it.

> looking at.  That discussion never reached any kind of conclusion before
> the merge window, but it does need to reach a conclusion for the next
> window.

Yes. I still think the super device approach is a best solution, and I
think the only problem here is backward compatibility.  I have a feel
that we might resolve that issue easier then we think. I think all we
have to do for it is to implement some codes for backward
compatibility on top of super device approach.

This way, we could have a better design for the future drm drivers
without being tied to the backward compatibility.

Thanks,
Inki Dae

>
> --
> FTTC broadband for 0.8mile line: now at 9.7Mbps down 460kbps up... slowly
> improving, and getting towards what was expected from it.
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-06  3:15           ` Inki Dae
@ 2014-04-07 14:18             ` Andrzej Hajda
  -1 siblings, 0 replies; 47+ messages in thread
From: Andrzej Hajda @ 2014-04-07 14:18 UTC (permalink / raw)
  To: Inki Dae, Tomasz Figa
  Cc: Tomasz Figa, linux-samsung-soc, Arnd Bergmann, DRI mailing list,
	Kyungmin Park, linux-arm-kernel, Marek Szyprowski

Hi Inki and Tomasz,

On 04/06/2014 05:15 AM, Inki Dae wrote:

(...)
> The code creating the list of components to wait for
> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
> actually enabled in kernel config.
>
> Are you sure?
>
> exynos_drm_add_components() will try to attach components *added to
> component_lists. And these components will be added by only
> corresponding sub drivers to the component_lists and
> master->components.
>
> So in this case, if users disabled HDMI support then a commponent
> object for HDMI sub driver doesn't exists in the component_lists and
> master->components. This means that a component object for HDMI sub
> driver *cannot be attached to master object*.
>
> As a result, component_bind_add() will ignor component_bind call for
> HDMI sub driver so HDMI driver will not be bounded. The only
> components added by sub drivers will be bound, component->ops->bind().
>
> For more understanding, it seems like you need to look into below codes,
>
> static int exynos_drm_add_components(...)
> {
>         ...
>         for (i == 0;; i++) {
>                 ...
>                 node = of_parse_phandle(np, "ports", i);
>                 ...
>                 ret = component_master_add_child(m, compare_of, node);
>                 ...
>         }
> }

Hmm, In case HDMI driver is not present, HDMI device is not probed and
HDMI component is not added, so component_master_add_child returns
an error when it tries to add hdmi component and master is never brought
up, am I correct?

>
>
> And below codes,
>
> int component_master_add_child(...)
> {
>         list_for_each_entry(c, &component_list, node) {
>                 if (c->master)
>                         continue;
>
>                 if (compare(...)) {
>                          component_attach_master(master, c);
>                          ...
>                 }
>         }
> }
>
> And below codes,
>
> static void component_attach_master(master, c)
> {
>         c->master = master;
>         list_add_tail(&c->master_node, &master->comonents);
> }
>
>
> As you can see above, the only components added to component_list can
> be attached to master. And the important thing is that components can
> be added by sub drivers to the component_list.
>
> And below codes that actually tries to bind each sub drivers,
>
> int component_bind_add(...)
> {
>         ....
>         list_for_each_entry(c, &master->components, master_node) {
>                    ret = component_bind(c, master, data);
>                    ...
>         }
>         ...
> }
>
> The hdmi driver users disabled doesn't exist to master->components list.
> How Exynos DRM cannot be initialized?
>
> Of course, there may be my missing point, but I think I see them
> correctly. Anyway I will test them tomorrow.
>
> Thanks,
> Inki Dae
>
>>>> register, which is completely wrong. Users should be able to select which
>>>> drivers should be compiled into their kernels.
>>>
>>> So users are be able to select drivers they want to use, and will be
>>> compiled correctly. So no, the only thing users can disable is each
>>> sub driver, not core module.
>>>
>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>> without possibility of loading some sub-drivers as modules. I know that
>>>> current driver design doesn't support it either, but if this series is
>>>
>>> No, current drm driver *must also be built* as one integrated single
>>> drm driver without super device approach.
>>
>> As I wrote, I know that current design before this patch isn't modular
>> either, but this is not my concern here. See below.
>>
>>
>>> So the super device approach
>>> *has no any effect on existing design*,  and what the super device
>>> approch tries to do is to resolve the probe order issue to sub drivers
>>> *without some codes specific to Exynos drm*.
>>
>> My concern is that the supernode design is actually carving such broken
>> non-modular design in stone. Remember that we are currently heading towards
>> a fully multi-platform kernel where it is critical for such subsystems to be
>> modular, because the same zImage is going to be running on completely
>> different machines.
>>
>>
>>>> claimed to improve things, it should really do so.
>>>>
>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>> all.
>>>> In fact even without adding any new single property or node to DT. We
>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>> which
>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>> weekend.
>>>
>>> I'm not sure but I had implemented below prototype codes for that, see
>>> the below link,
>>>
>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>
>>> I guess what you said would be similler approach.
>>
>> Not exactly. The approach we found does mostly the same as componentized
>> subsystem framework but without _any_ extra data in Device Tree. Just based
>> on the list of subsystem sub-drivers that is already available to the master
>> driver.

I am not so sure which approach is better, anyway I hope to post RFC soon,
as some material for discussion.

>>
>>
>>> And I still think the use of the component framework would be the best
>>> solution and *Linux generic way* for resolving the probe order issue
>>> without any specific codes. So I'm not advocating the compoent
>>> framework but I tend not to want to use specific codes.
>>>
>> I understand your concern. I also believe that generic frameworks should be
>> reused wherever possible. However the componentized subsystem framework is a
>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>> trash can where any data that can be thought of can be thrown as you go, but
>> rather a hardware description that is supposed to be a stable ABI and needs
>> to be well-thought. So, if something can be done in a way that doesn't
>> require additional data, it's better to do it that way.
>>
>>
>>>> 5) This series seems to break DPI display support with runtime PM
>>>> enabled.
>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>> with
>>>> probe deferral. This needs more investigation, though.

If we are talking about the same issue, it is a problem of panel
initialization sequence on some
panels. I will post fix for it.


Regards
Andrzej

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-07 14:18             ` Andrzej Hajda
  0 siblings, 0 replies; 47+ messages in thread
From: Andrzej Hajda @ 2014-04-07 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Inki and Tomasz,

On 04/06/2014 05:15 AM, Inki Dae wrote:

(...)
> The code creating the list of components to wait for
> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
> actually enabled in kernel config.
>
> Are you sure?
>
> exynos_drm_add_components() will try to attach components *added to
> component_lists. And these components will be added by only
> corresponding sub drivers to the component_lists and
> master->components.
>
> So in this case, if users disabled HDMI support then a commponent
> object for HDMI sub driver doesn't exists in the component_lists and
> master->components. This means that a component object for HDMI sub
> driver *cannot be attached to master object*.
>
> As a result, component_bind_add() will ignor component_bind call for
> HDMI sub driver so HDMI driver will not be bounded. The only
> components added by sub drivers will be bound, component->ops->bind().
>
> For more understanding, it seems like you need to look into below codes,
>
> static int exynos_drm_add_components(...)
> {
>         ...
>         for (i == 0;; i++) {
>                 ...
>                 node = of_parse_phandle(np, "ports", i);
>                 ...
>                 ret = component_master_add_child(m, compare_of, node);
>                 ...
>         }
> }

Hmm, In case HDMI driver is not present, HDMI device is not probed and
HDMI component is not added, so component_master_add_child returns
an error when it tries to add hdmi component and master is never brought
up, am I correct?

>
>
> And below codes,
>
> int component_master_add_child(...)
> {
>         list_for_each_entry(c, &component_list, node) {
>                 if (c->master)
>                         continue;
>
>                 if (compare(...)) {
>                          component_attach_master(master, c);
>                          ...
>                 }
>         }
> }
>
> And below codes,
>
> static void component_attach_master(master, c)
> {
>         c->master = master;
>         list_add_tail(&c->master_node, &master->comonents);
> }
>
>
> As you can see above, the only components added to component_list can
> be attached to master. And the important thing is that components can
> be added by sub drivers to the component_list.
>
> And below codes that actually tries to bind each sub drivers,
>
> int component_bind_add(...)
> {
>         ....
>         list_for_each_entry(c, &master->components, master_node) {
>                    ret = component_bind(c, master, data);
>                    ...
>         }
>         ...
> }
>
> The hdmi driver users disabled doesn't exist to master->components list.
> How Exynos DRM cannot be initialized?
>
> Of course, there may be my missing point, but I think I see them
> correctly. Anyway I will test them tomorrow.
>
> Thanks,
> Inki Dae
>
>>>> register, which is completely wrong. Users should be able to select which
>>>> drivers should be compiled into their kernels.
>>>
>>> So users are be able to select drivers they want to use, and will be
>>> compiled correctly. So no, the only thing users can disable is each
>>> sub driver, not core module.
>>>
>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>> without possibility of loading some sub-drivers as modules. I know that
>>>> current driver design doesn't support it either, but if this series is
>>>
>>> No, current drm driver *must also be built* as one integrated single
>>> drm driver without super device approach.
>>
>> As I wrote, I know that current design before this patch isn't modular
>> either, but this is not my concern here. See below.
>>
>>
>>> So the super device approach
>>> *has no any effect on existing design*,  and what the super device
>>> approch tries to do is to resolve the probe order issue to sub drivers
>>> *without some codes specific to Exynos drm*.
>>
>> My concern is that the supernode design is actually carving such broken
>> non-modular design in stone. Remember that we are currently heading towards
>> a fully multi-platform kernel where it is critical for such subsystems to be
>> modular, because the same zImage is going to be running on completely
>> different machines.
>>
>>
>>>> claimed to improve things, it should really do so.
>>>>
>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>> all.
>>>> In fact even without adding any new single property or node to DT. We
>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>> which
>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>> weekend.
>>>
>>> I'm not sure but I had implemented below prototype codes for that, see
>>> the below link,
>>>
>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>
>>> I guess what you said would be similler approach.
>>
>> Not exactly. The approach we found does mostly the same as componentized
>> subsystem framework but without _any_ extra data in Device Tree. Just based
>> on the list of subsystem sub-drivers that is already available to the master
>> driver.

I am not so sure which approach is better, anyway I hope to post RFC soon,
as some material for discussion.

>>
>>
>>> And I still think the use of the component framework would be the best
>>> solution and *Linux generic way* for resolving the probe order issue
>>> without any specific codes. So I'm not advocating the compoent
>>> framework but I tend not to want to use specific codes.
>>>
>> I understand your concern. I also believe that generic frameworks should be
>> reused wherever possible. However the componentized subsystem framework is a
>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>> trash can where any data that can be thought of can be thrown as you go, but
>> rather a hardware description that is supposed to be a stable ABI and needs
>> to be well-thought. So, if something can be done in a way that doesn't
>> require additional data, it's better to do it that way.
>>
>>
>>>> 5) This series seems to break DPI display support with runtime PM
>>>> enabled.
>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>> with
>>>> probe deferral. This needs more investigation, though.

If we are talking about the same issue, it is a problem of panel
initialization sequence on some
panels. I will post fix for it.


Regards
Andrzej

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-07 14:18             ` Andrzej Hajda
@ 2014-04-07 14:24               ` Tomasz Figa
  -1 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-07 14:24 UTC (permalink / raw)
  To: Andrzej Hajda, Inki Dae
  Cc: linux-samsung-soc, Arnd Bergmann, DRI mailing list,
	Kyungmin Park, linux-arm-kernel, Marek Szyprowski

Hi Andrzej,

On 07.04.2014 16:18, Andrzej Hajda wrote:
> Hi Inki and Tomasz,
>
> On 04/06/2014 05:15 AM, Inki Dae wrote:
>
> (...)
>> The code creating the list of components to wait for
>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>> actually enabled in kernel config.
>>
>> Are you sure?
>>
>> exynos_drm_add_components() will try to attach components *added to
>> component_lists. And these components will be added by only
>> corresponding sub drivers to the component_lists and
>> master->components.
>>
>> So in this case, if users disabled HDMI support then a commponent
>> object for HDMI sub driver doesn't exists in the component_lists and
>> master->components. This means that a component object for HDMI sub
>> driver *cannot be attached to master object*.
>>
>> As a result, component_bind_add() will ignor component_bind call for
>> HDMI sub driver so HDMI driver will not be bounded. The only
>> components added by sub drivers will be bound, component->ops->bind().
>>
>> For more understanding, it seems like you need to look into below codes,
>>
>> static int exynos_drm_add_components(...)
>> {
>>          ...
>>          for (i == 0;; i++) {
>>                  ...
>>                  node = of_parse_phandle(np, "ports", i);
>>                  ...
>>                  ret = component_master_add_child(m, compare_of, node);
>>                  ...
>>          }
>> }
>
> Hmm, In case HDMI driver is not present, HDMI device is not probed and
> HDMI component is not added, so component_master_add_child returns
> an error when it tries to add hdmi component and master is never brought
> up, am I correct?
>

This is my thought here as well.

>>
>>
>> And below codes,
>>
>> int component_master_add_child(...)
>> {
>>          list_for_each_entry(c, &component_list, node) {
>>                  if (c->master)
>>                          continue;
>>
>>                  if (compare(...)) {
>>                           component_attach_master(master, c);
>>                           ...
>>                  }
>>          }
>> }
>>
>> And below codes,
>>
>> static void component_attach_master(master, c)
>> {
>>          c->master = master;
>>          list_add_tail(&c->master_node, &master->comonents);
>> }
>>
>>
>> As you can see above, the only components added to component_list can
>> be attached to master. And the important thing is that components can
>> be added by sub drivers to the component_list.
>>
>> And below codes that actually tries to bind each sub drivers,
>>
>> int component_bind_add(...)
>> {
>>          ....
>>          list_for_each_entry(c, &master->components, master_node) {
>>                     ret = component_bind(c, master, data);
>>                     ...
>>          }
>>          ...
>> }
>>
>> The hdmi driver users disabled doesn't exist to master->components list.
>> How Exynos DRM cannot be initialized?
>>
>> Of course, there may be my missing point, but I think I see them
>> correctly. Anyway I will test them tomorrow.
>>
>> Thanks,
>> Inki Dae
>>
>>>>> register, which is completely wrong. Users should be able to select which
>>>>> drivers should be compiled into their kernels.
>>>>
>>>> So users are be able to select drivers they want to use, and will be
>>>> compiled correctly. So no, the only thing users can disable is each
>>>> sub driver, not core module.
>>>>
>>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>>> without possibility of loading some sub-drivers as modules. I know that
>>>>> current driver design doesn't support it either, but if this series is
>>>>
>>>> No, current drm driver *must also be built* as one integrated single
>>>> drm driver without super device approach.
>>>
>>> As I wrote, I know that current design before this patch isn't modular
>>> either, but this is not my concern here. See below.
>>>
>>>
>>>> So the super device approach
>>>> *has no any effect on existing design*,  and what the super device
>>>> approch tries to do is to resolve the probe order issue to sub drivers
>>>> *without some codes specific to Exynos drm*.
>>>
>>> My concern is that the supernode design is actually carving such broken
>>> non-modular design in stone. Remember that we are currently heading towards
>>> a fully multi-platform kernel where it is critical for such subsystems to be
>>> modular, because the same zImage is going to be running on completely
>>> different machines.
>>>
>>>
>>>>> claimed to improve things, it should really do so.
>>>>>
>>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>>> all.
>>>>> In fact even without adding any new single property or node to DT. We
>>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>>> which
>>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>>> weekend.
>>>>
>>>> I'm not sure but I had implemented below prototype codes for that, see
>>>> the below link,
>>>>
>>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>>
>>>> I guess what you said would be similler approach.
>>>
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just based
>>> on the list of subsystem sub-drivers that is already available to the master
>>> driver.
>
> I am not so sure which approach is better, anyway I hope to post RFC soon,
> as some material for discussion.
>

Great. Looking forward for it.

>>>
>>>
>>>> And I still think the use of the component framework would be the best
>>>> solution and *Linux generic way* for resolving the probe order issue
>>>> without any specific codes. So I'm not advocating the compoent
>>>> framework but I tend not to want to use specific codes.
>>>>
>>> I understand your concern. I also believe that generic frameworks should be
>>> reused wherever possible. However the componentized subsystem framework is a
>>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>>> trash can where any data that can be thought of can be thrown as you go, but
>>> rather a hardware description that is supposed to be a stable ABI and needs
>>> to be well-thought. So, if something can be done in a way that doesn't
>>> require additional data, it's better to do it that way.
>>>
>>>
>>>>> 5) This series seems to break DPI display support with runtime PM
>>>>> enabled.
>>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>>> with
>>>>> probe deferral. This needs more investigation, though.
>
> If we are talking about the same issue, it is a problem of panel
> initialization sequence on some
> panels. I will post fix for it.

That's possible.

I'm not saying that it's a problem of this series itself, but it has 
been introduced/triggered by this series. My intention was to point that 
such issues need to be investigated before pushing the patches upstream.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-07 14:24               ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-07 14:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andrzej,

On 07.04.2014 16:18, Andrzej Hajda wrote:
> Hi Inki and Tomasz,
>
> On 04/06/2014 05:15 AM, Inki Dae wrote:
>
> (...)
>> The code creating the list of components to wait for
>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>> actually enabled in kernel config.
>>
>> Are you sure?
>>
>> exynos_drm_add_components() will try to attach components *added to
>> component_lists. And these components will be added by only
>> corresponding sub drivers to the component_lists and
>> master->components.
>>
>> So in this case, if users disabled HDMI support then a commponent
>> object for HDMI sub driver doesn't exists in the component_lists and
>> master->components. This means that a component object for HDMI sub
>> driver *cannot be attached to master object*.
>>
>> As a result, component_bind_add() will ignor component_bind call for
>> HDMI sub driver so HDMI driver will not be bounded. The only
>> components added by sub drivers will be bound, component->ops->bind().
>>
>> For more understanding, it seems like you need to look into below codes,
>>
>> static int exynos_drm_add_components(...)
>> {
>>          ...
>>          for (i == 0;; i++) {
>>                  ...
>>                  node = of_parse_phandle(np, "ports", i);
>>                  ...
>>                  ret = component_master_add_child(m, compare_of, node);
>>                  ...
>>          }
>> }
>
> Hmm, In case HDMI driver is not present, HDMI device is not probed and
> HDMI component is not added, so component_master_add_child returns
> an error when it tries to add hdmi component and master is never brought
> up, am I correct?
>

This is my thought here as well.

>>
>>
>> And below codes,
>>
>> int component_master_add_child(...)
>> {
>>          list_for_each_entry(c, &component_list, node) {
>>                  if (c->master)
>>                          continue;
>>
>>                  if (compare(...)) {
>>                           component_attach_master(master, c);
>>                           ...
>>                  }
>>          }
>> }
>>
>> And below codes,
>>
>> static void component_attach_master(master, c)
>> {
>>          c->master = master;
>>          list_add_tail(&c->master_node, &master->comonents);
>> }
>>
>>
>> As you can see above, the only components added to component_list can
>> be attached to master. And the important thing is that components can
>> be added by sub drivers to the component_list.
>>
>> And below codes that actually tries to bind each sub drivers,
>>
>> int component_bind_add(...)
>> {
>>          ....
>>          list_for_each_entry(c, &master->components, master_node) {
>>                     ret = component_bind(c, master, data);
>>                     ...
>>          }
>>          ...
>> }
>>
>> The hdmi driver users disabled doesn't exist to master->components list.
>> How Exynos DRM cannot be initialized?
>>
>> Of course, there may be my missing point, but I think I see them
>> correctly. Anyway I will test them tomorrow.
>>
>> Thanks,
>> Inki Dae
>>
>>>>> register, which is completely wrong. Users should be able to select which
>>>>> drivers should be compiled into their kernels.
>>>>
>>>> So users are be able to select drivers they want to use, and will be
>>>> compiled correctly. So no, the only thing users can disable is each
>>>> sub driver, not core module.
>>>>
>>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>>> without possibility of loading some sub-drivers as modules. I know that
>>>>> current driver design doesn't support it either, but if this series is
>>>>
>>>> No, current drm driver *must also be built* as one integrated single
>>>> drm driver without super device approach.
>>>
>>> As I wrote, I know that current design before this patch isn't modular
>>> either, but this is not my concern here. See below.
>>>
>>>
>>>> So the super device approach
>>>> *has no any effect on existing design*,  and what the super device
>>>> approch tries to do is to resolve the probe order issue to sub drivers
>>>> *without some codes specific to Exynos drm*.
>>>
>>> My concern is that the supernode design is actually carving such broken
>>> non-modular design in stone. Remember that we are currently heading towards
>>> a fully multi-platform kernel where it is critical for such subsystems to be
>>> modular, because the same zImage is going to be running on completely
>>> different machines.
>>>
>>>
>>>>> claimed to improve things, it should really do so.
>>>>>
>>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>>> all.
>>>>> In fact even without adding any new single property or node to DT. We
>>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>>> which
>>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>>> weekend.
>>>>
>>>> I'm not sure but I had implemented below prototype codes for that, see
>>>> the below link,
>>>>
>>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>>
>>>> I guess what you said would be similler approach.
>>>
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just based
>>> on the list of subsystem sub-drivers that is already available to the master
>>> driver.
>
> I am not so sure which approach is better, anyway I hope to post RFC soon,
> as some material for discussion.
>

Great. Looking forward for it.

>>>
>>>
>>>> And I still think the use of the component framework would be the best
>>>> solution and *Linux generic way* for resolving the probe order issue
>>>> without any specific codes. So I'm not advocating the compoent
>>>> framework but I tend not to want to use specific codes.
>>>>
>>> I understand your concern. I also believe that generic frameworks should be
>>> reused wherever possible. However the componentized subsystem framework is a
>>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>>> trash can where any data that can be thought of can be thrown as you go, but
>>> rather a hardware description that is supposed to be a stable ABI and needs
>>> to be well-thought. So, if something can be done in a way that doesn't
>>> require additional data, it's better to do it that way.
>>>
>>>
>>>>> 5) This series seems to break DPI display support with runtime PM
>>>>> enabled.
>>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>>> with
>>>>> probe deferral. This needs more investigation, though.
>
> If we are talking about the same issue, it is a problem of panel
> initialization sequence on some
> panels. I will post fix for it.

That's possible.

I'm not saying that it's a problem of this series itself, but it has 
been introduced/triggered by this series. My intention was to point that 
such issues need to be investigated before pushing the patches upstream.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-07 14:18             ` Andrzej Hajda
@ 2014-04-07 15:16               ` Inki Dae
  -1 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-07 15:16 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: linux-samsung-soc, Arnd Bergmann, DRI mailing list,
	Kyungmin Park, linux-arm-kernel, Marek Szyprowski

Hi Andrzej,

2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
> Hi Inki and Tomasz,
>
> On 04/06/2014 05:15 AM, Inki Dae wrote:
>
> (...)
>> The code creating the list of components to wait for
>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>> actually enabled in kernel config.
>>
>> Are you sure?
>>
>> exynos_drm_add_components() will try to attach components *added to
>> component_lists. And these components will be added by only
>> corresponding sub drivers to the component_lists and
>> master->components.
>>
>> So in this case, if users disabled HDMI support then a commponent
>> object for HDMI sub driver doesn't exists in the component_lists and
>> master->components. This means that a component object for HDMI sub
>> driver *cannot be attached to master object*.
>>
>> As a result, component_bind_add() will ignor component_bind call for
>> HDMI sub driver so HDMI driver will not be bounded. The only
>> components added by sub drivers will be bound, component->ops->bind().
>>
>> For more understanding, it seems like you need to look into below codes,
>>
>> static int exynos_drm_add_components(...)
>> {
>>         ...
>>         for (i == 0;; i++) {
>>                 ...
>>                 node = of_parse_phandle(np, "ports", i);
>>                 ...
>>                 ret = component_master_add_child(m, compare_of, node);
>>                 ...
>>         }
>> }
>
> Hmm, In case HDMI driver is not present, HDMI device is not probed and
> HDMI component is not added, so component_master_add_child returns
> an error when it tries to add hdmi component and master is never brought
> up, am I correct?
>

Ok, after that,

ret = component_master_add(,..)
if (ret < 0)
         DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");

As you can see above, if component_master_add() is failed, return 0,
*not error*. And then component_add() called by other kms drivers,
late probing of hdmi or fimd probing - if there is any kms driver
enabled - will try to bring up master again by calling
try_to_bring_up_master() from beginning.

And if component_list is empty then it means that there is no any kms
driver enabled.

Do you still think in that case, exynos drm initialization will be failed?

Thanks,
Inki Dae

>>
>>
>> And below codes,
>>
>> int component_master_add_child(...)
>> {
>>         list_for_each_entry(c, &component_list, node) {
>>                 if (c->master)
>>                         continue;
>>
>>                 if (compare(...)) {
>>                          component_attach_master(master, c);
>>                          ...
>>                 }
>>         }
>> }
>>
>> And below codes,
>>
>> static void component_attach_master(master, c)
>> {
>>         c->master = master;
>>         list_add_tail(&c->master_node, &master->comonents);
>> }
>>
>>
>> As you can see above, the only components added to component_list can
>> be attached to master. And the important thing is that components can
>> be added by sub drivers to the component_list.
>>
>> And below codes that actually tries to bind each sub drivers,
>>
>> int component_bind_add(...)
>> {
>>         ....
>>         list_for_each_entry(c, &master->components, master_node) {
>>                    ret = component_bind(c, master, data);
>>                    ...
>>         }
>>         ...
>> }
>>
>> The hdmi driver users disabled doesn't exist to master->components list.
>> How Exynos DRM cannot be initialized?
>>
>> Of course, there may be my missing point, but I think I see them
>> correctly. Anyway I will test them tomorrow.
>>
>> Thanks,
>> Inki Dae
>>
>>>>> register, which is completely wrong. Users should be able to select which
>>>>> drivers should be compiled into their kernels.
>>>>
>>>> So users are be able to select drivers they want to use, and will be
>>>> compiled correctly. So no, the only thing users can disable is each
>>>> sub driver, not core module.
>>>>
>>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>>> without possibility of loading some sub-drivers as modules. I know that
>>>>> current driver design doesn't support it either, but if this series is
>>>>
>>>> No, current drm driver *must also be built* as one integrated single
>>>> drm driver without super device approach.
>>>
>>> As I wrote, I know that current design before this patch isn't modular
>>> either, but this is not my concern here. See below.
>>>
>>>
>>>> So the super device approach
>>>> *has no any effect on existing design*,  and what the super device
>>>> approch tries to do is to resolve the probe order issue to sub drivers
>>>> *without some codes specific to Exynos drm*.
>>>
>>> My concern is that the supernode design is actually carving such broken
>>> non-modular design in stone. Remember that we are currently heading towards
>>> a fully multi-platform kernel where it is critical for such subsystems to be
>>> modular, because the same zImage is going to be running on completely
>>> different machines.
>>>
>>>
>>>>> claimed to improve things, it should really do so.
>>>>>
>>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>>> all.
>>>>> In fact even without adding any new single property or node to DT. We
>>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>>> which
>>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>>> weekend.
>>>>
>>>> I'm not sure but I had implemented below prototype codes for that, see
>>>> the below link,
>>>>
>>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>>
>>>> I guess what you said would be similler approach.
>>>
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just based
>>> on the list of subsystem sub-drivers that is already available to the master
>>> driver.
>
> I am not so sure which approach is better, anyway I hope to post RFC soon,
> as some material for discussion.
>

Feel free to post RFC but as I mentioned eailer, it'd be good way to
use existing infrastructure, not specific one.

Thanks,
Inki Dae

>>>
>>>
>>>> And I still think the use of the component framework would be the best
>>>> solution and *Linux generic way* for resolving the probe order issue
>>>> without any specific codes. So I'm not advocating the compoent
>>>> framework but I tend not to want to use specific codes.
>>>>
>>> I understand your concern. I also believe that generic frameworks should be
>>> reused wherever possible. However the componentized subsystem framework is a
>>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>>> trash can where any data that can be thought of can be thrown as you go, but
>>> rather a hardware description that is supposed to be a stable ABI and needs
>>> to be well-thought. So, if something can be done in a way that doesn't
>>> require additional data, it's better to do it that way.
>>>
>>>
>>>>> 5) This series seems to break DPI display support with runtime PM
>>>>> enabled.
>>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>>> with
>>>>> probe deferral. This needs more investigation, though.
>
> If we are talking about the same issue, it is a problem of panel
> initialization sequence on some
> panels. I will post fix for it.
>
>
> Regards
> Andrzej
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-07 15:16               ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-07 15:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andrzej,

2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
> Hi Inki and Tomasz,
>
> On 04/06/2014 05:15 AM, Inki Dae wrote:
>
> (...)
>> The code creating the list of components to wait for
>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>> actually enabled in kernel config.
>>
>> Are you sure?
>>
>> exynos_drm_add_components() will try to attach components *added to
>> component_lists. And these components will be added by only
>> corresponding sub drivers to the component_lists and
>> master->components.
>>
>> So in this case, if users disabled HDMI support then a commponent
>> object for HDMI sub driver doesn't exists in the component_lists and
>> master->components. This means that a component object for HDMI sub
>> driver *cannot be attached to master object*.
>>
>> As a result, component_bind_add() will ignor component_bind call for
>> HDMI sub driver so HDMI driver will not be bounded. The only
>> components added by sub drivers will be bound, component->ops->bind().
>>
>> For more understanding, it seems like you need to look into below codes,
>>
>> static int exynos_drm_add_components(...)
>> {
>>         ...
>>         for (i == 0;; i++) {
>>                 ...
>>                 node = of_parse_phandle(np, "ports", i);
>>                 ...
>>                 ret = component_master_add_child(m, compare_of, node);
>>                 ...
>>         }
>> }
>
> Hmm, In case HDMI driver is not present, HDMI device is not probed and
> HDMI component is not added, so component_master_add_child returns
> an error when it tries to add hdmi component and master is never brought
> up, am I correct?
>

Ok, after that,

ret = component_master_add(,..)
if (ret < 0)
         DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");

As you can see above, if component_master_add() is failed, return 0,
*not error*. And then component_add() called by other kms drivers,
late probing of hdmi or fimd probing - if there is any kms driver
enabled - will try to bring up master again by calling
try_to_bring_up_master() from beginning.

And if component_list is empty then it means that there is no any kms
driver enabled.

Do you still think in that case, exynos drm initialization will be failed?

Thanks,
Inki Dae

>>
>>
>> And below codes,
>>
>> int component_master_add_child(...)
>> {
>>         list_for_each_entry(c, &component_list, node) {
>>                 if (c->master)
>>                         continue;
>>
>>                 if (compare(...)) {
>>                          component_attach_master(master, c);
>>                          ...
>>                 }
>>         }
>> }
>>
>> And below codes,
>>
>> static void component_attach_master(master, c)
>> {
>>         c->master = master;
>>         list_add_tail(&c->master_node, &master->comonents);
>> }
>>
>>
>> As you can see above, the only components added to component_list can
>> be attached to master. And the important thing is that components can
>> be added by sub drivers to the component_list.
>>
>> And below codes that actually tries to bind each sub drivers,
>>
>> int component_bind_add(...)
>> {
>>         ....
>>         list_for_each_entry(c, &master->components, master_node) {
>>                    ret = component_bind(c, master, data);
>>                    ...
>>         }
>>         ...
>> }
>>
>> The hdmi driver users disabled doesn't exist to master->components list.
>> How Exynos DRM cannot be initialized?
>>
>> Of course, there may be my missing point, but I think I see them
>> correctly. Anyway I will test them tomorrow.
>>
>> Thanks,
>> Inki Dae
>>
>>>>> register, which is completely wrong. Users should be able to select which
>>>>> drivers should be compiled into their kernels.
>>>>
>>>> So users are be able to select drivers they want to use, and will be
>>>> compiled correctly. So no, the only thing users can disable is each
>>>> sub driver, not core module.
>>>>
>>>>> 3) Such approach leads to complete integration of all Exynos DRM drivers,
>>>>> without possibility of loading some sub-drivers as modules. I know that
>>>>> current driver design doesn't support it either, but if this series is
>>>>
>>>> No, current drm driver *must also be built* as one integrated single
>>>> drm driver without super device approach.
>>>
>>> As I wrote, I know that current design before this patch isn't modular
>>> either, but this is not my concern here. See below.
>>>
>>>
>>>> So the super device approach
>>>> *has no any effect on existing design*,  and what the super device
>>>> approch tries to do is to resolve the probe order issue to sub drivers
>>>> *without some codes specific to Exynos drm*.
>>>
>>> My concern is that the supernode design is actually carving such broken
>>> non-modular design in stone. Remember that we are currently heading towards
>>> a fully multi-platform kernel where it is critical for such subsystems to be
>>> modular, because the same zImage is going to be running on completely
>>> different machines.
>>>
>>>
>>>>> claimed to improve things, it should really do so.
>>>>>
>>>>> 4) Exactly the same can be achieved without changing the DT bindings at
>>>>> all.
>>>>> In fact even without adding any new single property or node to DT. We
>>>>> discussed this with Andrzej and Marek today and came to a solution in
>>>>> which
>>>>> just by adding a little bit of code to Exynos DRM subdrivers, you could
>>>>> guarantee correct registration of Exynos DRM platform and also get rid of
>>>>> #ifdeffery in exynos_drm_drv.c. Andrzej will send an RFC after the
>>>>> weekend.
>>>>
>>>> I'm not sure but I had implemented below prototype codes for that, see
>>>> the below link,
>>>>
>>>> https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?h=exynos-bridge-test&id=2860ad02d736e300034ddeabce3da92614922b4e
>>>>
>>>> I guess what you said would be similler approach.
>>>
>>> Not exactly. The approach we found does mostly the same as componentized
>>> subsystem framework but without _any_ extra data in Device Tree. Just based
>>> on the list of subsystem sub-drivers that is already available to the master
>>> driver.
>
> I am not so sure which approach is better, anyway I hope to post RFC soon,
> as some material for discussion.
>

Feel free to post RFC but as I mentioned eailer, it'd be good way to
use existing infrastructure, not specific one.

Thanks,
Inki Dae

>>>
>>>
>>>> And I still think the use of the component framework would be the best
>>>> solution and *Linux generic way* for resolving the probe order issue
>>>> without any specific codes. So I'm not advocating the compoent
>>>> framework but I tend not to want to use specific codes.
>>>>
>>> I understand your concern. I also believe that generic frameworks should be
>>> reused wherever possible. However the componentized subsystem framework is a
>>> bit of overkill for this simple problem. Moreover, Device Tree is not a
>>> trash can where any data that can be thought of can be thrown as you go, but
>>> rather a hardware description that is supposed to be a stable ABI and needs
>>> to be well-thought. So, if something can be done in a way that doesn't
>>> require additional data, it's better to do it that way.
>>>
>>>
>>>>> 5) This series seems to break DPI display support with runtime PM
>>>>> enabled.
>>>>> Universal C210 just hangs on second FIMD probe, after first one fails
>>>>> with
>>>>> probe deferral. This needs more investigation, though.
>
> If we are talking about the same issue, it is a problem of panel
> initialization sequence on some
> panels. I will post fix for it.
>
>
> Regards
> Andrzej
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-07 15:16               ` Inki Dae
@ 2014-04-07 15:40                 ` Tomasz Figa
  -1 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-07 15:40 UTC (permalink / raw)
  To: Inki Dae, Andrzej Hajda
  Cc: linux-samsung-soc, Arnd Bergmann, DRI mailing list,
	Kyungmin Park, linux-arm-kernel, Marek Szyprowski

On 07.04.2014 17:16, Inki Dae wrote:
> Hi Andrzej,
>
> 2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
>> Hi Inki and Tomasz,
>>
>> On 04/06/2014 05:15 AM, Inki Dae wrote:
>>
>> (...)
>>> The code creating the list of components to wait for
>>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>>> actually enabled in kernel config.
>>>
>>> Are you sure?
>>>
>>> exynos_drm_add_components() will try to attach components *added to
>>> component_lists. And these components will be added by only
>>> corresponding sub drivers to the component_lists and
>>> master->components.
>>>
>>> So in this case, if users disabled HDMI support then a commponent
>>> object for HDMI sub driver doesn't exists in the component_lists and
>>> master->components. This means that a component object for HDMI sub
>>> driver *cannot be attached to master object*.
>>>
>>> As a result, component_bind_add() will ignor component_bind call for
>>> HDMI sub driver so HDMI driver will not be bounded. The only
>>> components added by sub drivers will be bound, component->ops->bind().
>>>
>>> For more understanding, it seems like you need to look into below codes,
>>>
>>> static int exynos_drm_add_components(...)
>>> {
>>>          ...
>>>          for (i == 0;; i++) {
>>>                  ...
>>>                  node = of_parse_phandle(np, "ports", i);
>>>                  ...
>>>                  ret = component_master_add_child(m, compare_of, node);
>>>                  ...
>>>          }
>>> }
>>
>> Hmm, In case HDMI driver is not present, HDMI device is not probed and
>> HDMI component is not added, so component_master_add_child returns
>> an error when it tries to add hdmi component and master is never brought
>> up, am I correct?
>>
>
> Ok, after that,
>
> ret = component_master_add(,..)
> if (ret < 0)
>           DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
>
> As you can see above, if component_master_add() is failed, return 0,
> *not error*. And then component_add() called by other kms drivers,
> late probing of hdmi or fimd probing - if there is any kms driver
> enabled - will try to bring up master again by calling
> try_to_bring_up_master() from beginning.
>
> And if component_list is empty then it means that there is no any kms
> driver enabled.
>
> Do you still think in that case, exynos drm initialization will be failed?

There will be no HDMI driver to call component_add(), because HDMI sub 
driver will be disabled in kernel config and any previous 
component_master_add_child() for the phandle pointing to HDMI node will 
wail, because such component will never be registered.

The complete failure path is as follows:

exynos_drm_platform_probe()
	component_master_add()
		try_to_bring_up_master()
			exynos_drm_add_components()
				// phandle to HDMI node
				component_master_add_child()
				= -ENXIO
			= -ENXIO
		= 0 // but no call to master->ops->bind(master->dev);
	= 0
= 0 // but Exynos DRM platform is not registered yet

Now if any other late-probed sub-driver comes, the sequence will be as 
follows (let's take FIMD as an example):

fimd_probe()
	component_add()
		try_to_bring_up_masters()
			try_to_bring_up_master()
				exynos_drm_add_components()
					// phandle to HDMI node
					component_master_add_child()
					= -ENXIO
				= -ENXIO
			= 0 // but no call to 	
			    // master->ops->bind(master->dev);
		= 0
	= 0
= 0 // but Exynos DRM platform still not registered

And the same for any late-probed driver, unless HDMI drivers loads, but 
there is no HDMI driver, because it is disabled in kernel config and not 
compiled in.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-07 15:40                 ` Tomasz Figa
  0 siblings, 0 replies; 47+ messages in thread
From: Tomasz Figa @ 2014-04-07 15:40 UTC (permalink / raw)
  To: linux-arm-kernel

On 07.04.2014 17:16, Inki Dae wrote:
> Hi Andrzej,
>
> 2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
>> Hi Inki and Tomasz,
>>
>> On 04/06/2014 05:15 AM, Inki Dae wrote:
>>
>> (...)
>>> The code creating the list of components to wait for
>>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers are
>>> actually enabled in kernel config.
>>>
>>> Are you sure?
>>>
>>> exynos_drm_add_components() will try to attach components *added to
>>> component_lists. And these components will be added by only
>>> corresponding sub drivers to the component_lists and
>>> master->components.
>>>
>>> So in this case, if users disabled HDMI support then a commponent
>>> object for HDMI sub driver doesn't exists in the component_lists and
>>> master->components. This means that a component object for HDMI sub
>>> driver *cannot be attached to master object*.
>>>
>>> As a result, component_bind_add() will ignor component_bind call for
>>> HDMI sub driver so HDMI driver will not be bounded. The only
>>> components added by sub drivers will be bound, component->ops->bind().
>>>
>>> For more understanding, it seems like you need to look into below codes,
>>>
>>> static int exynos_drm_add_components(...)
>>> {
>>>          ...
>>>          for (i == 0;; i++) {
>>>                  ...
>>>                  node = of_parse_phandle(np, "ports", i);
>>>                  ...
>>>                  ret = component_master_add_child(m, compare_of, node);
>>>                  ...
>>>          }
>>> }
>>
>> Hmm, In case HDMI driver is not present, HDMI device is not probed and
>> HDMI component is not added, so component_master_add_child returns
>> an error when it tries to add hdmi component and master is never brought
>> up, am I correct?
>>
>
> Ok, after that,
>
> ret = component_master_add(,..)
> if (ret < 0)
>           DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
>
> As you can see above, if component_master_add() is failed, return 0,
> *not error*. And then component_add() called by other kms drivers,
> late probing of hdmi or fimd probing - if there is any kms driver
> enabled - will try to bring up master again by calling
> try_to_bring_up_master() from beginning.
>
> And if component_list is empty then it means that there is no any kms
> driver enabled.
>
> Do you still think in that case, exynos drm initialization will be failed?

There will be no HDMI driver to call component_add(), because HDMI sub 
driver will be disabled in kernel config and any previous 
component_master_add_child() for the phandle pointing to HDMI node will 
wail, because such component will never be registered.

The complete failure path is as follows:

exynos_drm_platform_probe()
	component_master_add()
		try_to_bring_up_master()
			exynos_drm_add_components()
				// phandle to HDMI node
				component_master_add_child()
				= -ENXIO
			= -ENXIO
		= 0 // but no call to master->ops->bind(master->dev);
	= 0
= 0 // but Exynos DRM platform is not registered yet

Now if any other late-probed sub-driver comes, the sequence will be as 
follows (let's take FIMD as an example):

fimd_probe()
	component_add()
		try_to_bring_up_masters()
			try_to_bring_up_master()
				exynos_drm_add_components()
					// phandle to HDMI node
					component_master_add_child()
					= -ENXIO
				= -ENXIO
			= 0 // but no call to 	
			    // master->ops->bind(master->dev);
		= 0
	= 0
= 0 // but Exynos DRM platform still not registered

And the same for any late-probed driver, unless HDMI drivers loads, but 
there is no HDMI driver, because it is disabled in kernel config and not 
compiled in.

Best regards,
Tomasz

^ permalink raw reply	[flat|nested] 47+ messages in thread

* Re: [PATCH v2 1/7] drm/exynos: add super device support
  2014-04-07 15:40                 ` Tomasz Figa
@ 2014-04-08  8:37                   ` Inki Dae
  -1 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-08  8:37 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Andrzej Hajda, linux-samsung-soc, Arnd Bergmann,
	DRI mailing list, Kyungmin Park, linux-arm-kernel,
	Marek Szyprowski

2014-04-08 0:40 GMT+09:00, Tomasz Figa <tomasz.figa@gmail.com>:
> On 07.04.2014 17:16, Inki Dae wrote:
>> Hi Andrzej,
>>
>> 2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
>>> Hi Inki and Tomasz,
>>>
>>> On 04/06/2014 05:15 AM, Inki Dae wrote:
>>>
>>> (...)
>>>> The code creating the list of components to wait for
>>>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers
>>>> are
>>>> actually enabled in kernel config.
>>>>
>>>> Are you sure?
>>>>
>>>> exynos_drm_add_components() will try to attach components *added to
>>>> component_lists. And these components will be added by only
>>>> corresponding sub drivers to the component_lists and
>>>> master->components.
>>>>
>>>> So in this case, if users disabled HDMI support then a commponent
>>>> object for HDMI sub driver doesn't exists in the component_lists and
>>>> master->components. This means that a component object for HDMI sub
>>>> driver *cannot be attached to master object*.
>>>>
>>>> As a result, component_bind_add() will ignor component_bind call for
>>>> HDMI sub driver so HDMI driver will not be bounded. The only
>>>> components added by sub drivers will be bound, component->ops->bind().
>>>>
>>>> For more understanding, it seems like you need to look into below
>>>> codes,
>>>>
>>>> static int exynos_drm_add_components(...)
>>>> {
>>>>          ...
>>>>          for (i == 0;; i++) {
>>>>                  ...
>>>>                  node = of_parse_phandle(np, "ports", i);
>>>>                  ...
>>>>                  ret = component_master_add_child(m, compare_of, node);
>>>>                  ...
>>>>          }
>>>> }
>>>
>>> Hmm, In case HDMI driver is not present, HDMI device is not probed and
>>> HDMI component is not added, so component_master_add_child returns
>>> an error when it tries to add hdmi component and master is never brought
>>> up, am I correct?
>>>
>>
>> Ok, after that,
>>
>> ret = component_master_add(,..)
>> if (ret < 0)
>>           DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
>>
>> As you can see above, if component_master_add() is failed, return 0,
>> *not error*. And then component_add() called by other kms drivers,
>> late probing of hdmi or fimd probing - if there is any kms driver
>> enabled - will try to bring up master again by calling
>> try_to_bring_up_master() from beginning.
>>
>> And if component_list is empty then it means that there is no any kms
>> driver enabled.
>>
>> Do you still think in that case, exynos drm initialization will be
>> failed?
>
> There will be no HDMI driver to call component_add(), because HDMI sub
> driver will be disabled in kernel config and any previous
> component_master_add_child() for the phandle pointing to HDMI node will
> wail, because such component will never be registered.
>
> The complete failure path is as follows:
>
> exynos_drm_platform_probe()
> 	component_master_add()
> 		try_to_bring_up_master()
> 			exynos_drm_add_components()
> 				// phandle to HDMI node
> 				component_master_add_child()
> 				= -ENXIO
> 			= -ENXIO
> 		= 0 // but no call to master->ops->bind(master->dev);
> 	= 0
> = 0 // but Exynos DRM platform is not registered yet
>
> Now if any other late-probed sub-driver comes, the sequence will be as
> follows (let's take FIMD as an example):
>
> fimd_probe()
> 	component_add()
> 		try_to_bring_up_masters()
> 			try_to_bring_up_master()
> 				exynos_drm_add_components()
> 					// phandle to HDMI node
> 					component_master_add_child()
> 					= -ENXIO
> 				= -ENXIO
> 			= 0 // but no call to 	
> 			    // master->ops->bind(master->dev);
> 		= 0
> 	= 0
> = 0 // but Exynos DRM platform still not registered
>
> And the same for any late-probed driver, unless HDMI drivers loads, but
> there is no HDMI driver, because it is disabled in kernel config and not
> compiled in.
>

Ah, right. I missed that it gets phandle to hdmi, and compares the
phandle to one in component_list.
Yes, in this case, exynos drm driver will be failed because
component_list never has a component object for hdmi.
So this shouldn't return as long as there is any component - in
component_list - that can be attached to master.

Hm.. the foot of the candle is dark.

For this, I fixed and tested it like below,
for (i = 0;; i++) {
        node = of_parse_phandle(np, "ports", i);
        ...
        ret = component_master_add_child(...);
        ...
        if (!ret)
                attached_cnt++;
}

if (!attached_cnt)
        return -ENXIO;
...

And one more thing, it seems that we could  resolve dt broken issue
easily by getting phandle to existing device node directly.

Thanks,
Inki Dae

> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

* [PATCH v2 1/7] drm/exynos: add super device support
@ 2014-04-08  8:37                   ` Inki Dae
  0 siblings, 0 replies; 47+ messages in thread
From: Inki Dae @ 2014-04-08  8:37 UTC (permalink / raw)
  To: linux-arm-kernel

2014-04-08 0:40 GMT+09:00, Tomasz Figa <tomasz.figa@gmail.com>:
> On 07.04.2014 17:16, Inki Dae wrote:
>> Hi Andrzej,
>>
>> 2014-04-07 23:18 GMT+09:00 Andrzej Hajda <a.hajda@samsung.com>:
>>> Hi Inki and Tomasz,
>>>
>>> On 04/06/2014 05:15 AM, Inki Dae wrote:
>>>
>>> (...)
>>>> The code creating the list of components to wait for
>>>> (exynos_drm_add_components()) doesn't seem to consider which sub-drivers
>>>> are
>>>> actually enabled in kernel config.
>>>>
>>>> Are you sure?
>>>>
>>>> exynos_drm_add_components() will try to attach components *added to
>>>> component_lists. And these components will be added by only
>>>> corresponding sub drivers to the component_lists and
>>>> master->components.
>>>>
>>>> So in this case, if users disabled HDMI support then a commponent
>>>> object for HDMI sub driver doesn't exists in the component_lists and
>>>> master->components. This means that a component object for HDMI sub
>>>> driver *cannot be attached to master object*.
>>>>
>>>> As a result, component_bind_add() will ignor component_bind call for
>>>> HDMI sub driver so HDMI driver will not be bounded. The only
>>>> components added by sub drivers will be bound, component->ops->bind().
>>>>
>>>> For more understanding, it seems like you need to look into below
>>>> codes,
>>>>
>>>> static int exynos_drm_add_components(...)
>>>> {
>>>>          ...
>>>>          for (i == 0;; i++) {
>>>>                  ...
>>>>                  node = of_parse_phandle(np, "ports", i);
>>>>                  ...
>>>>                  ret = component_master_add_child(m, compare_of, node);
>>>>                  ...
>>>>          }
>>>> }
>>>
>>> Hmm, In case HDMI driver is not present, HDMI device is not probed and
>>> HDMI component is not added, so component_master_add_child returns
>>> an error when it tries to add hdmi component and master is never brought
>>> up, am I correct?
>>>
>>
>> Ok, after that,
>>
>> ret = component_master_add(,..)
>> if (ret < 0)
>>           DRM_DEBUG_KMS("re-tried by last sub driver probed later.\n");
>>
>> As you can see above, if component_master_add() is failed, return 0,
>> *not error*. And then component_add() called by other kms drivers,
>> late probing of hdmi or fimd probing - if there is any kms driver
>> enabled - will try to bring up master again by calling
>> try_to_bring_up_master() from beginning.
>>
>> And if component_list is empty then it means that there is no any kms
>> driver enabled.
>>
>> Do you still think in that case, exynos drm initialization will be
>> failed?
>
> There will be no HDMI driver to call component_add(), because HDMI sub
> driver will be disabled in kernel config and any previous
> component_master_add_child() for the phandle pointing to HDMI node will
> wail, because such component will never be registered.
>
> The complete failure path is as follows:
>
> exynos_drm_platform_probe()
> 	component_master_add()
> 		try_to_bring_up_master()
> 			exynos_drm_add_components()
> 				// phandle to HDMI node
> 				component_master_add_child()
> 				= -ENXIO
> 			= -ENXIO
> 		= 0 // but no call to master->ops->bind(master->dev);
> 	= 0
> = 0 // but Exynos DRM platform is not registered yet
>
> Now if any other late-probed sub-driver comes, the sequence will be as
> follows (let's take FIMD as an example):
>
> fimd_probe()
> 	component_add()
> 		try_to_bring_up_masters()
> 			try_to_bring_up_master()
> 				exynos_drm_add_components()
> 					// phandle to HDMI node
> 					component_master_add_child()
> 					= -ENXIO
> 				= -ENXIO
> 			= 0 // but no call to 	
> 			    // master->ops->bind(master->dev);
> 		= 0
> 	= 0
> = 0 // but Exynos DRM platform still not registered
>
> And the same for any late-probed driver, unless HDMI drivers loads, but
> there is no HDMI driver, because it is disabled in kernel config and not
> compiled in.
>

Ah, right. I missed that it gets phandle to hdmi, and compares the
phandle to one in component_list.
Yes, in this case, exynos drm driver will be failed because
component_list never has a component object for hdmi.
So this shouldn't return as long as there is any component - in
component_list - that can be attached to master.

Hm.. the foot of the candle is dark.

For this, I fixed and tested it like below,
for (i = 0;; i++) {
        node = of_parse_phandle(np, "ports", i);
        ...
        ret = component_master_add_child(...);
        ...
        if (!ret)
                attached_cnt++;
}

if (!attached_cnt)
        return -ENXIO;
...

And one more thing, it seems that we could  resolve dt broken issue
easily by getting phandle to existing device node directly.

Thanks,
Inki Dae

> Best regards,
> Tomasz
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

^ permalink raw reply	[flat|nested] 47+ messages in thread

end of thread, other threads:[~2014-04-08  8:37 UTC | newest]

Thread overview: 47+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-01 12:37 [PATCH v2 0/7] drm/exynos: more cleanup with super device support Inki Dae
2014-04-01 12:37 ` [PATCH v2 1/7] drm/exynos: add " Inki Dae
2014-04-02 14:06   ` Andrzej Hajda
2014-04-03  7:43     ` Inki Dae
2014-04-03  8:36   ` [PATCH v3] " Inki Dae
2014-04-03 11:47     ` [PATCH v4] " Inki Dae
2014-04-03 14:26       ` [PATCH] drm/exynos: separate dpi from fimd Andrzej Hajda
2014-04-03 16:29         ` Inki Dae
2014-04-03 16:35         ` Inki Dae
2014-04-03 17:01           ` Inki Dae
2014-04-04 13:55   ` [PATCH v2 1/7] drm/exynos: add super device support Tomasz Figa
2014-04-04 15:44     ` Inki Dae
2014-04-05 17:32       ` Tomasz Figa
2014-04-05 17:32         ` Tomasz Figa
2014-04-05 18:24         ` Russell King - ARM Linux
2014-04-05 18:24           ` Russell King - ARM Linux
2014-04-05 18:31           ` Tomasz Figa
2014-04-05 18:31             ` Tomasz Figa
2014-04-05 18:52             ` Russell King - ARM Linux
2014-04-05 18:52               ` Russell King - ARM Linux
2014-04-05 19:01               ` Tomasz Figa
2014-04-05 19:01                 ` Tomasz Figa
2014-04-06  4:21             ` Inki Dae
2014-04-06  4:21               ` Inki Dae
2014-04-06  8:47               ` Russell King - ARM Linux
2014-04-06  8:47                 ` Russell King - ARM Linux
2014-04-06  9:38                 ` Inki Dae
2014-04-06  9:38                   ` Inki Dae
2014-04-06  3:15         ` Inki Dae
2014-04-06  3:15           ` Inki Dae
2014-04-07 14:18           ` Andrzej Hajda
2014-04-07 14:18             ` Andrzej Hajda
2014-04-07 14:24             ` Tomasz Figa
2014-04-07 14:24               ` Tomasz Figa
2014-04-07 15:16             ` Inki Dae
2014-04-07 15:16               ` Inki Dae
2014-04-07 15:40               ` Tomasz Figa
2014-04-07 15:40                 ` Tomasz Figa
2014-04-08  8:37                 ` Inki Dae
2014-04-08  8:37                   ` Inki Dae
2014-04-01 12:37 ` [PATCH 2/7] drm/exynos: dpi: fix hotplug fail issue Inki Dae
2014-04-01 12:37 ` [PATCH v2 3/7] drm/exynos: register platform driver at each kms sub drivers Inki Dae
2014-04-01 12:37 ` [PATCH 4/7] ARM: dts: exynos4210-universal: add super device node for exynos drm Inki Dae
2014-04-01 12:38 ` [PATCH 5/7] ARM: dts: exynos4210-trats: " Inki Dae
2014-04-01 12:38 ` [PATCH 6/7] ARM: dts: exynos4412-trats2: " Inki Dae
2014-04-01 12:38 ` [PATCH 7/7] exynos/drm: add DT bindings Inki Dae
2014-04-03  7:43 ` [PATCH v2 0/7] drm/exynos: more cleanup with super device support Andrzej Hajda

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.