All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver
@ 2013-10-16 19:26 Sean Paul
  2013-10-16 19:26 ` [PATCH v2 01/26] drm/exynos: Remove useless slab.h include Sean Paul
                   ` (25 more replies)
  0 siblings, 26 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patchset refactors parts of the exynos driver to move it closer to a proper
drm driver (rather than just implementing a drm layer on top of the hardware
drivers). The hope is to get to a point where the dp/hdmi drivers can implement
drm_connector/drm_encoder directly, and fimd/mixer can directly implement
drm_crtc.

The notable changes in this set:
	- drm_encoder funcs no longer route through the crtc
	- DP driver has been moved from video into the drm driver
	- fimd no longer implements encoder callbacks
	- exynos_drm_hdmi is removed in favor of generic manager/display
	  handling

At a glance, differences between v1 and v2:
	- Passing manager/display in callbacks instead of ctx
	- Tacked on some dpms patches on the end to handle suspend/resume
	  through the dpms path

Sean


Daniel Kurtz (1):
  drm/exynos: hdmi: remove the i2c drivers and use devtree

Sean Paul (24):
  drm/exynos: Merge overlay_ops into manager_ops
  drm/exynos: Add an initialize function to manager and display
  drm/exynos: Use manager_op initialize in fimd
  drm/exynos: hdmi: Implement initialize op for hdmi
  drm/exynos: Pass exynos_drm_manager in manager ops instead of dev
  drm/exynos: Remove apply manager callback
  drm/exynos: Remove dpms link between encoder/connector
  drm/exynos: Rename display_op power_on to dpms
  drm/exynos: Don't keep dpms state in encoder
  drm/exynos: Use unsigned long for possible_crtcs
  drm/exynos: Split manager/display/subdrv
  drm/exynos: Remove exynos_drm_hdmi shim
  drm/exynos: Use drm_mode_copy to copy modes
  drm/exynos: Disable unused crtc planes from crtc
  drm/exynos: Add mode_set manager operation
  drm/exynos: Implement mode_fixup manager operation
  drm/exynos: Use mode_set to configure fimd
  drm/exynos: Remove unused/useless fimd_context members
  drm/exynos: Move dp driver from video/ to drm/
  drm/exynos: Move display implementation into dp
  ARM: dts: Move display-timings node from fimd to dp
  drm/exynos: Implement dpms display callback in DP
  drm/exynos: Clean up FIMD power on/off routines
  drm/exynos: Consolidate suspend/resume in drm_drv

Stéphane Marchesin (1):
  drm/exynos: Remove useless slab.h include

 .../devicetree/bindings/video/exynos_dp.txt        |   17 +
 .../devicetree/bindings/video/samsung-fimd.txt     |    2 +
 arch/arm/boot/dts/exynos5250-arndale.dts           |    7 +-
 arch/arm/boot/dts/exynos5250-smdk5250.dts          |    7 +-
 arch/arm/boot/dts/exynos5250-snow.dts              |    7 +-
 arch/arm/boot/dts/exynos5420-smdk5420.dts          |    7 +-
 drivers/gpu/drm/exynos/Kconfig                     |    7 +
 drivers/gpu/drm/exynos/Makefile                    |    5 +-
 drivers/gpu/drm/exynos/exynos_ddc.c                |   63 -
 drivers/gpu/drm/exynos/exynos_dp_core.c            | 1277 ++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_dp_core.h            |  216 ++++
 drivers/gpu/drm/exynos/exynos_dp_reg.c             | 1245 +++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_dp_reg.h             |  366 ++++++
 drivers/gpu/drm/exynos/exynos_drm_connector.c      |   92 +-
 drivers/gpu/drm/exynos/exynos_drm_connector.h      |    4 -
 drivers/gpu/drm/exynos/exynos_drm_core.c           |  181 ++-
 drivers/gpu/drm/exynos/exynos_drm_crtc.c           |  139 ++-
 drivers/gpu/drm/exynos/exynos_drm_crtc.h           |   20 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c            |  155 ++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h            |  157 ++-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c        |  356 +-----
 drivers/gpu/drm/exynos/exynos_drm_encoder.h        |   18 +-
 drivers/gpu/drm/exynos/exynos_drm_fb.c             |    4 +-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c           |  875 ++++++--------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c           |  439 -------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h           |   67 -
 drivers/gpu/drm/exynos/exynos_drm_plane.c          |   17 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.h          |    2 +-
 drivers/gpu/drm/exynos/exynos_drm_vidi.c           |   84 +-
 drivers/gpu/drm/exynos/exynos_hdmi.c               |  278 ++---
 drivers/gpu/drm/exynos/exynos_hdmi.h               |   23 -
 drivers/gpu/drm/exynos/exynos_hdmiphy.c            |   65 -
 drivers/gpu/drm/exynos/exynos_mixer.c              |  280 ++---
 drivers/gpu/drm/exynos/exynos_mixer.h              |   20 +
 drivers/video/exynos/Kconfig                       |    7 -
 drivers/video/exynos/Makefile                      |    1 -
 drivers/video/exynos/exynos_dp_core.c              | 1214 -------------------
 drivers/video/exynos/exynos_dp_core.h              |  210 ----
 drivers/video/exynos/exynos_dp_reg.c               | 1245 -------------------
 drivers/video/exynos/exynos_dp_reg.h               |  366 ------
 40 files changed, 4384 insertions(+), 5161 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_ddc.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmi.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmiphy.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h
 delete mode 100644 drivers/video/exynos/exynos_dp_core.c
 delete mode 100644 drivers/video/exynos/exynos_dp_core.h
 delete mode 100644 drivers/video/exynos/exynos_dp_reg.c
 delete mode 100644 drivers/video/exynos/exynos_dp_reg.h

-- 
1.8.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 01/26] drm/exynos: Remove useless slab.h include
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 02/26] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

From: Stéphane Marchesin <marcheu@chromium.org>

Signed-off-by: Stéphane Marchesin <marcheu@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/video/exynos/exynos_dp_core.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
index 12bbede..089ae22 100644
--- a/drivers/video/exynos/exynos_dp_core.c
+++ b/drivers/video/exynos/exynos_dp_core.c
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/clk.h>
 #include <linux/io.h>
-- 
1.8.4

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH v2 02/26] drm/exynos: Merge overlay_ops into manager_ops
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
  2013-10-16 19:26 ` [PATCH v2 01/26] drm/exynos: Remove useless slab.h include Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 03/26] drm/exynos: Add an initialize function to manager and display Sean Paul
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch merges overlay_ops into manager_ops. In all cases,
overlay_ops is implemented in the same place as manager ops, it doesn't
serve a functional purpose, and doesn't make things more clear.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_drv.h     |  29 +--
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |  26 +-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    | 363 ++++++++++++++--------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c    |  36 ++-
 drivers/gpu/drm/exynos/exynos_drm_vidi.c    |  29 +--
 drivers/gpu/drm/exynos/exynos_mixer.c       |   2 -
 6 files changed, 229 insertions(+), 256 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index eaa1966..6f31839 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -54,22 +54,6 @@ enum exynos_drm_output_type {
 };
 
 /*
- * Exynos drm overlay ops structure.
- *
- * @mode_set: copy drm overlay info to hw specific overlay info.
- * @commit: apply hardware specific overlay data to registers.
- * @enable: enable hardware specific overlay.
- * @disable: disable hardware specific overlay.
- */
-struct exynos_drm_overlay_ops {
-	void (*mode_set)(struct device *subdrv_dev,
-			 struct exynos_drm_overlay *overlay);
-	void (*commit)(struct device *subdrv_dev, int zpos);
-	void (*enable)(struct device *subdrv_dev, int zpos);
-	void (*disable)(struct device *subdrv_dev, int zpos);
-};
-
-/*
  * Exynos drm common overlay structure.
  *
  * @fb_x: offset x on a framebuffer to be displayed.
@@ -169,6 +153,10 @@ struct exynos_drm_display_ops {
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
  * @wait_for_vblank: wait for vblank interrupt to make sure that
  *	hardware overlay is updated.
+ * @win_mode_set: copy drm overlay info to hw specific overlay info.
+ * @win_commit: apply hardware specific overlay data to registers.
+ * @win_enable: enable hardware specific overlay.
+ * @win_disable: disable hardware specific overlay.
  */
 struct exynos_drm_manager_ops {
 	void (*dpms)(struct device *subdrv_dev, int mode);
@@ -184,6 +172,11 @@ struct exynos_drm_manager_ops {
 	int (*enable_vblank)(struct device *subdrv_dev);
 	void (*disable_vblank)(struct device *subdrv_dev);
 	void (*wait_for_vblank)(struct device *subdrv_dev);
+	void (*win_mode_set)(struct device *subdrv_dev,
+				struct exynos_drm_overlay *overlay);
+	void (*win_commit)(struct device *subdrv_dev, int zpos);
+	void (*win_enable)(struct device *subdrv_dev, int zpos);
+	void (*win_disable)(struct device *subdrv_dev, int zpos);
 };
 
 /*
@@ -195,9 +188,6 @@ struct exynos_drm_manager_ops {
  * @ops: pointer to callbacks for exynos drm specific framebuffer.
  *	these callbacks should be set by specific drivers such fimd
  *	or hdmi driver and are used to control hardware global registers.
- * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer.
- *	these callbacks should be set by specific drivers such fimd
- *	or hdmi driver and are used to control hardware overlay reigsters.
  * @display: pointer to callbacks for exynos drm specific framebuffer.
  *	these callbacks should be set by specific drivers such fimd
  *	or hdmi driver and are used to control display devices such as
@@ -207,7 +197,6 @@ struct exynos_drm_manager {
 	struct device *dev;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
-	struct exynos_drm_overlay_ops *overlay_ops;
 	struct exynos_drm_display_ops *display_ops;
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 06f1b2a..c255341 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -133,7 +133,7 @@ static void disable_plane_to_crtc(struct drm_device *dev,
 			 *
 			 * plane->funcs->disable_plane call checks
 			 * if encoder->crtc is same as plane->crtc and if same
-			 * then overlay_ops->disable callback will be called
+			 * then manager_ops->win_disable callback will be called
 			 * to diasble current hw overlay so plane->crtc should
 			 * have new_crtc because new_crtc was set to
 			 * encoder->crtc in advance.
@@ -442,51 +442,51 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	struct exynos_drm_overlay *overlay = data;
 
-	if (overlay_ops && overlay_ops->mode_set)
-		overlay_ops->mode_set(manager->dev, overlay);
+	if (manager_ops && manager_ops->win_mode_set)
+		manager_ops->win_mode_set(manager->dev, overlay);
 }
 
 void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int zpos = DEFAULT_ZPOS;
 
 	if (data)
 		zpos = *(int *)data;
 
-	if (overlay_ops && overlay_ops->commit)
-		overlay_ops->commit(manager->dev, zpos);
+	if (manager_ops && manager_ops->win_commit)
+		manager_ops->win_commit(manager->dev, zpos);
 }
 
 void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int zpos = DEFAULT_ZPOS;
 
 	if (data)
 		zpos = *(int *)data;
 
-	if (overlay_ops && overlay_ops->enable)
-		overlay_ops->enable(manager->dev, zpos);
+	if (manager_ops && manager_ops->win_enable)
+		manager_ops->win_enable(manager->dev, zpos);
 }
 
 void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
 {
 	struct exynos_drm_manager *manager =
 		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
+	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	int zpos = DEFAULT_ZPOS;
 
 	if (data)
 		zpos = *(int *)data;
 
-	if (overlay_ops && overlay_ops->disable)
-		overlay_ops->disable(manager->dev, zpos);
+	if (manager_ops && manager_ops->win_disable)
+		manager_ops->win_disable(manager->dev, zpos);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 868a14d..f271f22 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -181,185 +181,6 @@ static struct exynos_drm_display_ops fimd_display_ops = {
 	.power_on = fimd_display_power_on,
 };
 
-static void fimd_dpms(struct device *subdrv_dev, int mode)
-{
-	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-
-	DRM_DEBUG_KMS("%d\n", mode);
-
-	mutex_lock(&ctx->lock);
-
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-		/*
-		 * enable fimd hardware only if suspended status.
-		 *
-		 * P.S. fimd_dpms function would be called at booting time so
-		 * clk_enable could be called double time.
-		 */
-		if (ctx->suspended)
-			pm_runtime_get_sync(subdrv_dev);
-		break;
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-	case DRM_MODE_DPMS_OFF:
-		if (!ctx->suspended)
-			pm_runtime_put_sync(subdrv_dev);
-		break;
-	default:
-		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
-		break;
-	}
-
-	mutex_unlock(&ctx->lock);
-}
-
-static void fimd_apply(struct device *subdrv_dev)
-{
-	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-	struct exynos_drm_manager *mgr = ctx->subdrv.manager;
-	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-	struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
-	struct fimd_win_data *win_data;
-	int i;
-
-	for (i = 0; i < WINDOWS_NR; i++) {
-		win_data = &ctx->win_data[i];
-		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-			ovl_ops->commit(subdrv_dev, i);
-	}
-
-	if (mgr_ops && mgr_ops->commit)
-		mgr_ops->commit(subdrv_dev);
-}
-
-static void fimd_commit(struct device *dev)
-{
-	struct fimd_context *ctx = get_fimd_context(dev);
-	struct exynos_drm_panel_info *panel = &ctx->panel;
-	struct videomode *vm = &panel->vm;
-	struct fimd_driver_data *driver_data;
-	u32 val;
-
-	driver_data = ctx->driver_data;
-	if (ctx->suspended)
-		return;
-
-	/* setup polarity values from machine code. */
-	writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
-
-	/* setup vertical timing values. */
-	val = VIDTCON0_VBPD(vm->vback_porch - 1) |
-	       VIDTCON0_VFPD(vm->vfront_porch - 1) |
-	       VIDTCON0_VSPW(vm->vsync_len - 1);
-	writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
-
-	/* setup horizontal timing values.  */
-	val = VIDTCON1_HBPD(vm->hback_porch - 1) |
-	       VIDTCON1_HFPD(vm->hfront_porch - 1) |
-	       VIDTCON1_HSPW(vm->hsync_len - 1);
-	writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
-
-	/* setup horizontal and vertical display size. */
-	val = VIDTCON2_LINEVAL(vm->vactive - 1) |
-	       VIDTCON2_HOZVAL(vm->hactive - 1) |
-	       VIDTCON2_LINEVAL_E(vm->vactive - 1) |
-	       VIDTCON2_HOZVAL_E(vm->hactive - 1);
-	writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
-
-	/* setup clock source, clock divider, enable dma. */
-	val = ctx->vidcon0;
-	val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
-	if (ctx->driver_data->has_clksel) {
-		val &= ~VIDCON0_CLKSEL_MASK;
-		val |= VIDCON0_CLKSEL_LCD;
-	}
-
-	if (ctx->clkdiv > 1)
-		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
-	else
-		val &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
-
-	/*
-	 * fields of register with prefix '_F' would be updated
-	 * at vsync(same as dma start)
-	 */
-	val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
-	writel(val, ctx->regs + VIDCON0);
-}
-
-static int fimd_enable_vblank(struct device *dev)
-{
-	struct fimd_context *ctx = get_fimd_context(dev);
-	u32 val;
-
-	if (ctx->suspended)
-		return -EPERM;
-
-	if (!test_and_set_bit(0, &ctx->irq_flags)) {
-		val = readl(ctx->regs + VIDINTCON0);
-
-		val |= VIDINTCON0_INT_ENABLE;
-		val |= VIDINTCON0_INT_FRAME;
-
-		val &= ~VIDINTCON0_FRAMESEL0_MASK;
-		val |= VIDINTCON0_FRAMESEL0_VSYNC;
-		val &= ~VIDINTCON0_FRAMESEL1_MASK;
-		val |= VIDINTCON0_FRAMESEL1_NONE;
-
-		writel(val, ctx->regs + VIDINTCON0);
-	}
-
-	return 0;
-}
-
-static void fimd_disable_vblank(struct device *dev)
-{
-	struct fimd_context *ctx = get_fimd_context(dev);
-	u32 val;
-
-	if (ctx->suspended)
-		return;
-
-	if (test_and_clear_bit(0, &ctx->irq_flags)) {
-		val = readl(ctx->regs + VIDINTCON0);
-
-		val &= ~VIDINTCON0_INT_FRAME;
-		val &= ~VIDINTCON0_INT_ENABLE;
-
-		writel(val, ctx->regs + VIDINTCON0);
-	}
-}
-
-static void fimd_wait_for_vblank(struct device *dev)
-{
-	struct fimd_context *ctx = get_fimd_context(dev);
-
-	if (ctx->suspended)
-		return;
-
-	atomic_set(&ctx->wait_vsync_event, 1);
-
-	/*
-	 * wait for FIMD to signal VSYNC interrupt or return after
-	 * timeout which is set to 50ms (refresh rate of 20).
-	 */
-	if (!wait_event_timeout(ctx->wait_vsync_queue,
-				!atomic_read(&ctx->wait_vsync_event),
-				DRM_HZ/20))
-		DRM_DEBUG_KMS("vblank wait timed out.\n");
-}
-
-static struct exynos_drm_manager_ops fimd_manager_ops = {
-	.dpms = fimd_dpms,
-	.apply = fimd_apply,
-	.commit = fimd_commit,
-	.enable_vblank = fimd_enable_vblank,
-	.disable_vblank = fimd_disable_vblank,
-	.wait_for_vblank = fimd_wait_for_vblank,
-};
-
 static void fimd_win_mode_set(struct device *dev,
 			      struct exynos_drm_overlay *overlay)
 {
@@ -669,16 +490,190 @@ static void fimd_win_disable(struct device *dev, int zpos)
 	win_data->enabled = false;
 }
 
-static struct exynos_drm_overlay_ops fimd_overlay_ops = {
-	.mode_set = fimd_win_mode_set,
-	.commit = fimd_win_commit,
-	.disable = fimd_win_disable,
+static void fimd_dpms(struct device *subdrv_dev, int mode)
+{
+	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+	DRM_DEBUG_KMS("%d\n", mode);
+
+	mutex_lock(&ctx->lock);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		/*
+		 * enable fimd hardware only if suspended status.
+		 *
+		 * P.S. fimd_dpms function would be called at booting time so
+		 * clk_enable could be called double time.
+		 */
+		if (ctx->suspended)
+			pm_runtime_get_sync(subdrv_dev);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		if (!ctx->suspended)
+			pm_runtime_put_sync(subdrv_dev);
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+
+	mutex_unlock(&ctx->lock);
+}
+
+static void fimd_apply(struct device *subdrv_dev)
+{
+	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+	struct exynos_drm_manager *mgr = ctx->subdrv.manager;
+	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+	struct fimd_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
+			mgr_ops->win_commit(subdrv_dev, i);
+	}
+
+	if (mgr_ops && mgr_ops->commit)
+		mgr_ops->commit(subdrv_dev);
+}
+
+static void fimd_commit(struct device *dev)
+{
+	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_panel_info *panel = &ctx->panel;
+	struct videomode *vm = &panel->vm;
+	struct fimd_driver_data *driver_data;
+	u32 val;
+
+	driver_data = ctx->driver_data;
+	if (ctx->suspended)
+		return;
+
+	/* setup polarity values from machine code. */
+	writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
+
+	/* setup vertical timing values. */
+	val = VIDTCON0_VBPD(vm->vback_porch - 1) |
+	       VIDTCON0_VFPD(vm->vfront_porch - 1) |
+	       VIDTCON0_VSPW(vm->vsync_len - 1);
+	writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
+
+	/* setup horizontal timing values.  */
+	val = VIDTCON1_HBPD(vm->hback_porch - 1) |
+	       VIDTCON1_HFPD(vm->hfront_porch - 1) |
+	       VIDTCON1_HSPW(vm->hsync_len - 1);
+	writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
+
+	/* setup horizontal and vertical display size. */
+	val = VIDTCON2_LINEVAL(vm->vactive - 1) |
+	       VIDTCON2_HOZVAL(vm->hactive - 1) |
+	       VIDTCON2_LINEVAL_E(vm->vactive - 1) |
+	       VIDTCON2_HOZVAL_E(vm->hactive - 1);
+	writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
+
+	/* setup clock source, clock divider, enable dma. */
+	val = ctx->vidcon0;
+	val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
+
+	if (ctx->driver_data->has_clksel) {
+		val &= ~VIDCON0_CLKSEL_MASK;
+		val |= VIDCON0_CLKSEL_LCD;
+	}
+
+	if (ctx->clkdiv > 1)
+		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
+	else
+		val &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
+
+	/*
+	 * fields of register with prefix '_F' would be updated
+	 * at vsync(same as dma start)
+	 */
+	val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+	writel(val, ctx->regs + VIDCON0);
+}
+
+static int fimd_enable_vblank(struct device *dev)
+{
+	struct fimd_context *ctx = get_fimd_context(dev);
+	u32 val;
+
+	if (ctx->suspended)
+		return -EPERM;
+
+	if (!test_and_set_bit(0, &ctx->irq_flags)) {
+		val = readl(ctx->regs + VIDINTCON0);
+
+		val |= VIDINTCON0_INT_ENABLE;
+		val |= VIDINTCON0_INT_FRAME;
+
+		val &= ~VIDINTCON0_FRAMESEL0_MASK;
+		val |= VIDINTCON0_FRAMESEL0_VSYNC;
+		val &= ~VIDINTCON0_FRAMESEL1_MASK;
+		val |= VIDINTCON0_FRAMESEL1_NONE;
+
+		writel(val, ctx->regs + VIDINTCON0);
+	}
+
+	return 0;
+}
+
+static void fimd_disable_vblank(struct device *dev)
+{
+	struct fimd_context *ctx = get_fimd_context(dev);
+	u32 val;
+
+	if (ctx->suspended)
+		return;
+
+	if (test_and_clear_bit(0, &ctx->irq_flags)) {
+		val = readl(ctx->regs + VIDINTCON0);
+
+		val &= ~VIDINTCON0_INT_FRAME;
+		val &= ~VIDINTCON0_INT_ENABLE;
+
+		writel(val, ctx->regs + VIDINTCON0);
+	}
+}
+
+static void fimd_wait_for_vblank(struct device *dev)
+{
+	struct fimd_context *ctx = get_fimd_context(dev);
+
+	if (ctx->suspended)
+		return;
+
+	atomic_set(&ctx->wait_vsync_event, 1);
+
+	/*
+	 * wait for FIMD to signal VSYNC interrupt or return after
+	 * timeout which is set to 50ms (refresh rate of 20).
+	 */
+	if (!wait_event_timeout(ctx->wait_vsync_queue,
+				!atomic_read(&ctx->wait_vsync_event),
+				DRM_HZ/20))
+		DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static struct exynos_drm_manager_ops fimd_manager_ops = {
+	.dpms = fimd_dpms,
+	.apply = fimd_apply,
+	.commit = fimd_commit,
+	.enable_vblank = fimd_enable_vblank,
+	.disable_vblank = fimd_disable_vblank,
+	.wait_for_vblank = fimd_wait_for_vblank,
+	.win_mode_set = fimd_win_mode_set,
+	.win_commit = fimd_win_commit,
+	.win_disable = fimd_win_disable,
 };
 
 static struct exynos_drm_manager fimd_manager = {
 	.pipe		= -1,
 	.ops		= &fimd_manager_ops,
-	.overlay_ops	= &fimd_overlay_ops,
 	.display_ops	= &fimd_display_ops,
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index 8548b97..a1ef3c9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -284,19 +284,7 @@ static void drm_hdmi_apply(struct device *subdrv_dev)
 		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
-	.dpms = drm_hdmi_dpms,
-	.apply = drm_hdmi_apply,
-	.enable_vblank = drm_hdmi_enable_vblank,
-	.disable_vblank = drm_hdmi_disable_vblank,
-	.wait_for_vblank = drm_hdmi_wait_for_vblank,
-	.mode_fixup = drm_hdmi_mode_fixup,
-	.mode_set = drm_hdmi_mode_set,
-	.get_max_resol = drm_hdmi_get_max_resol,
-	.commit = drm_hdmi_commit,
-};
-
-static void drm_mixer_mode_set(struct device *subdrv_dev,
+static void drm_mixer_win_mode_set(struct device *subdrv_dev,
 		struct exynos_drm_overlay *overlay)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -305,7 +293,7 @@ static void drm_mixer_mode_set(struct device *subdrv_dev,
 		mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
 }
 
-static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_commit(struct device *subdrv_dev, int zpos)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
@@ -321,7 +309,7 @@ static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
 	ctx->enabled[win] = true;
 }
 
-static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
@@ -337,16 +325,24 @@ static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
 	ctx->enabled[win] = false;
 }
 
-static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
-	.mode_set = drm_mixer_mode_set,
-	.commit = drm_mixer_commit,
-	.disable = drm_mixer_disable,
+static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+	.dpms = drm_hdmi_dpms,
+	.apply = drm_hdmi_apply,
+	.enable_vblank = drm_hdmi_enable_vblank,
+	.disable_vblank = drm_hdmi_disable_vblank,
+	.wait_for_vblank = drm_hdmi_wait_for_vblank,
+	.mode_fixup = drm_hdmi_mode_fixup,
+	.mode_set = drm_hdmi_mode_set,
+	.get_max_resol = drm_hdmi_get_max_resol,
+	.commit = drm_hdmi_commit,
+	.win_mode_set = drm_mixer_win_mode_set,
+	.win_commit = drm_mixer_win_commit,
+	.win_disable = drm_mixer_win_disable,
 };
 
 static struct exynos_drm_manager hdmi_manager = {
 	.pipe		= -1,
 	.ops		= &drm_hdmi_manager_ops,
-	.overlay_ops	= &drm_hdmi_overlay_ops,
 	.display_ops	= &drm_hdmi_display_ops,
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 4400330..15a97ce 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -182,14 +182,13 @@ static void vidi_apply(struct device *subdrv_dev)
 	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
 	struct exynos_drm_manager *mgr = ctx->subdrv.manager;
 	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-	struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
 	struct vidi_win_data *win_data;
 	int i;
 
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
-		if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-			ovl_ops->commit(subdrv_dev, i);
+		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
+			mgr_ops->win_commit(subdrv_dev, i);
 	}
 
 	if (mgr_ops && mgr_ops->commit)
@@ -219,7 +218,7 @@ static int vidi_enable_vblank(struct device *dev)
 	/*
 	 * in case of page flip request, vidi_finish_pageflip function
 	 * will not be called because direct_vblank is true and then
-	 * that function will be called by overlay_ops->commit callback
+	 * that function will be called by manager_ops->win_commit callback
 	 */
 	schedule_work(&ctx->work);
 
@@ -237,14 +236,6 @@ static void vidi_disable_vblank(struct device *dev)
 		ctx->vblank_on = false;
 }
 
-static struct exynos_drm_manager_ops vidi_manager_ops = {
-	.dpms = vidi_dpms,
-	.apply = vidi_apply,
-	.commit = vidi_commit,
-	.enable_vblank = vidi_enable_vblank,
-	.disable_vblank = vidi_disable_vblank,
-};
-
 static void vidi_win_mode_set(struct device *dev,
 			      struct exynos_drm_overlay *overlay)
 {
@@ -341,16 +332,20 @@ static void vidi_win_disable(struct device *dev, int zpos)
 	/* TODO. */
 }
 
-static struct exynos_drm_overlay_ops vidi_overlay_ops = {
-	.mode_set = vidi_win_mode_set,
-	.commit = vidi_win_commit,
-	.disable = vidi_win_disable,
+static struct exynos_drm_manager_ops vidi_manager_ops = {
+	.dpms = vidi_dpms,
+	.apply = vidi_apply,
+	.commit = vidi_commit,
+	.enable_vblank = vidi_enable_vblank,
+	.disable_vblank = vidi_disable_vblank,
+	.win_mode_set = vidi_win_mode_set,
+	.win_commit = vidi_win_commit,
+	.win_disable = vidi_win_disable,
 };
 
 static struct exynos_drm_manager vidi_manager = {
 	.pipe		= -1,
 	.ops		= &vidi_manager_ops,
-	.overlay_ops	= &vidi_overlay_ops,
 	.display_ops	= &vidi_display_ops,
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 63bc5f9..9634188 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -975,8 +975,6 @@ static struct exynos_mixer_ops mixer_ops = {
 	.disable_vblank		= mixer_disable_vblank,
 	.wait_for_vblank	= mixer_wait_for_vblank,
 	.dpms			= mixer_dpms,
-
-	/* overlay */
 	.win_mode_set		= mixer_win_mode_set,
 	.win_commit		= mixer_win_commit,
 	.win_disable		= mixer_win_disable,
-- 
1.8.4

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

* [PATCH v2 03/26] drm/exynos: Add an initialize function to manager and display
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
  2013-10-16 19:26 ` [PATCH v2 01/26] drm/exynos: Remove useless slab.h include Sean Paul
  2013-10-16 19:26 ` [PATCH v2 02/26] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 04/26] drm/exynos: Use manager_op initialize in fimd Sean Paul
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch adds an initialize function to the manager and display
operations. This allows them to keep track of drm_device in their
local context, as well as adds an initialization hook right after
the encoder is created.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_drv.h     |  5 +++++
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 21 +++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 6f31839..09bfe60 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -123,6 +123,7 @@ struct exynos_drm_overlay {
  *	- this structure is common to analog tv, digital tv and lcd panel.
  *
  * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @initialize: initializes the display with drm_dev
  * @is_connected: check for that display is connected or not.
  * @get_edid: get edid modes from display driver.
  * @get_panel: get panel object from display driver.
@@ -131,6 +132,7 @@ struct exynos_drm_overlay {
  */
 struct exynos_drm_display_ops {
 	enum exynos_drm_output_type type;
+	int (*initialize)(struct device *dev, struct drm_device *drm_dev);
 	bool (*is_connected)(struct device *dev);
 	struct edid *(*get_edid)(struct device *dev,
 			struct drm_connector *connector);
@@ -142,6 +144,7 @@ struct exynos_drm_display_ops {
 /*
  * Exynos drm manager ops
  *
+ * @initialize: initializes the manager with drm_dev
  * @dpms: control device power.
  * @apply: set timing, vblank and overlay data to registers.
  * @mode_fixup: fix mode data comparing to hw specific display mode.
@@ -159,6 +162,8 @@ struct exynos_drm_display_ops {
  * @win_disable: disable hardware specific overlay.
  */
 struct exynos_drm_manager_ops {
+	int (*initialize)(struct device *subdrv_dev,
+			struct drm_device *drm_dev);
 	void (*dpms)(struct device *subdrv_dev, int mode);
 	void (*apply)(struct device *subdrv_dev);
 	void (*mode_fixup)(struct device *subdrv_dev,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index c255341..a9eb2b0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -316,6 +316,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
 {
 	struct drm_encoder *encoder;
 	struct exynos_drm_encoder *exynos_encoder;
+	int ret;
 
 	if (!manager || !possible_crtcs)
 		return NULL;
@@ -339,9 +340,29 @@ exynos_drm_encoder_create(struct drm_device *dev,
 
 	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
 
+	if (manager->ops && manager->ops->initialize) {
+		ret = manager->ops->initialize(manager->dev, dev);
+		if (ret) {
+			DRM_ERROR("Manager initialize failed %d\n", ret);
+			goto error;
+		}
+	}
+
+	if (manager->display_ops && manager->display_ops->initialize) {
+		ret = manager->display_ops->initialize(manager->dev, dev);
+		if (ret) {
+			DRM_ERROR("Display initialize failed %d\n", ret);
+			goto error;
+		}
+	}
+
 	DRM_DEBUG_KMS("encoder has been created\n");
 
 	return encoder;
+
+error:
+	exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
+	return NULL;
 }
 
 struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
-- 
1.8.4

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

* [PATCH v2 04/26] drm/exynos: Use manager_op initialize in fimd
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (2 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 03/26] drm/exynos: Add an initialize function to manager and display Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 05/26] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch implements the intitialize manager op in fimd.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f271f22..90fcd6f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -106,6 +106,7 @@ struct fimd_win_data {
 
 struct fimd_context {
 	struct exynos_drm_subdrv	subdrv;
+	struct drm_device		*drm_dev;
 	int				irq;
 	struct drm_crtc			*crtc;
 	struct clk			*bus_clk;
@@ -490,6 +491,16 @@ static void fimd_win_disable(struct device *dev, int zpos)
 	win_data->enabled = false;
 }
 
+static int fimd_mgr_initialize(struct device *subdrv_dev,
+		struct drm_device *drm_dev)
+{
+	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+
+	ctx->drm_dev = drm_dev;
+
+	return 0;
+}
+
 static void fimd_dpms(struct device *subdrv_dev, int mode)
 {
 	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
@@ -660,6 +671,7 @@ static void fimd_wait_for_vblank(struct device *dev)
 }
 
 static struct exynos_drm_manager_ops fimd_manager_ops = {
+	.initialize = fimd_mgr_initialize,
 	.dpms = fimd_dpms,
 	.apply = fimd_apply,
 	.commit = fimd_commit,
@@ -681,7 +693,6 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
 	struct fimd_context *ctx = (struct fimd_context *)dev_id;
 	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-	struct drm_device *drm_dev = subdrv->drm_dev;
 	struct exynos_drm_manager *manager = subdrv->manager;
 	u32 val;
 
@@ -692,11 +703,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 		writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
 
 	/* check the crtc is detached already from encoder */
-	if (manager->pipe < 0)
+	if (manager->pipe < 0 || !ctx->drm_dev)
 		goto out;
 
-	drm_handle_vblank(drm_dev, manager->pipe);
-	exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
+	drm_handle_vblank(ctx->drm_dev, manager->pipe);
+	exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
 
 	/* set wait vsync event to zero and wake up queue. */
 	if (atomic_read(&ctx->wait_vsync_event)) {
-- 
1.8.4

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

* [PATCH v2 05/26] drm/exynos: hdmi: Implement initialize op for hdmi
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (3 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 04/26] drm/exynos: Use manager_op initialize in fimd Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 06/26] drm/exynos: Pass exynos_drm_manager in manager ops instead of dev Sean Paul
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch implements the initialize callback in the hdmi and mixer
manager. This allows us to get rid of drm_dev in the drm_hdmi level and
track it in the mixer and hdmi drivers. This is one of the things
holding back the complete removal of the drm_hdmi layer.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_hdmi.c | 35 ++++++++++++++++++++++++++------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h |  3 ++-
 drivers/gpu/drm/exynos/exynos_hdmi.c     | 18 ++++++++++++----
 drivers/gpu/drm/exynos/exynos_mixer.c    | 35 +++++++++++++++++++-------------
 4 files changed, 66 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index a1ef3c9..aebcc0e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -97,6 +97,18 @@ void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
 		mixer_ops = ops;
 }
 
+static int drm_hdmi_display_initialize(struct device *dev,
+		struct drm_device *drm_dev)
+{
+	struct drm_hdmi_context *ctx = to_context(dev);
+
+	if (hdmi_ops && hdmi_ops->initialize)
+		return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
+
+	return 0;
+}
+
+
 static bool drm_hdmi_is_connected(struct device *dev)
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
@@ -153,6 +165,7 @@ static int drm_hdmi_power_on(struct device *dev, int mode)
 
 static struct exynos_drm_display_ops drm_hdmi_display_ops = {
 	.type = EXYNOS_DISPLAY_TYPE_HDMI,
+	.initialize = drm_hdmi_display_initialize,
 	.is_connected = drm_hdmi_is_connected,
 	.get_edid = drm_hdmi_get_edid,
 	.check_mode = drm_hdmi_check_mode,
@@ -257,6 +270,21 @@ static void drm_hdmi_commit(struct device *subdrv_dev)
 		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
+static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
+		struct drm_device *drm_dev)
+{
+	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	int ret = 0;
+
+	if (mixer_ops && mixer_ops->initialize)
+		ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
+
+	if (mixer_ops->iommu_on)
+		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
+
+	return ret;
+}
+
 static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
 {
 	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
@@ -326,6 +354,7 @@ static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
 }
 
 static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
+	.initialize = drm_hdmi_mgr_initialize,
 	.dpms = drm_hdmi_dpms,
 	.apply = drm_hdmi_apply,
 	.enable_vblank = drm_hdmi_enable_vblank,
@@ -372,12 +401,6 @@ static int hdmi_subdrv_probe(struct drm_device *drm_dev,
 	ctx->hdmi_ctx = hdmi_ctx;
 	ctx->mixer_ctx = mixer_ctx;
 
-	ctx->hdmi_ctx->drm_dev = drm_dev;
-	ctx->mixer_ctx->drm_dev = drm_dev;
-
-	if (mixer_ops->iommu_on)
-		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 724cab1..cf7b1da 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -23,12 +23,12 @@
  *	this context should be hdmi_context or mixer_context.
  */
 struct exynos_drm_hdmi_context {
-	struct drm_device	*drm_dev;
 	void			*ctx;
 };
 
 struct exynos_hdmi_ops {
 	/* display */
+	int (*initialize)(void *ctx, struct drm_device *drm_dev);
 	bool (*is_connected)(void *ctx);
 	struct edid *(*get_edid)(void *ctx,
 			struct drm_connector *connector);
@@ -45,6 +45,7 @@ struct exynos_hdmi_ops {
 
 struct exynos_mixer_ops {
 	/* manager */
+	int (*initialize)(void *ctx, struct drm_device *drm_dev);
 	int (*iommu_on)(void *ctx, bool enable);
 	int (*enable_vblank)(void *ctx, int pipe);
 	void (*disable_vblank)(void *ctx);
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a0e10ae..a3fba8e 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -742,6 +742,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
 	}
 }
 
+static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+{
+	struct hdmi_context *hdata = ctx;
+
+	hdata->drm_dev = drm_dev;
+
+	return 0;
+}
+
 static bool hdmi_is_connected(void *ctx)
 {
 	struct hdmi_context *hdata = ctx;
@@ -1747,6 +1756,7 @@ static void hdmi_dpms(void *ctx, int mode)
 
 static struct exynos_hdmi_ops hdmi_ops = {
 	/* display */
+	.initialize	= hdmi_initialize,
 	.is_connected	= hdmi_is_connected,
 	.get_edid	= hdmi_get_edid,
 	.check_mode	= hdmi_check_mode,
@@ -1767,8 +1777,8 @@ static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 	mutex_unlock(&hdata->hdmi_mutex);
 
-	if (ctx->drm_dev)
-		drm_helper_hpd_irq_event(ctx->drm_dev);
+	if (hdata->drm_dev)
+		drm_helper_hpd_irq_event(hdata->drm_dev);
 
 	return IRQ_HANDLED;
 }
@@ -2026,8 +2036,8 @@ static int hdmi_suspend(struct device *dev)
 	disable_irq(hdata->irq);
 
 	hdata->hpd = false;
-	if (ctx->drm_dev)
-		drm_helper_hpd_irq_event(ctx->drm_dev);
+	if (hdata->drm_dev)
+		drm_helper_hpd_irq_event(hdata->drm_dev);
 
 	if (pm_runtime_suspended(dev)) {
 		DRM_DEBUG_KMS("Already suspended\n");
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 9634188..2f204c1 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -685,20 +685,25 @@ static void mixer_win_reset(struct mixer_context *ctx)
 	spin_unlock_irqrestore(&res->reg_slock, flags);
 }
 
+static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+{
+	struct mixer_context *mixer_ctx = ctx;
+
+	mixer_ctx->drm_dev = drm_dev;
+
+	return 0;
+}
+
 static int mixer_iommu_on(void *ctx, bool enable)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
 	struct mixer_context *mdata = ctx;
-	struct drm_device *drm_dev;
-
-	drm_hdmi_ctx = mdata->parent_ctx;
-	drm_dev = drm_hdmi_ctx->drm_dev;
 
-	if (is_drm_iommu_supported(drm_dev)) {
+	if (is_drm_iommu_supported(mdata->drm_dev)) {
 		if (enable)
-			return drm_iommu_attach_device(drm_dev, mdata->dev);
+			return drm_iommu_attach_device(mdata->drm_dev,
+					mdata->dev);
 
-		drm_iommu_detach_device(drm_dev, mdata->dev);
+		drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
 	}
 	return 0;
 }
@@ -970,6 +975,7 @@ static void mixer_dpms(void *ctx, int mode)
 
 static struct exynos_mixer_ops mixer_ops = {
 	/* manager */
+	.initialize		= mixer_initialize,
 	.iommu_on		= mixer_iommu_on,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
@@ -985,8 +991,7 @@ static struct exynos_mixer_ops mixer_ops = {
 
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct mixer_context *ctx = arg;
 	struct mixer_resources *res = &ctx->mixer_res;
 	u32 val, base, shadow;
 
@@ -995,6 +1000,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 	/* read interrupt status for handling and clearing flags for VSYNC */
 	val = mixer_reg_read(res, MXR_INT_STATUS);
 
+	if (!ctx->drm_dev)
+		goto out;
+
 	/* handling VSYNC */
 	if (val & MXR_INT_STATUS_VSYNC) {
 		/* interlace scan need to check shadow register */
@@ -1010,9 +1018,8 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
 				goto out;
 		}
 
-		drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
-		exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
-				ctx->pipe);
+		drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+		exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 
 		/* set wait vsync event to zero and wake up queue. */
 		if (atomic_read(&ctx->wait_vsync_event)) {
@@ -1077,7 +1084,7 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
 	}
 
 	ret = devm_request_irq(dev, res->start, mixer_irq_handler,
-							0, "drm_mixer", ctx);
+						0, "drm_mixer", mixer_ctx);
 	if (ret) {
 		dev_err(dev, "request interrupt failed.\n");
 		return ret;
-- 
1.8.4

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

* [PATCH v2 06/26] drm/exynos: Pass exynos_drm_manager in manager ops instead of dev
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (4 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 05/26] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 07/26] drm/exynos: Remove apply manager callback Sean Paul
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch changes the manager ops callbacks from accepting the subdrv
device pointer to taking a pointer to the manager. This will allow us
to move closer to decoupling manager/display from subdrv, and subsequently
decoupling the crtc/plane from the encoder.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Instead of passing context, pass manager
	- Properly assign ctx->dev in fimd driver

 drivers/gpu/drm/exynos/exynos_drm_connector.c |   2 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.h       |  35 ++++----
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   |  27 +++---
 drivers/gpu/drm/exynos/exynos_drm_fimd.c      | 114 ++++++++++++++------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c      |  72 ++++++++--------
 drivers/gpu/drm/exynos/exynos_drm_vidi.c      |  49 +++++------
 6 files changed, 159 insertions(+), 140 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index e082efb..23b69d8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -198,7 +198,7 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 	 * resolution then get max width and height from that driver.
 	 */
 	if (ops && ops->get_max_resol)
-		ops->get_max_resol(manager->dev, &width, &height);
+		ops->get_max_resol(manager, &width, &height);
 
 	return drm_helper_probe_single_connector_modes(connector, width,
 							height);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 09bfe60..8eb8b83 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -161,27 +161,28 @@ struct exynos_drm_display_ops {
  * @win_enable: enable hardware specific overlay.
  * @win_disable: disable hardware specific overlay.
  */
+struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
-	int (*initialize)(struct device *subdrv_dev,
-			struct drm_device *drm_dev);
-	void (*dpms)(struct device *subdrv_dev, int mode);
-	void (*apply)(struct device *subdrv_dev);
-	void (*mode_fixup)(struct device *subdrv_dev,
+	int (*initialize)(struct exynos_drm_manager *mgr,
+				struct drm_device *drm_dev);
+	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
+	void (*apply)(struct exynos_drm_manager *mgr);
+	void (*mode_fixup)(struct exynos_drm_manager *mgr,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode);
-	void (*mode_set)(struct device *subdrv_dev, void *mode);
-	void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
-				unsigned int *height);
-	void (*commit)(struct device *subdrv_dev);
-	int (*enable_vblank)(struct device *subdrv_dev);
-	void (*disable_vblank)(struct device *subdrv_dev);
-	void (*wait_for_vblank)(struct device *subdrv_dev);
-	void (*win_mode_set)(struct device *subdrv_dev,
+	void (*mode_set)(struct exynos_drm_manager *mgr, void *mode);
+	void (*get_max_resol)(struct exynos_drm_manager *mgr,
+				unsigned int *width, unsigned int *height);
+	void (*commit)(struct exynos_drm_manager *mgr);
+	int (*enable_vblank)(struct exynos_drm_manager *mgr);
+	void (*disable_vblank)(struct exynos_drm_manager *mgr);
+	void (*wait_for_vblank)(struct exynos_drm_manager *mgr);
+	void (*win_mode_set)(struct exynos_drm_manager *mgr,
 				struct exynos_drm_overlay *overlay);
-	void (*win_commit)(struct device *subdrv_dev, int zpos);
-	void (*win_enable)(struct device *subdrv_dev, int zpos);
-	void (*win_disable)(struct device *subdrv_dev, int zpos);
+	void (*win_commit)(struct exynos_drm_manager *mgr, int zpos);
+	void (*win_enable)(struct exynos_drm_manager *mgr, int zpos);
+	void (*win_disable)(struct exynos_drm_manager *mgr, int zpos);
 };
 
 /*
@@ -197,12 +198,14 @@ struct exynos_drm_manager_ops {
  *	these callbacks should be set by specific drivers such fimd
  *	or hdmi driver and are used to control display devices such as
  *	analog tv, digital tv and lcd panel and also get timing data for them.
+ * @ctx: A pointer to the manager's implementation specific context
  */
 struct exynos_drm_manager {
 	struct device *dev;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
 	struct exynos_drm_display_ops *display_ops;
+	void *ctx;
 };
 
 struct exynos_drm_g2d_private {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index a9eb2b0..ec627fa 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -74,7 +74,7 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 	case DRM_MODE_DPMS_ON:
 		if (manager_ops && manager_ops->apply)
 			if (!exynos_encoder->updated)
-				manager_ops->apply(manager->dev);
+				manager_ops->apply(manager);
 
 		exynos_drm_connector_power(encoder, mode);
 		exynos_encoder->dpms = mode;
@@ -107,7 +107,7 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder)
 			if (manager_ops && manager_ops->mode_fixup)
-				manager_ops->mode_fixup(manager->dev, connector,
+				manager_ops->mode_fixup(manager, connector,
 							mode, adjusted_mode);
 	}
 
@@ -175,8 +175,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 			manager_ops = manager->ops;
 
 			if (manager_ops && manager_ops->mode_set)
-				manager_ops->mode_set(manager->dev,
-							adjusted_mode);
+				manager_ops->mode_set(manager, adjusted_mode);
 
 			exynos_encoder->old_crtc = encoder->crtc;
 		}
@@ -195,7 +194,7 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
 	if (manager_ops && manager_ops->commit)
-		manager_ops->commit(manager->dev);
+		manager_ops->commit(manager);
 
 	/*
 	 * this will avoid one issue that overlay data is updated to
@@ -233,7 +232,7 @@ void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
 		 *	real hardware.
 		 */
 		if (ops->wait_for_vblank)
-			ops->wait_for_vblank(exynos_encoder->manager->dev);
+			ops->wait_for_vblank(exynos_encoder->manager);
 	}
 }
 
@@ -341,7 +340,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
 	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
 
 	if (manager->ops && manager->ops->initialize) {
-		ret = manager->ops->initialize(manager->dev, dev);
+		ret = manager->ops->initialize(manager, dev);
 		if (ret) {
 			DRM_ERROR("Manager initialize failed %d\n", ret);
 			goto error;
@@ -408,7 +407,7 @@ void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
 		return;
 
 	if (manager_ops->enable_vblank)
-		manager_ops->enable_vblank(manager->dev);
+		manager_ops->enable_vblank(manager);
 }
 
 void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
@@ -422,7 +421,7 @@ void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
 		return;
 
 	if (manager_ops->disable_vblank)
-		manager_ops->disable_vblank(manager->dev);
+		manager_ops->disable_vblank(manager);
 }
 
 void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
@@ -433,7 +432,7 @@ void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
 	int mode = *(int *)data;
 
 	if (manager_ops && manager_ops->dpms)
-		manager_ops->dpms(manager->dev, mode);
+		manager_ops->dpms(manager, mode);
 
 	/*
 	 * if this condition is ok then it means that the crtc is already
@@ -467,7 +466,7 @@ void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
 	struct exynos_drm_overlay *overlay = data;
 
 	if (manager_ops && manager_ops->win_mode_set)
-		manager_ops->win_mode_set(manager->dev, overlay);
+		manager_ops->win_mode_set(manager, overlay);
 }
 
 void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
@@ -481,7 +480,7 @@ void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
 		zpos = *(int *)data;
 
 	if (manager_ops && manager_ops->win_commit)
-		manager_ops->win_commit(manager->dev, zpos);
+		manager_ops->win_commit(manager, zpos);
 }
 
 void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
@@ -495,7 +494,7 @@ void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
 		zpos = *(int *)data;
 
 	if (manager_ops && manager_ops->win_enable)
-		manager_ops->win_enable(manager->dev, zpos);
+		manager_ops->win_enable(manager, zpos);
 }
 
 void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
@@ -509,5 +508,5 @@ void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
 		zpos = *(int *)data;
 
 	if (manager_ops && manager_ops->win_disable)
-		manager_ops->win_disable(manager->dev, zpos);
+		manager_ops->win_disable(manager, zpos);
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 90fcd6f..2769eb3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -62,7 +62,7 @@
 /* FIMD has totally five hardware windows. */
 #define WINDOWS_NR	5
 
-#define get_fimd_context(dev)	platform_get_drvdata(to_platform_device(dev))
+#define get_fimd_manager(mgr)	platform_get_drvdata(to_platform_device(dev))
 
 struct fimd_driver_data {
 	unsigned int timing_base;
@@ -106,6 +106,7 @@ struct fimd_win_data {
 
 struct fimd_context {
 	struct exynos_drm_subdrv	subdrv;
+	struct device			*dev;
 	struct drm_device		*drm_dev;
 	int				irq;
 	struct drm_crtc			*crtc;
@@ -155,7 +156,8 @@ static bool fimd_display_is_connected(struct device *dev)
 
 static void *fimd_get_panel(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
+	struct fimd_context *ctx = mgr->ctx;
 
 	return &ctx->panel;
 }
@@ -182,16 +184,16 @@ static struct exynos_drm_display_ops fimd_display_ops = {
 	.power_on = fimd_display_power_on,
 };
 
-static void fimd_win_mode_set(struct device *dev,
-			      struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
+			struct exynos_drm_overlay *overlay)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int win;
 	unsigned long offset;
 
 	if (!overlay) {
-		dev_err(dev, "overlay is NULL\n");
+		DRM_ERROR("overlay is NULL\n");
 		return;
 	}
 
@@ -231,9 +233,8 @@ static void fimd_win_mode_set(struct device *dev,
 			overlay->fb_width, overlay->crtc_width);
 }
 
-static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
 	struct fimd_win_data *win_data = &ctx->win_data[win];
 	unsigned long val;
 
@@ -289,9 +290,8 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
 	writel(val, ctx->regs + WINCON(win));
 }
 
-static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
 	unsigned int keycon0 = 0, keycon1 = 0;
 
 	keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
@@ -330,9 +330,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
 	writel(val, ctx->regs + reg);
 }
 
-static void fimd_win_commit(struct device *dev, int zpos)
+static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int win = zpos;
 	unsigned long val, alpha, size;
@@ -427,11 +427,11 @@ static void fimd_win_commit(struct device *dev, int zpos)
 		DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
 	}
 
-	fimd_win_set_pixfmt(dev, win);
+	fimd_win_set_pixfmt(ctx, win);
 
 	/* hardware window 0 doesn't support color key. */
 	if (win != 0)
-		fimd_win_set_colkey(dev, win);
+		fimd_win_set_colkey(ctx, win);
 
 	/* wincon */
 	val = readl(ctx->regs + WINCON(win));
@@ -450,9 +450,9 @@ static void fimd_win_commit(struct device *dev, int zpos)
 	win_data->enabled = true;
 }
 
-static void fimd_win_disable(struct device *dev, int zpos)
+static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int win = zpos;
 	u32 val;
@@ -491,19 +491,19 @@ static void fimd_win_disable(struct device *dev, int zpos)
 	win_data->enabled = false;
 }
 
-static int fimd_mgr_initialize(struct device *subdrv_dev,
-		struct drm_device *drm_dev)
+static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
+			struct drm_device *drm_dev)
 {
-	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+	struct fimd_context *ctx = mgr->ctx;
 
 	ctx->drm_dev = drm_dev;
 
 	return 0;
 }
 
-static void fimd_dpms(struct device *subdrv_dev, int mode)
+static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+	struct fimd_context *ctx = mgr->ctx;
 
 	DRM_DEBUG_KMS("%d\n", mode);
 
@@ -518,13 +518,13 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
 		 * clk_enable could be called double time.
 		 */
 		if (ctx->suspended)
-			pm_runtime_get_sync(subdrv_dev);
+			pm_runtime_get_sync(ctx->dev);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
 		if (!ctx->suspended)
-			pm_runtime_put_sync(subdrv_dev);
+			pm_runtime_put_sync(ctx->dev);
 		break;
 	default:
 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -534,10 +534,9 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
 	mutex_unlock(&ctx->lock);
 }
 
-static void fimd_apply(struct device *subdrv_dev)
+static void fimd_apply(struct exynos_drm_manager *mgr)
 {
-	struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-	struct exynos_drm_manager *mgr = ctx->subdrv.manager;
+	struct fimd_context *ctx = mgr->ctx;
 	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
 	struct fimd_win_data *win_data;
 	int i;
@@ -545,16 +544,16 @@ static void fimd_apply(struct device *subdrv_dev)
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
-			mgr_ops->win_commit(subdrv_dev, i);
+			mgr_ops->win_commit(mgr, i);
 	}
 
 	if (mgr_ops && mgr_ops->commit)
-		mgr_ops->commit(subdrv_dev);
+		mgr_ops->commit(mgr);
 }
 
-static void fimd_commit(struct device *dev)
+static void fimd_commit(struct exynos_drm_manager *mgr)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct exynos_drm_panel_info *panel = &ctx->panel;
 	struct videomode *vm = &panel->vm;
 	struct fimd_driver_data *driver_data;
@@ -608,9 +607,9 @@ static void fimd_commit(struct device *dev)
 	writel(val, ctx->regs + VIDCON0);
 }
 
-static int fimd_enable_vblank(struct device *dev)
+static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	u32 val;
 
 	if (ctx->suspended)
@@ -633,9 +632,9 @@ static int fimd_enable_vblank(struct device *dev)
 	return 0;
 }
 
-static void fimd_disable_vblank(struct device *dev)
+static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	u32 val;
 
 	if (ctx->suspended)
@@ -651,9 +650,9 @@ static void fimd_disable_vblank(struct device *dev)
 	}
 }
 
-static void fimd_wait_for_vblank(struct device *dev)
+static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct fimd_context *ctx = mgr->ctx;
 
 	if (ctx->suspended)
 		return;
@@ -838,21 +837,23 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
 
 static void fimd_window_suspend(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int i;
 
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		win_data->resume = win_data->enabled;
-		fimd_win_disable(dev, i);
+		fimd_win_disable(mgr, i);
 	}
-	fimd_wait_for_vblank(dev);
+	fimd_wait_for_vblank(mgr);
 }
 
 static void fimd_window_resume(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
+	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int i;
 
@@ -863,9 +864,11 @@ static void fimd_window_resume(struct device *dev)
 	}
 }
 
-static int fimd_activate(struct fimd_context *ctx, bool enable)
+static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 {
+	struct fimd_context *ctx = mgr->ctx;
 	struct device *dev = ctx->subdrv.dev;
+
 	if (enable) {
 		int ret;
 
@@ -877,7 +880,7 @@ static int fimd_activate(struct fimd_context *ctx, bool enable)
 
 		/* if vblank was enabled status, enable it again. */
 		if (test_and_clear_bit(0, &ctx->irq_flags))
-			fimd_enable_vblank(dev);
+			fimd_enable_vblank(mgr);
 
 		fimd_window_resume(dev);
 	} else {
@@ -930,6 +933,8 @@ static int fimd_probe(struct platform_device *pdev)
 	if (!ctx)
 		return -ENOMEM;
 
+	ctx->dev = dev;
+
 	ret = fimd_get_platform_data(ctx, dev);
 	if (ret)
 		return ret;
@@ -963,6 +968,8 @@ static int fimd_probe(struct platform_device *pdev)
 	DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
+	fimd_manager.ctx = ctx;
+
 	subdrv = &ctx->subdrv;
 
 	subdrv->dev = dev;
@@ -972,7 +979,7 @@ static int fimd_probe(struct platform_device *pdev)
 
 	mutex_init(&ctx->lock);
 
-	platform_set_drvdata(pdev, ctx);
+	platform_set_drvdata(pdev, &fimd_manager);
 
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
@@ -988,7 +995,8 @@ static int fimd_probe(struct platform_device *pdev)
 static int fimd_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct fimd_context *ctx = platform_get_drvdata(pdev);
+	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
+	struct fimd_context *ctx = mgr->ctx;
 
 	exynos_drm_subdrv_unregister(&ctx->subdrv);
 
@@ -1007,7 +1015,7 @@ out:
 #ifdef CONFIG_PM_SLEEP
 static int fimd_suspend(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
 	/*
 	 * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
@@ -1015,14 +1023,14 @@ static int fimd_suspend(struct device *dev)
 	 * because the usage_count of pm runtime is more than 1.
 	 */
 	if (!pm_runtime_suspended(dev))
-		return fimd_activate(ctx, false);
+		return fimd_activate(mgr, false);
 
 	return 0;
 }
 
 static int fimd_resume(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
 	/*
 	 * if entered to sleep when lcd panel was on, the usage_count
@@ -1032,7 +1040,7 @@ static int fimd_resume(struct device *dev)
 	if (!pm_runtime_suspended(dev)) {
 		int ret;
 
-		ret = fimd_activate(ctx, true);
+		ret = fimd_activate(mgr, true);
 		if (ret < 0)
 			return ret;
 
@@ -1042,7 +1050,7 @@ static int fimd_resume(struct device *dev)
 		 * registers but in case of sleep wakeup, it's not.
 		 * so fimd_apply function should be called at here.
 		 */
-		fimd_apply(dev);
+		fimd_apply(mgr);
 	}
 
 	return 0;
@@ -1052,16 +1060,16 @@ static int fimd_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int fimd_runtime_suspend(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
-	return fimd_activate(ctx, false);
+	return fimd_activate(mgr, false);
 }
 
 static int fimd_runtime_resume(struct device *dev)
 {
-	struct fimd_context *ctx = get_fimd_context(dev);
+	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
-	return fimd_activate(ctx, true);
+	return fimd_activate(mgr, true);
 }
 #endif
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index aebcc0e..ca0a87f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -129,11 +129,9 @@ static struct edid *drm_hdmi_get_edid(struct device *dev,
 
 	return NULL;
 }
-
-static int drm_hdmi_check_mode(struct device *dev,
+static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
 		struct drm_display_mode *mode)
 {
-	struct drm_hdmi_context *ctx = to_context(dev);
 	int ret = 0;
 
 	/*
@@ -153,6 +151,14 @@ static int drm_hdmi_check_mode(struct device *dev,
 	return 0;
 }
 
+static int drm_hdmi_check_mode(struct device *dev,
+		struct drm_display_mode *mode)
+{
+	struct drm_hdmi_context *ctx = to_context(dev);
+
+	return drm_hdmi_check_mode_ctx(ctx, mode);
+}
+
 static int drm_hdmi_power_on(struct device *dev, int mode)
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
@@ -172,9 +178,9 @@ static struct exynos_drm_display_ops drm_hdmi_display_ops = {
 	.power_on = drm_hdmi_power_on,
 };
 
-static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
+static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
 	struct exynos_drm_manager *manager = subdrv->manager;
 
@@ -185,33 +191,34 @@ static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
 	return 0;
 }
 
-static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
+static void drm_hdmi_disable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (mixer_ops && mixer_ops->disable_vblank)
 		return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
 }
 
-static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
+static void drm_hdmi_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (mixer_ops && mixer_ops->wait_for_vblank)
 		mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
 }
 
-static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
+static void drm_hdmi_mode_fixup(struct exynos_drm_manager *mgr,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
 				struct drm_display_mode *adjusted_mode)
 {
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	struct drm_display_mode *m;
 	int mode_ok;
 
 	drm_mode_set_crtcinfo(adjusted_mode, 0);
 
-	mode_ok = drm_hdmi_check_mode(subdrv_dev, adjusted_mode);
+	mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
 
 	/* just return if user desired mode exists. */
 	if (mode_ok == 0)
@@ -222,7 +229,7 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
 	 * to adjusted_mode.
 	 */
 	list_for_each_entry(m, &connector->modes, head) {
-		mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
+		mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
 
 		if (mode_ok == 0) {
 			struct drm_mode_object base;
@@ -245,35 +252,34 @@ static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
 	}
 }
 
-static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
+static void drm_hdmi_mode_set(struct exynos_drm_manager *mgr, void *mode)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (hdmi_ops && hdmi_ops->mode_set)
 		hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
 }
 
-static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
+static void drm_hdmi_get_max_resol(struct exynos_drm_manager *mgr,
 				unsigned int *width, unsigned int *height)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (hdmi_ops && hdmi_ops->get_max_resol)
 		hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
 }
 
-static void drm_hdmi_commit(struct device *subdrv_dev)
+static void drm_hdmi_commit(struct exynos_drm_manager *mgr)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (hdmi_ops && hdmi_ops->commit)
 		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
-static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
-		struct drm_device *drm_dev)
+static int drm_hdmi_mgr_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	int ret = 0;
 
 	if (mixer_ops && mixer_ops->initialize)
@@ -285,9 +291,9 @@ static int drm_hdmi_mgr_initialize(struct device *subdrv_dev,
 	return ret;
 }
 
-static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
+static void drm_hdmi_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (mixer_ops && mixer_ops->dpms)
 		mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
@@ -296,9 +302,9 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
 		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
 }
 
-static void drm_hdmi_apply(struct device *subdrv_dev)
+static void drm_hdmi_apply(struct exynos_drm_manager *mgr)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	int i;
 
 	for (i = 0; i < MIXER_WIN_NR; i++) {
@@ -312,18 +318,18 @@ static void drm_hdmi_apply(struct device *subdrv_dev)
 		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
 }
 
-static void drm_mixer_win_mode_set(struct device *subdrv_dev,
-		struct exynos_drm_overlay *overlay)
+static void drm_mixer_win_mode_set(struct exynos_drm_manager *mgr,
+				struct exynos_drm_overlay *overlay)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 
 	if (mixer_ops && mixer_ops->win_mode_set)
 		mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
 }
 
-static void drm_mixer_win_commit(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
 
 	if (win < 0 || win >= MIXER_WIN_NR) {
@@ -337,9 +343,9 @@ static void drm_mixer_win_commit(struct device *subdrv_dev, int zpos)
 	ctx->enabled[win] = true;
 }
 
-static void drm_mixer_win_disable(struct device *subdrv_dev, int zpos)
+static void drm_mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct drm_hdmi_context *ctx = to_context(subdrv_dev);
+	struct drm_hdmi_context *ctx = mgr->ctx;
 	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
 
 	if (win < 0 || win >= MIXER_WIN_NR) {
@@ -425,6 +431,8 @@ static int exynos_drm_hdmi_probe(struct platform_device *pdev)
 	if (!ctx)
 		return -ENOMEM;
 
+	hdmi_manager.ctx = ctx;
+
 	subdrv = &ctx->subdrv;
 
 	subdrv->dev = dev;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 15a97ce..a583a74 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -152,9 +152,9 @@ static struct exynos_drm_display_ops vidi_display_ops = {
 	.power_on = vidi_display_power_on,
 };
 
-static void vidi_dpms(struct device *subdrv_dev, int mode)
+static void vidi_dpms(void *in_ctx, int mode)
 {
-	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+	struct vidi_context *ctx = in_ctx;
 
 	DRM_DEBUG_KMS("%d\n", mode);
 
@@ -177,9 +177,9 @@ static void vidi_dpms(struct device *subdrv_dev, int mode)
 	mutex_unlock(&ctx->lock);
 }
 
-static void vidi_apply(struct device *subdrv_dev)
+static void vidi_apply(void *in_ctx)
 {
-	struct vidi_context *ctx = get_vidi_context(subdrv_dev);
+	struct vidi_context *ctx = in_ctx;
 	struct exynos_drm_manager *mgr = ctx->subdrv.manager;
 	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
 	struct vidi_win_data *win_data;
@@ -188,24 +188,24 @@ static void vidi_apply(struct device *subdrv_dev)
 	for (i = 0; i < WINDOWS_NR; i++) {
 		win_data = &ctx->win_data[i];
 		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
-			mgr_ops->win_commit(subdrv_dev, i);
+			mgr_ops->win_commit(ctx, i);
 	}
 
 	if (mgr_ops && mgr_ops->commit)
-		mgr_ops->commit(subdrv_dev);
+		mgr_ops->commit(ctx);
 }
 
-static void vidi_commit(struct device *dev)
+static void vidi_commit(void *in_ctx)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 
 	if (ctx->suspended)
 		return;
 }
 
-static int vidi_enable_vblank(struct device *dev)
+static int vidi_enable_vblank(void *in_ctx)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 
 	if (ctx->suspended)
 		return -EPERM;
@@ -225,9 +225,9 @@ static int vidi_enable_vblank(struct device *dev)
 	return 0;
 }
 
-static void vidi_disable_vblank(struct device *dev)
+static void vidi_disable_vblank(void *in_ctx)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 
 	if (ctx->suspended)
 		return;
@@ -236,16 +236,15 @@ static void vidi_disable_vblank(struct device *dev)
 		ctx->vblank_on = false;
 }
 
-static void vidi_win_mode_set(struct device *dev,
-			      struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(void *in_ctx, struct exynos_drm_overlay *overlay)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 	struct vidi_win_data *win_data;
 	int win;
 	unsigned long offset;
 
 	if (!overlay) {
-		dev_err(dev, "overlay is NULL\n");
+		DRM_ERROR("overlay is NULL\n");
 		return;
 	}
 
@@ -289,9 +288,9 @@ static void vidi_win_mode_set(struct device *dev,
 			overlay->fb_width, overlay->crtc_width);
 }
 
-static void vidi_win_commit(struct device *dev, int zpos)
+static void vidi_win_commit(void *in_ctx, int zpos)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
@@ -314,9 +313,9 @@ static void vidi_win_commit(struct device *dev, int zpos)
 		schedule_work(&ctx->work);
 }
 
-static void vidi_win_disable(struct device *dev, int zpos)
+static void vidi_win_disable(void *in_ctx, int zpos)
 {
-	struct vidi_context *ctx = get_vidi_context(dev);
+	struct vidi_context *ctx = in_ctx;
 	struct vidi_win_data *win_data;
 	int win = zpos;
 
@@ -405,17 +404,19 @@ static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 
 static int vidi_power_on(struct vidi_context *ctx, bool enable)
 {
-	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-	struct device *dev = subdrv->dev;
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	if (enable != false && enable != true)
+		return -EINVAL;
 
 	if (enable) {
 		ctx->suspended = false;
 
 		/* if vblank was enabled status, enable it again. */
 		if (test_and_clear_bit(0, &ctx->irq_flags))
-			vidi_enable_vblank(dev);
+			vidi_enable_vblank(ctx);
 
-		vidi_apply(dev);
+		vidi_apply(ctx);
 	} else {
 		ctx->suspended = true;
 	}
-- 
1.8.4

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

* [PATCH v2 07/26] drm/exynos: Remove apply manager callback
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (5 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 06/26] drm/exynos: Pass exynos_drm_manager in manager ops instead of dev Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 08/26] drm/exynos: Remove dpms link between encoder/connector Sean Paul
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch removes the apply() manager callback in favor of putting the
relevant commits in the individual drivers. This will mitigate some of
the difference between the suspend/resume path and the dpms path

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- This was previously in another patch, but moved since it
	  warrants its own

 drivers/gpu/drm/exynos/exynos_drm_drv.h     |  2 --
 drivers/gpu/drm/exynos/exynos_drm_encoder.c |  6 ------
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    | 22 +++++-----------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c    | 17 -----------------
 drivers/gpu/drm/exynos/exynos_hdmi.c        |  1 +
 drivers/gpu/drm/exynos/exynos_mixer.c       |  2 ++
 6 files changed, 8 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 8eb8b83..bff432a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -146,7 +146,6 @@ struct exynos_drm_display_ops {
  *
  * @initialize: initializes the manager with drm_dev
  * @dpms: control device power.
- * @apply: set timing, vblank and overlay data to registers.
  * @mode_fixup: fix mode data comparing to hw specific display mode.
  * @mode_set: convert drm_display_mode to hw specific display mode and
  *	      would be called by encoder->mode_set().
@@ -166,7 +165,6 @@ struct exynos_drm_manager_ops {
 	int (*initialize)(struct exynos_drm_manager *mgr,
 				struct drm_device *drm_dev);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
-	void (*apply)(struct exynos_drm_manager *mgr);
 	void (*mode_fixup)(struct exynos_drm_manager *mgr,
 				struct drm_connector *connector,
 				const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index ec627fa..19ee84d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -57,8 +57,6 @@ static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct drm_device *dev = encoder->dev;
-	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
 	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
@@ -72,10 +70,6 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		if (manager_ops && manager_ops->apply)
-			if (!exynos_encoder->updated)
-				manager_ops->apply(manager);
-
 		exynos_drm_connector_power(encoder, mode);
 		exynos_encoder->dpms = mode;
 		break;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 2769eb3..f0ac1d5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -672,7 +672,6 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 static struct exynos_drm_manager_ops fimd_manager_ops = {
 	.initialize = fimd_mgr_initialize,
 	.dpms = fimd_dpms,
-	.apply = fimd_apply,
 	.commit = fimd_commit,
 	.enable_vblank = fimd_enable_vblank,
 	.disable_vblank = fimd_disable_vblank,
@@ -883,6 +882,8 @@ static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 			fimd_enable_vblank(mgr);
 
 		fimd_window_resume(dev);
+
+		fimd_apply(mgr);
 	} else {
 		fimd_window_suspend(dev);
 
@@ -1037,23 +1038,10 @@ static int fimd_resume(struct device *dev)
 	 * of pm runtime would still be 1 so in this case, fimd driver
 	 * should be on directly not drawing on pm runtime interface.
 	 */
-	if (!pm_runtime_suspended(dev)) {
-		int ret;
+	if (pm_runtime_suspended(dev))
+		return 0;
 
-		ret = fimd_activate(mgr, true);
-		if (ret < 0)
-			return ret;
-
-		/*
-		 * in case of dpms on(standby), fimd_apply function will
-		 * be called by encoder's dpms callback to update fimd's
-		 * registers but in case of sleep wakeup, it's not.
-		 * so fimd_apply function should be called at here.
-		 */
-		fimd_apply(mgr);
-	}
-
-	return 0;
+	return fimd_activate(mgr, true);
 }
 #endif
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index ca0a87f..c5de00a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -302,22 +302,6 @@ static void drm_hdmi_dpms(struct exynos_drm_manager *mgr, int mode)
 		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
 }
 
-static void drm_hdmi_apply(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int i;
-
-	for (i = 0; i < MIXER_WIN_NR; i++) {
-		if (!ctx->enabled[i])
-			continue;
-		if (mixer_ops && mixer_ops->win_commit)
-			mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
-	}
-
-	if (hdmi_ops && hdmi_ops->commit)
-		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
 static void drm_mixer_win_mode_set(struct exynos_drm_manager *mgr,
 				struct exynos_drm_overlay *overlay)
 {
@@ -362,7 +346,6 @@ static void drm_mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
 	.initialize = drm_hdmi_mgr_initialize,
 	.dpms = drm_hdmi_dpms,
-	.apply = drm_hdmi_apply,
 	.enable_vblank = drm_hdmi_enable_vblank,
 	.disable_vblank = drm_hdmi_disable_vblank,
 	.wait_for_vblank = drm_hdmi_wait_for_vblank,
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index a3fba8e..94b1e0c 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1700,6 +1700,7 @@ static void hdmi_poweron(struct hdmi_context *hdata)
 	clk_prepare_enable(res->sclk_hdmi);
 
 	hdmiphy_poweron(hdata);
+	hdmi_commit(hdata);
 }
 
 static void hdmi_poweroff(struct hdmi_context *hdata)
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 2f204c1..60935c4 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -899,6 +899,8 @@ static void mixer_window_resume(struct mixer_context *ctx)
 		win_data = &ctx->win_data[i];
 		win_data->enabled = win_data->resume;
 		win_data->resume = false;
+		if (win_data->enabled)
+			mixer_win_commit(ctx, i);
 	}
 }
 
-- 
1.8.4

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

* [PATCH v2 08/26] drm/exynos: Remove dpms link between encoder/connector
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (6 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 07/26] drm/exynos: Remove apply manager callback Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 09/26] drm/exynos: Rename display_op power_on to dpms Sean Paul
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch removes the call from encoder dpms into connector dpms (which
will then call back into encoder dpms through the helper function). The
callback is likely to keep connector->dpms in the right state when
initiating dpms from crtc or encoder, but this isn't the right way to do
it. This patch is the first step towards rationalizing power management
in the exynos drm driver.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Split out the apply change into a new patch

 drivers/gpu/drm/exynos/exynos_drm_connector.c | 42 ++--------------------
 drivers/gpu/drm/exynos/exynos_drm_connector.h |  4 ---
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   | 50 +++------------------------
 3 files changed, 8 insertions(+), 88 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index 23b69d8..ca270e2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -26,7 +26,6 @@ struct exynos_drm_connector {
 	struct drm_connector	drm_connector;
 	uint32_t		encoder_id;
 	struct exynos_drm_manager *manager;
-	uint32_t		dpms;
 };
 
 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
@@ -119,7 +118,8 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
 	return ret;
 }
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *exynos_drm_best_encoder(
+		struct drm_connector *connector)
 {
 	struct drm_device *dev = connector->dev;
 	struct exynos_drm_connector *exynos_connector =
@@ -146,41 +146,6 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
 	.best_encoder	= exynos_drm_best_encoder,
 };
 
-void exynos_drm_display_power(struct drm_connector *connector, int mode)
-{
-	struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
-	struct exynos_drm_connector *exynos_connector;
-	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-	struct exynos_drm_display_ops *display_ops = manager->display_ops;
-
-	exynos_connector = to_exynos_connector(connector);
-
-	if (exynos_connector->dpms == mode) {
-		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-		return;
-	}
-
-	if (display_ops && display_ops->power_on)
-		display_ops->power_on(manager->dev, mode);
-
-	exynos_connector->dpms = mode;
-}
-
-static void exynos_drm_connector_dpms(struct drm_connector *connector,
-					int mode)
-{
-	/*
-	 * in case that drm_crtc_helper_set_mode() is called,
-	 * encoder/crtc->funcs->dpms() will be just returned
-	 * because they already were DRM_MODE_DPMS_ON so only
-	 * exynos_drm_display_power() will be called.
-	 */
-	drm_helper_connector_dpms(connector, mode);
-
-	exynos_drm_display_power(connector, mode);
-
-}
-
 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 				unsigned int max_width, unsigned int max_height)
 {
@@ -236,7 +201,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs exynos_connector_funcs = {
-	.dpms		= exynos_drm_connector_dpms,
+	.dpms		= drm_helper_connector_dpms,
 	.fill_modes	= exynos_drm_connector_fill_modes,
 	.detect		= exynos_drm_connector_detect,
 	.destroy	= exynos_drm_connector_destroy,
@@ -281,7 +246,6 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 
 	exynos_connector->encoder_id = encoder->base.id;
 	exynos_connector->manager = manager;
-	exynos_connector->dpms = DRM_MODE_DPMS_OFF;
 	connector->dpms = DRM_MODE_DPMS_OFF;
 	connector->encoder = encoder;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h
index 547c6b5..4eb20d7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h
@@ -17,8 +17,4 @@
 struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 						   struct drm_encoder *encoder);
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector);
-
-void exynos_drm_display_power(struct drm_connector *connector, int mode);
-
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 19ee84d..df4b2852 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -29,35 +29,19 @@
  * @manager: specific encoder has its own manager to control a hardware
  *	appropriately and we can access a hardware drawing on this manager.
  * @dpms: store the encoder dpms value.
- * @updated: indicate whether overlay data updating is needed or not.
  */
 struct exynos_drm_encoder {
 	struct drm_crtc			*old_crtc;
 	struct drm_encoder		drm_encoder;
 	struct exynos_drm_manager	*manager;
 	int				dpms;
-	bool				updated;
 };
 
-static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
-{
-	struct drm_device *dev = encoder->dev;
-	struct drm_connector *connector;
-
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (exynos_drm_best_encoder(connector) == encoder) {
-			DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
-					connector->base.id, mode);
-
-			exynos_drm_display_power(connector, mode);
-		}
-	}
-}
-
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-	struct drm_device *dev = encoder->dev;
+	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+	struct exynos_drm_display_ops *display_ops = manager->display_ops;
 
 	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
@@ -66,26 +50,10 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 		return;
 	}
 
-	mutex_lock(&dev->struct_mutex);
-
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-		exynos_drm_connector_power(encoder, mode);
-		exynos_encoder->dpms = mode;
-		break;
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-	case DRM_MODE_DPMS_OFF:
-		exynos_drm_connector_power(encoder, mode);
-		exynos_encoder->dpms = mode;
-		exynos_encoder->updated = false;
-		break;
-	default:
-		DRM_ERROR("unspecified mode %d\n", mode);
-		break;
-	}
+	if (display_ops && display_ops->power_on)
+		display_ops->power_on(manager->ctx, mode);
 
-	mutex_unlock(&dev->struct_mutex);
+	exynos_encoder->dpms = mode;
 }
 
 static bool
@@ -191,14 +159,6 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 		manager_ops->commit(manager);
 
 	/*
-	 * this will avoid one issue that overlay data is updated to
-	 * real hardware two times.
-	 * And this variable will be used to check if the data was
-	 * already updated or not by exynos_drm_encoder_dpms function.
-	 */
-	exynos_encoder->updated = true;
-
-	/*
 	 * In case of setcrtc, there is no way to update encoder's dpms
 	 * so update it here.
 	 */
-- 
1.8.4

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

* [PATCH v2 09/26] drm/exynos: Rename display_op power_on to dpms
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (7 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 08/26] drm/exynos: Remove dpms link between encoder/connector Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 10/26] drm/exynos: Don't keep dpms state in encoder Sean Paul
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch renames the display_op power_on to dpms to accurately reflect
what the function does.

The side-effect of this patch is that the new hdmi dpms callback is now
invoked twice in the dpms path. This is safe and will be dealt with when
the exynos_drm shim goes away.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_drv.h     | 4 ++--
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 4 ++--
 drivers/gpu/drm/exynos/exynos_drm_fimd.c    | 8 --------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c    | 8 ++++----
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h    | 3 +--
 drivers/gpu/drm/exynos/exynos_drm_vidi.c    | 8 --------
 drivers/gpu/drm/exynos/exynos_hdmi.c        | 2 +-
 7 files changed, 10 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index bff432a..e31c088 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -128,7 +128,7 @@ struct exynos_drm_overlay {
  * @get_edid: get edid modes from display driver.
  * @get_panel: get panel object from display driver.
  * @check_mode: check if mode is valid or not.
- * @power_on: display device on or off.
+ * @dpms: display device on or off.
  */
 struct exynos_drm_display_ops {
 	enum exynos_drm_output_type type;
@@ -138,7 +138,7 @@ struct exynos_drm_display_ops {
 			struct drm_connector *connector);
 	void *(*get_panel)(struct device *dev);
 	int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
-	int (*power_on)(struct device *dev, int mode);
+	int (*dpms)(struct device *dev, int mode);
 };
 
 /*
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index df4b2852..5bf1e1e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -50,8 +50,8 @@ static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 		return;
 	}
 
-	if (display_ops && display_ops->power_on)
-		display_ops->power_on(manager->ctx, mode);
+	if (display_ops && display_ops->dpms)
+		display_ops->dpms(manager->ctx, mode);
 
 	exynos_encoder->dpms = mode;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f0ac1d5..b980b05 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -169,19 +169,11 @@ static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
 	return 0;
 }
 
-static int fimd_display_power_on(struct device *dev, int mode)
-{
-	/* TODO */
-
-	return 0;
-}
-
 static struct exynos_drm_display_ops fimd_display_ops = {
 	.type = EXYNOS_DISPLAY_TYPE_LCD,
 	.is_connected = fimd_display_is_connected,
 	.get_panel = fimd_get_panel,
 	.check_mode = fimd_check_mode,
-	.power_on = fimd_display_power_on,
 };
 
 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
index c5de00a..f9a9324 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
@@ -159,12 +159,12 @@ static int drm_hdmi_check_mode(struct device *dev,
 	return drm_hdmi_check_mode_ctx(ctx, mode);
 }
 
-static int drm_hdmi_power_on(struct device *dev, int mode)
+static int drm_hdmi_display_dpms(struct device *dev, int mode)
 {
 	struct drm_hdmi_context *ctx = to_context(dev);
 
-	if (hdmi_ops && hdmi_ops->power_on)
-		return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
+	if (hdmi_ops && hdmi_ops->dpms)
+		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
 
 	return 0;
 }
@@ -175,7 +175,7 @@ static struct exynos_drm_display_ops drm_hdmi_display_ops = {
 	.is_connected = drm_hdmi_is_connected,
 	.get_edid = drm_hdmi_get_edid,
 	.check_mode = drm_hdmi_check_mode,
-	.power_on = drm_hdmi_power_on,
+	.dpms = drm_hdmi_display_dpms,
 };
 
 static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index cf7b1da..923239b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -33,14 +33,13 @@ struct exynos_hdmi_ops {
 	struct edid *(*get_edid)(void *ctx,
 			struct drm_connector *connector);
 	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-	int (*power_on)(void *ctx, int mode);
+	void (*dpms)(void *ctx, int mode);
 
 	/* manager */
 	void (*mode_set)(void *ctx, struct drm_display_mode *mode);
 	void (*get_max_resol)(void *ctx, unsigned int *width,
 				unsigned int *height);
 	void (*commit)(void *ctx);
-	void (*dpms)(void *ctx, int mode);
 };
 
 struct exynos_mixer_ops {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index a583a74..d734098 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -136,20 +136,12 @@ static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
 	return 0;
 }
 
-static int vidi_display_power_on(struct device *dev, int mode)
-{
-	/* TODO */
-
-	return 0;
-}
-
 static struct exynos_drm_display_ops vidi_display_ops = {
 	.type = EXYNOS_DISPLAY_TYPE_VIDI,
 	.is_connected = vidi_display_is_connected,
 	.get_edid = vidi_get_edid,
 	.get_panel = vidi_get_panel,
 	.check_mode = vidi_check_mode,
-	.power_on = vidi_display_power_on,
 };
 
 static void vidi_dpms(void *in_ctx, int mode)
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 94b1e0c..0b85c48 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -1761,12 +1761,12 @@ static struct exynos_hdmi_ops hdmi_ops = {
 	.is_connected	= hdmi_is_connected,
 	.get_edid	= hdmi_get_edid,
 	.check_mode	= hdmi_check_mode,
+	.dpms		= hdmi_dpms,
 
 	/* manager */
 	.mode_set	= hdmi_mode_set,
 	.get_max_resol	= hdmi_get_max_resol,
 	.commit		= hdmi_commit,
-	.dpms		= hdmi_dpms,
 };
 
 static irqreturn_t hdmi_irq_thread(int irq, void *arg)
-- 
1.8.4

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

* [PATCH v2 10/26] drm/exynos: Don't keep dpms state in encoder
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (8 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 09/26] drm/exynos: Rename display_op power_on to dpms Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 11/26] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch removes the dpms state tracking in encoder. This
state is at best confusing and at worst incorrect since the display
drivers can turn on and off without propagating the value.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 17 -----------------
 1 file changed, 17 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 5bf1e1e..a823d53 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -28,32 +28,22 @@
  * @drm_encoder: encoder object.
  * @manager: specific encoder has its own manager to control a hardware
  *	appropriately and we can access a hardware drawing on this manager.
- * @dpms: store the encoder dpms value.
  */
 struct exynos_drm_encoder {
 	struct drm_crtc			*old_crtc;
 	struct drm_encoder		drm_encoder;
 	struct exynos_drm_manager	*manager;
-	int				dpms;
 };
 
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
 	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 	struct exynos_drm_display_ops *display_ops = manager->display_ops;
 
 	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
-	if (exynos_encoder->dpms == mode) {
-		DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-		return;
-	}
-
 	if (display_ops && display_ops->dpms)
 		display_ops->dpms(manager->ctx, mode);
-
-	exynos_encoder->dpms = mode;
 }
 
 static bool
@@ -157,12 +147,6 @@ static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 
 	if (manager_ops && manager_ops->commit)
 		manager_ops->commit(manager);
-
-	/*
-	 * In case of setcrtc, there is no way to update encoder's dpms
-	 * so update it here.
-	 */
-	exynos_encoder->dpms = DRM_MODE_DPMS_ON;
 }
 
 void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
@@ -281,7 +265,6 @@ exynos_drm_encoder_create(struct drm_device *dev,
 	if (!exynos_encoder)
 		return NULL;
 
-	exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
 	exynos_encoder->manager = manager;
 	encoder = &exynos_encoder->drm_encoder;
 	encoder->possible_crtcs = possible_crtcs;
-- 
1.8.4

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

* [PATCH v2 11/26] drm/exynos: Use unsigned long for possible_crtcs
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (9 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 10/26] drm/exynos: Don't keep dpms state in encoder Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv Sean Paul
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

Change all instances of possible_crtcs in the exynos drm driver to be
unsigned long. This matches the type used in the drm layer.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_drv.c     | 2 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 2 +-
 drivers/gpu/drm/exynos/exynos_drm_encoder.h | 2 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.c   | 2 +-
 drivers/gpu/drm/exynos/exynos_drm_plane.h   | 2 +-
 5 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index bb82ef7..617748e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -84,7 +84,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	for (nr = 0; nr < MAX_PLANE; nr++) {
 		struct drm_plane *plane;
-		unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+		unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
 		plane = exynos_plane_init(dev, possible_crtcs, false);
 		if (!plane)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index a823d53..efe4e60 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -249,7 +249,7 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
 struct drm_encoder *
 exynos_drm_encoder_create(struct drm_device *dev,
 			   struct exynos_drm_manager *manager,
-			   unsigned int possible_crtcs)
+			   unsigned long possible_crtcs)
 {
 	struct drm_encoder *encoder;
 	struct exynos_drm_encoder *exynos_encoder;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index 89e2fb0..0f3e5e2 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -19,7 +19,7 @@ struct exynos_drm_manager;
 void exynos_drm_encoder_setup(struct drm_device *dev);
 struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
 					       struct exynos_drm_manager *mgr,
-					       unsigned int possible_crtcs);
+					       unsigned long possible_crtcs);
 struct exynos_drm_manager *
 exynos_drm_get_manager(struct drm_encoder *encoder);
 void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index fcb0652..cff3aed 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -259,7 +259,7 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 }
 
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-				    unsigned int possible_crtcs, bool priv)
+				    unsigned long possible_crtcs, bool priv)
 {
 	struct exynos_plane *exynos_plane;
 	int err;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 8831245..84d464c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -17,4 +17,4 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 void exynos_plane_commit(struct drm_plane *plane);
 void exynos_plane_dpms(struct drm_plane *plane, int mode);
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-				    unsigned int possible_crtcs, bool priv);
+				    unsigned long possible_crtcs, bool priv);
-- 
1.8.4

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

* [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (10 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 11/26] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-17  8:21   ` Inki Dae
  2013-10-22 10:30   ` Inki Dae
  2013-10-16 19:26 ` [PATCH v2 13/26] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
                   ` (13 subsequent siblings)
  25 siblings, 2 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch splits display and manager from subdrv. The result is that
crtc functions can directly call into manager callbacks and encoder
functions can directly call into display callbacks. This will allow
us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
with common code.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Pass display into display_ops instead of context

 drivers/gpu/drm/exynos/exynos_drm_connector.c |  50 ++-
 drivers/gpu/drm/exynos/exynos_drm_core.c      | 181 ++++++++---
 drivers/gpu/drm/exynos/exynos_drm_crtc.c      | 115 +++++--
 drivers/gpu/drm/exynos/exynos_drm_crtc.h      |  20 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c       |  29 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.h       | 106 +++---
 drivers/gpu/drm/exynos/exynos_drm_encoder.c   | 258 ++-------------
 drivers/gpu/drm/exynos/exynos_drm_encoder.h   |  18 +-
 drivers/gpu/drm/exynos/exynos_drm_fb.c        |   4 +-
 drivers/gpu/drm/exynos/exynos_drm_fimd.c      | 161 +++++----
 drivers/gpu/drm/exynos/exynos_drm_hdmi.c      | 449 --------------------------
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h      |   2 +
 drivers/gpu/drm/exynos/exynos_drm_plane.c     |  15 +-
 13 files changed, 466 insertions(+), 942 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c

diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index ca270e2..9a16dbe 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -23,26 +23,20 @@
 				drm_connector)
 
 struct exynos_drm_connector {
-	struct drm_connector	drm_connector;
-	uint32_t		encoder_id;
-	struct exynos_drm_manager *manager;
+	struct drm_connector		drm_connector;
+	uint32_t			encoder_id;
+	struct exynos_drm_display	*display;
 };
 
 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 {
 	struct exynos_drm_connector *exynos_connector =
 					to_exynos_connector(connector);
-	struct exynos_drm_manager *manager = exynos_connector->manager;
-	struct exynos_drm_display_ops *display_ops = manager->display_ops;
+	struct exynos_drm_display *display = exynos_connector->display;
 	struct edid *edid = NULL;
 	unsigned int count = 0;
 	int ret;
 
-	if (!display_ops) {
-		DRM_DEBUG_KMS("display_ops is null.\n");
-		return 0;
-	}
-
 	/*
 	 * if get_edid() exists then get_edid() callback of hdmi side
 	 * is called to get edid data through i2c interface else
@@ -51,8 +45,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 	 * P.S. in case of lcd panel, count is always 1 if success
 	 * because lcd panel has only one mode.
 	 */
-	if (display_ops->get_edid) {
-		edid = display_ops->get_edid(manager->dev, connector);
+	if (display->ops->get_edid) {
+		edid = display->ops->get_edid(display, connector);
 		if (IS_ERR_OR_NULL(edid)) {
 			ret = PTR_ERR(edid);
 			edid = NULL;
@@ -75,8 +69,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 			return 0;
 		}
 
-		if (display_ops->get_panel)
-			panel = display_ops->get_panel(manager->dev);
+		if (display->ops->get_panel)
+			panel = display->ops->get_panel(display);
 		else {
 			drm_mode_destroy(connector->dev, mode);
 			return 0;
@@ -105,14 +99,13 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
 {
 	struct exynos_drm_connector *exynos_connector =
 					to_exynos_connector(connector);
-	struct exynos_drm_manager *manager = exynos_connector->manager;
-	struct exynos_drm_display_ops *display_ops = manager->display_ops;
+	struct exynos_drm_display *display = exynos_connector->display;
 	int ret = MODE_BAD;
 
 	DRM_DEBUG_KMS("%s\n", __FILE__);
 
-	if (display_ops && display_ops->check_mode)
-		if (!display_ops->check_mode(manager->dev, mode))
+	if (display->ops->check_mode)
+		if (!display->ops->check_mode(display, mode))
 			ret = MODE_OK;
 
 	return ret;
@@ -151,8 +144,7 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 {
 	struct exynos_drm_connector *exynos_connector =
 					to_exynos_connector(connector);
-	struct exynos_drm_manager *manager = exynos_connector->manager;
-	struct exynos_drm_manager_ops *ops = manager->ops;
+	struct exynos_drm_display *display = exynos_connector->display;
 	unsigned int width, height;
 
 	width = max_width;
@@ -162,8 +154,8 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
 	 * if specific driver want to find desired_mode using maxmum
 	 * resolution then get max width and height from that driver.
 	 */
-	if (ops && ops->get_max_resol)
-		ops->get_max_resol(manager, &width, &height);
+	if (display->ops->get_max_resol)
+		display->ops->get_max_resol(display, &width, &height);
 
 	return drm_helper_probe_single_connector_modes(connector, width,
 							height);
@@ -175,13 +167,11 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force)
 {
 	struct exynos_drm_connector *exynos_connector =
 					to_exynos_connector(connector);
-	struct exynos_drm_manager *manager = exynos_connector->manager;
-	struct exynos_drm_display_ops *display_ops =
-					manager->display_ops;
+	struct exynos_drm_display *display = exynos_connector->display;
 	enum drm_connector_status status = connector_status_disconnected;
 
-	if (display_ops && display_ops->is_connected) {
-		if (display_ops->is_connected(manager->dev))
+	if (display->ops->is_connected) {
+		if (display->ops->is_connected(display))
 			status = connector_status_connected;
 		else
 			status = connector_status_disconnected;
@@ -211,7 +201,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 						   struct drm_encoder *encoder)
 {
 	struct exynos_drm_connector *exynos_connector;
-	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+	struct exynos_drm_display *display = exynos_drm_get_display(encoder);
 	struct drm_connector *connector;
 	int type;
 	int err;
@@ -222,7 +212,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 
 	connector = &exynos_connector->drm_connector;
 
-	switch (manager->display_ops->type) {
+	switch (display->type) {
 	case EXYNOS_DISPLAY_TYPE_HDMI:
 		type = DRM_MODE_CONNECTOR_HDMIA;
 		connector->interlace_allowed = true;
@@ -245,7 +235,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 		goto err_connector;
 
 	exynos_connector->encoder_id = encoder->base.id;
-	exynos_connector->manager = manager;
+	exynos_connector->display = display;
 	connector->dpms = DRM_MODE_DPMS_OFF;
 	connector->encoder = encoder;
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c
index 08ca4f9..e76098d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_core.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_core.c
@@ -16,11 +16,14 @@
 #include <drm/drmP.h>
 #include <drm/bridge/ptn3460.h>
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
 #include "exynos_drm_connector.h"
 #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);
 
 struct bridge_init {
 	struct i2c_client *client;
@@ -57,24 +60,28 @@ static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
 }
 
 static int exynos_drm_create_enc_conn(struct drm_device *dev,
-					struct exynos_drm_subdrv *subdrv)
+					struct exynos_drm_display *display)
 {
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
+	struct exynos_drm_manager *manager;
 	int ret;
+	unsigned long possible_crtcs = 0;
 
-	subdrv->manager->dev = subdrv->dev;
+	/* 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;
 
 	/* create and initialize a encoder for this sub driver. */
-	encoder = exynos_drm_encoder_create(dev, subdrv->manager,
-			(1 << MAX_CRTC) - 1);
+	encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
 	if (!encoder) {
 		DRM_ERROR("failed to create encoder\n");
 		return -EFAULT;
 	}
-	subdrv->encoder = encoder;
+	display->encoder = encoder;
 
-	if (subdrv->manager->display_ops->type == EXYNOS_DISPLAY_TYPE_LCD) {
+	if (display->type == EXYNOS_DISPLAY_TYPE_LCD) {
 		ret = exynos_drm_attach_lcd_bridge(dev, encoder);
 		if (ret)
 			return 0;
@@ -91,7 +98,7 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev,
 		goto err_destroy_encoder;
 	}
 
-	subdrv->connector = connector;
+	display->connector = connector;
 
 	return 0;
 
@@ -100,21 +107,6 @@ err_destroy_encoder:
 	return ret;
 }
 
-static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
-{
-	if (subdrv->encoder) {
-		struct drm_encoder *encoder = subdrv->encoder;
-		encoder->funcs->destroy(encoder);
-		subdrv->encoder = NULL;
-	}
-
-	if (subdrv->connector) {
-		struct drm_connector *connector = subdrv->connector;
-		connector->funcs->destroy(connector);
-		subdrv->connector = NULL;
-	}
-}
-
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
 					struct exynos_drm_subdrv *subdrv)
 {
@@ -146,10 +138,98 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev,
 		subdrv->remove(dev, subdrv->dev);
 }
 
+int exynos_drm_initialize_managers(struct drm_device *dev)
+{
+	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;
+			}
+		}
+
+		manager->drm_dev = dev;
+		manager->pipe = pipe++;
+
+		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);
+}
+
+int exynos_drm_initialize_displays(struct drm_device *dev)
+{
+	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;
+			}
+		}
+
+		initialized++;
+
+		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);
+}
+
 int exynos_drm_device_register(struct drm_device *dev)
 {
 	struct exynos_drm_subdrv *subdrv, *n;
-	unsigned int fine_cnt = 0;
 	int err;
 
 	if (!dev)
@@ -162,30 +242,8 @@ int exynos_drm_device_register(struct drm_device *dev)
 			list_del(&subdrv->list);
 			continue;
 		}
-
-		/*
-		 * if manager is null then it means that this sub driver
-		 * doesn't need encoder and connector.
-		 */
-		if (!subdrv->manager) {
-			fine_cnt++;
-			continue;
-		}
-
-		err = exynos_drm_create_enc_conn(dev, subdrv);
-		if (err) {
-			DRM_DEBUG("failed to create encoder and connector.\n");
-			exynos_drm_subdrv_remove(dev, subdrv);
-			list_del(&subdrv->list);
-			continue;
-		}
-
-		fine_cnt++;
 	}
 
-	if (!fine_cnt)
-		return -EINVAL;
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -201,13 +259,44 @@ 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);
-		exynos_drm_destroy_enc_conn(subdrv);
 	}
 
 	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)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index ebc0150..347d62d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -33,6 +33,7 @@ enum exynos_crtc_mode {
  *
  * @drm_crtc: crtc object.
  * @drm_plane: pointer of private plane object for this crtc
+ * @manager: the manager associated with this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *	and the crtc object would be set to private->crtc array
  *	to get a crtc object corresponding to this pipe from private->crtc
@@ -46,6 +47,7 @@ enum exynos_crtc_mode {
 struct exynos_drm_crtc {
 	struct drm_crtc			drm_crtc;
 	struct drm_plane		*plane;
+	struct exynos_drm_manager	*manager;
 	unsigned int			pipe;
 	unsigned int			dpms;
 	enum exynos_crtc_mode		mode;
@@ -56,6 +58,7 @@ struct exynos_drm_crtc {
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
@@ -71,7 +74,9 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 		drm_vblank_off(crtc->dev, exynos_crtc->pipe);
 	}
 
-	exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+	if (manager->ops->dpms)
+		manager->ops->dpms(manager, mode);
+
 	exynos_crtc->dpms = mode;
 }
 
@@ -83,9 +88,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
 static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
 	exynos_plane_commit(exynos_crtc->plane);
+
+	if (manager->ops->commit)
+		manager->ops->commit(manager);
+
 	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
 }
 
@@ -107,7 +118,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	struct drm_plane *plane = exynos_crtc->plane;
 	unsigned int crtc_w;
 	unsigned int crtc_h;
-	int pipe = exynos_crtc->pipe;
 	int ret;
 
 	/*
@@ -127,8 +137,6 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	plane->crtc = crtc;
 	plane->fb = crtc->fb;
 
-	exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
-
 	return 0;
 }
 
@@ -318,21 +326,24 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
 	drm_object_attach_property(&crtc->base, prop, 0);
 }
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 {
 	struct exynos_drm_crtc *exynos_crtc;
-	struct exynos_drm_private *private = dev->dev_private;
+	struct exynos_drm_private *private = manager->drm_dev->dev_private;
 	struct drm_crtc *crtc;
 
 	exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
 	if (!exynos_crtc)
 		return -ENOMEM;
 
-	exynos_crtc->pipe = nr;
-	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
 	init_waitqueue_head(&exynos_crtc->pending_flip_queue);
 	atomic_set(&exynos_crtc->pending_flip, 0);
-	exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+
+	exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
+	exynos_crtc->manager = manager;
+	exynos_crtc->pipe = manager->pipe;
+	exynos_crtc->plane = exynos_plane_init(manager->drm_dev,
+				1 << manager->pipe, true);
 	if (!exynos_crtc->plane) {
 		kfree(exynos_crtc);
 		return -ENOMEM;
@@ -340,9 +351,9 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 
 	crtc = &exynos_crtc->drm_crtc;
 
-	private->crtc[nr] = crtc;
+	private->crtc[manager->pipe] = crtc;
 
-	drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
+	drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs);
 	drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
 	exynos_drm_crtc_attach_mode_property(crtc);
@@ -350,39 +361,41 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 	return 0;
 }
 
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
 {
 	struct exynos_drm_private *private = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc =
-		to_exynos_crtc(private->crtc[crtc]);
+		to_exynos_crtc(private->crtc[pipe]);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return -EPERM;
 
-	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-			exynos_drm_enable_vblank);
+	if (manager->ops->enable_vblank)
+		manager->ops->enable_vblank(manager);
 
 	return 0;
 }
 
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
 {
 	struct exynos_drm_private *private = dev->dev_private;
 	struct exynos_drm_crtc *exynos_crtc =
-		to_exynos_crtc(private->crtc[crtc]);
+		to_exynos_crtc(private->crtc[pipe]);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
 
 	if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
 		return;
 
-	exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-			exynos_drm_disable_vblank);
+	if (manager->ops->disable_vblank)
+		manager->ops->disable_vblank(manager);
 }
 
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
 {
 	struct exynos_drm_private *dev_priv = dev->dev_private;
 	struct drm_pending_vblank_event *e, *t;
-	struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+	struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
 	unsigned long flags;
 
@@ -391,15 +404,71 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
 	list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
 			base.link) {
 		/* if event's pipe isn't same as crtc then ignore it. */
-		if (crtc != e->pipe)
+		if (pipe != e->pipe)
 			continue;
 
 		list_del(&e->base.link);
 		drm_send_vblank_event(dev, -1, e);
-		drm_vblank_put(dev, crtc);
+		drm_vblank_put(dev, pipe);
 		atomic_set(&exynos_crtc->pending_flip, 0);
 		wake_up(&exynos_crtc->pending_flip_queue);
 	}
 
 	spin_unlock_irqrestore(&dev->event_lock, flags);
 }
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+			struct exynos_drm_overlay *overlay)
+{
+	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+	if (manager->ops->win_mode_set)
+		manager->ops->win_mode_set(manager, overlay);
+}
+
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
+{
+	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+	if (manager->ops->win_commit)
+		manager->ops->win_commit(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
+{
+	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+	if (manager->ops->win_enable)
+		manager->ops->win_enable(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
+{
+	struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+	if (manager->ops->win_disable)
+		manager->ops->win_disable(manager, zpos);
+}
+
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
+{
+	struct exynos_drm_manager *manager;
+	struct drm_device *dev = fb->dev;
+	struct drm_crtc *crtc;
+
+	/*
+	 * make sure that overlay data are updated to real hardware
+	 * for all encoders.
+	 */
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		manager = to_exynos_crtc(crtc)->manager;
+
+		/*
+		 * wait for vblank interrupt
+		 * - this makes sure that overlay data are updated to
+		 *	real hardware.
+		 */
+		if (manager->ops->wait_for_vblank)
+			manager->ops->wait_for_vblank(manager);
+	}
+}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index 3e197e6..c27b66c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -15,9 +15,21 @@
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
+struct drm_device;
+struct drm_crtc;
+struct exynos_drm_manager;
+struct exynos_drm_overlay;
+
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+			struct exynos_drm_overlay *overlay);
+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);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 617748e..250903c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -72,15 +72,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 	exynos_drm_mode_config_init(dev);
 
-	/*
-	 * EXYNOS4 is enough to have two CRTCs and each crtc would be used
-	 * without dependency of hardware.
-	 */
-	for (nr = 0; nr < MAX_CRTC; nr++) {
-		ret = exynos_drm_crtc_create(dev, nr);
-		if (ret)
-			goto err_release_iommu_mapping;
-	}
+	ret = exynos_drm_initialize_managers(dev);
+	if (ret)
+		goto err_mode_config_cleanup;
 
 	for (nr = 0; nr < MAX_PLANE; nr++) {
 		struct drm_plane *plane;
@@ -88,12 +82,16 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
 		plane = exynos_plane_init(dev, possible_crtcs, false);
 		if (!plane)
-			goto err_release_iommu_mapping;
+			goto err_manager_cleanup;
 	}
 
+	ret = exynos_drm_initialize_displays(dev);
+	if (ret)
+		goto err_manager_cleanup;
+
 	ret = drm_vblank_init(dev, MAX_CRTC);
 	if (ret)
-		goto err_release_iommu_mapping;
+		goto err_display_cleanup;
 
 	/*
 	 * probe sub drivers such as display controller and hdmi driver,
@@ -125,7 +123,12 @@ err_drm_device:
 	exynos_drm_device_unregister(dev);
 err_vblank:
 	drm_vblank_cleanup(dev);
-err_release_iommu_mapping:
+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);
 err_crtc:
 	drm_mode_config_cleanup(dev);
@@ -140,6 +143,8 @@ static int exynos_drm_unload(struct drm_device *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);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index e31c088..dc730e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -122,34 +122,68 @@ struct exynos_drm_overlay {
  * Exynos DRM Display Structure.
  *	- this structure is common to analog tv, digital tv and lcd panel.
  *
- * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
  * @initialize: initializes the display with drm_dev
+ * @remove: cleans up the display for removal
  * @is_connected: check for that display is connected or not.
+ * @get_max_resol: get maximum resolution to specific hardware.
  * @get_edid: get edid modes from display driver.
  * @get_panel: get panel object from display driver.
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ *	      would be called by encoder->mode_set().
  * @check_mode: check if mode is valid or not.
  * @dpms: display device on or off.
+ * @commit: apply changes to hw
  */
+struct exynos_drm_display;
 struct exynos_drm_display_ops {
+	int (*initialize)(struct exynos_drm_display *display,
+				struct drm_device *drm_dev);
+	void (*remove)(struct exynos_drm_display *display);
+	bool (*is_connected)(struct exynos_drm_display *display);
+	void (*get_max_resol)(struct exynos_drm_display *display,
+				unsigned int *width,
+				unsigned int *height);
+	struct edid *(*get_edid)(struct exynos_drm_display *display,
+				struct drm_connector *connector);
+	void *(*get_panel)(struct exynos_drm_display *display);
+	void (*mode_fixup)(struct exynos_drm_display *display,
+				struct drm_connector *connector,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode);
+	void (*mode_set)(struct exynos_drm_display *display,
+				struct drm_display_mode *mode);
+	int (*check_mode)(struct exynos_drm_display *display,
+				struct drm_display_mode *mode);
+	void (*dpms)(struct exynos_drm_display *display, int mode);
+	void (*commit)(struct exynos_drm_display *display);
+};
+
+/*
+ * Exynos drm display structure, maps 1:1 with an encoder/connector
+ *
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @encoder: encoder object this display maps to
+ * @connector: connector object this display maps to
+ * @ops: pointer to callbacks for exynos drm specific functionality
+ * @ctx: A pointer to the display's implementation specific context
+ */
+struct exynos_drm_display {
+	struct list_head list;
 	enum exynos_drm_output_type type;
-	int (*initialize)(struct device *dev, struct drm_device *drm_dev);
-	bool (*is_connected)(struct device *dev);
-	struct edid *(*get_edid)(struct device *dev,
-			struct drm_connector *connector);
-	void *(*get_panel)(struct device *dev);
-	int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
-	int (*dpms)(struct device *dev, int mode);
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct exynos_drm_display_ops *ops;
+	void *ctx;
 };
 
 /*
  * 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 comparing to hw specific display mode.
- * @mode_set: convert drm_display_mode to hw specific display mode and
- *	      would be called by encoder->mode_set().
- * @get_max_resol: get maximum resolution to specific hardware.
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -163,15 +197,9 @@ struct exynos_drm_display_ops {
 struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
 	int (*initialize)(struct exynos_drm_manager *mgr,
-				struct drm_device *drm_dev);
+				struct drm_device *drm_dev, int pipe);
+	void (*remove)(struct exynos_drm_manager *mgr);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
-	void (*mode_fixup)(struct exynos_drm_manager *mgr,
-				struct drm_connector *connector,
-				const struct drm_display_mode *mode,
-				struct drm_display_mode *adjusted_mode);
-	void (*mode_set)(struct exynos_drm_manager *mgr, void *mode);
-	void (*get_max_resol)(struct exynos_drm_manager *mgr,
-				unsigned int *width, unsigned int *height);
 	void (*commit)(struct exynos_drm_manager *mgr);
 	int (*enable_vblank)(struct exynos_drm_manager *mgr);
 	void (*disable_vblank)(struct exynos_drm_manager *mgr);
@@ -184,25 +212,21 @@ struct exynos_drm_manager_ops {
 };
 
 /*
- * Exynos drm common manager structure.
+ * Exynos drm common manager structure, maps 1:1 with a crtc
  *
- * @dev: pointer to device object for subdrv device driver.
- *	sub drivers such as display controller or hdmi driver,
- *	have their own device object.
- * @ops: pointer to callbacks for exynos drm specific framebuffer.
- *	these callbacks should be set by specific drivers such fimd
- *	or hdmi driver and are used to control hardware global registers.
- * @display: pointer to callbacks for exynos drm specific framebuffer.
- *	these callbacks should be set by specific drivers such fimd
- *	or hdmi driver and are used to control display devices such as
- *	analog tv, digital tv and lcd panel and also get timing data for them.
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @drm_dev: pointer to the drm device
+ * @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
  */
 struct exynos_drm_manager {
-	struct device *dev;
+	struct list_head list;
+	enum exynos_drm_output_type type;
+	struct drm_device *drm_dev;
 	int pipe;
 	struct exynos_drm_manager_ops *ops;
-	struct exynos_drm_display_ops *display_ops;
 	void *ctx;
 };
 
@@ -267,14 +291,11 @@ struct exynos_drm_private {
  *	by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
- * @encoder: encoder object owned by this sub driver.
- * @connector: connector object owned by this sub driver.
  */
 struct exynos_drm_subdrv {
 	struct list_head list;
 	struct device *dev;
 	struct drm_device *drm_dev;
-	struct exynos_drm_manager *manager;
 
 	int (*probe)(struct drm_device *drm_dev, struct device *dev);
 	void (*remove)(struct drm_device *drm_dev, struct device *dev);
@@ -282,9 +303,6 @@ struct exynos_drm_subdrv {
 			struct drm_file *file);
 	void (*close)(struct drm_device *drm_dev, struct device *dev,
 			struct drm_file *file);
-
-	struct drm_encoder *encoder;
-	struct drm_connector *connector;
 };
 
 /*
@@ -299,6 +317,16 @@ int exynos_drm_device_register(struct drm_device *dev);
  */
 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
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index efe4e60..d4ae664 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -26,24 +26,23 @@
  * exynos specific encoder structure.
  *
  * @drm_encoder: encoder object.
- * @manager: specific encoder has its own manager to control a hardware
- *	appropriately and we can access a hardware drawing on this manager.
+ * @display: the display structure that maps to this encoder
  */
 struct exynos_drm_encoder {
 	struct drm_crtc			*old_crtc;
 	struct drm_encoder		drm_encoder;
-	struct exynos_drm_manager	*manager;
+	struct exynos_drm_display	*display;
 };
 
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-	struct exynos_drm_display_ops *display_ops = manager->display_ops;
+	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+	struct exynos_drm_display *display = exynos_encoder->display;
 
 	DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
-	if (display_ops && display_ops->dpms)
-		display_ops->dpms(manager->ctx, mode);
+	if (display->ops->dpms)
+		display->ops->dpms(display, mode);
 }
 
 static bool
@@ -52,15 +51,17 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 			       struct drm_display_mode *adjusted_mode)
 {
 	struct drm_device *dev = encoder->dev;
+	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+	struct exynos_drm_display *display = exynos_encoder->display;
 	struct drm_connector *connector;
-	struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder)
-			if (manager_ops && manager_ops->mode_fixup)
-				manager_ops->mode_fixup(manager, connector,
-							mode, adjusted_mode);
+		if (connector->encoder != encoder)
+			continue;
+
+		if (display->ops->mode_fixup)
+			display->ops->mode_fixup(display, connector, mode,
+					adjusted_mode);
 	}
 
 	return true;
@@ -102,8 +103,7 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 {
 	struct drm_device *dev = encoder->dev;
 	struct drm_connector *connector;
-	struct exynos_drm_manager *manager;
-	struct exynos_drm_manager_ops *manager_ops;
+	struct exynos_drm_display *display;
 
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 		if (connector->encoder == encoder) {
@@ -123,11 +123,11 @@ static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 						encoder->crtc);
 			}
 
-			manager = exynos_drm_get_manager(encoder);
-			manager_ops = manager->ops;
+			display = exynos_encoder->display;
 
-			if (manager_ops && manager_ops->mode_set)
-				manager_ops->mode_set(manager, adjusted_mode);
+			if (display->ops->mode_set)
+				display->ops->mode_set(display,
+							adjusted_mode);
 
 			exynos_encoder->old_crtc = encoder->crtc;
 		}
@@ -142,39 +142,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 {
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-	struct exynos_drm_manager *manager = exynos_encoder->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-
-	if (manager_ops && manager_ops->commit)
-		manager_ops->commit(manager);
-}
+	struct exynos_drm_display *display = exynos_encoder->display;
 
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
-{
-	struct exynos_drm_encoder *exynos_encoder;
-	struct exynos_drm_manager_ops *ops;
-	struct drm_device *dev = fb->dev;
-	struct drm_encoder *encoder;
+	if (display->ops->dpms)
+		display->ops->dpms(display, DRM_MODE_DPMS_ON);
 
-	/*
-	 * make sure that overlay data are updated to real hardware
-	 * for all encoders.
-	 */
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		exynos_encoder = to_exynos_encoder(encoder);
-		ops = exynos_encoder->manager->ops;
-
-		/*
-		 * wait for vblank interrupt
-		 * - this makes sure that overlay data are updated to
-		 *	real hardware.
-		 */
-		if (ops->wait_for_vblank)
-			ops->wait_for_vblank(exynos_encoder->manager);
-	}
+	if (display->ops->commit)
+		display->ops->commit(display);
 }
 
-
 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 {
 	struct drm_plane *plane;
@@ -200,10 +176,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
 
 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
 {
-	struct exynos_drm_encoder *exynos_encoder =
-		to_exynos_encoder(encoder);
-
-	exynos_encoder->manager->pipe = -1;
+	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
 	drm_encoder_cleanup(encoder);
 	kfree(exynos_encoder);
@@ -218,13 +191,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
 	struct drm_encoder *clone;
 	struct drm_device *dev = encoder->dev;
 	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-	struct exynos_drm_display_ops *display_ops =
-				exynos_encoder->manager->display_ops;
+	struct exynos_drm_display *display = exynos_encoder->display;
 	unsigned int clone_mask = 0;
 	int cnt = 0;
 
 	list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
-		switch (display_ops->type) {
+		switch (display->type) {
 		case EXYNOS_DISPLAY_TYPE_LCD:
 		case EXYNOS_DISPLAY_TYPE_HDMI:
 		case EXYNOS_DISPLAY_TYPE_VIDI:
@@ -248,24 +220,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
 
 struct drm_encoder *
 exynos_drm_encoder_create(struct drm_device *dev,
-			   struct exynos_drm_manager *manager,
+			   struct exynos_drm_display *display,
 			   unsigned long possible_crtcs)
 {
 	struct drm_encoder *encoder;
 	struct exynos_drm_encoder *exynos_encoder;
-	int ret;
 
-	if (!manager || !possible_crtcs)
-		return NULL;
-
-	if (!manager->dev)
+	if (!possible_crtcs)
 		return NULL;
 
 	exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
 	if (!exynos_encoder)
 		return NULL;
 
-	exynos_encoder->manager = manager;
+	exynos_encoder->display = display;
 	encoder = &exynos_encoder->drm_encoder;
 	encoder->possible_crtcs = possible_crtcs;
 
@@ -276,174 +244,12 @@ exynos_drm_encoder_create(struct drm_device *dev,
 
 	drm_encoder_helper_add(encoder, &exynos_encoder_helper_funcs);
 
-	if (manager->ops && manager->ops->initialize) {
-		ret = manager->ops->initialize(manager, dev);
-		if (ret) {
-			DRM_ERROR("Manager initialize failed %d\n", ret);
-			goto error;
-		}
-	}
-
-	if (manager->display_ops && manager->display_ops->initialize) {
-		ret = manager->display_ops->initialize(manager->dev, dev);
-		if (ret) {
-			DRM_ERROR("Display initialize failed %d\n", ret);
-			goto error;
-		}
-	}
-
 	DRM_DEBUG_KMS("encoder has been created\n");
 
 	return encoder;
-
-error:
-	exynos_drm_encoder_destroy(&exynos_encoder->drm_encoder);
-	return NULL;
 }
 
-struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
 {
-	return to_exynos_encoder(encoder)->manager;
-}
-
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-			    void (*fn)(struct drm_encoder *, void *))
-{
-	struct drm_device *dev = crtc->dev;
-	struct drm_encoder *encoder;
-	struct exynos_drm_private *private = dev->dev_private;
-	struct exynos_drm_manager *manager;
-
-	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-		/*
-		 * if crtc is detached from encoder, check pipe,
-		 * otherwise check crtc attached to encoder
-		 */
-		if (!encoder->crtc) {
-			manager = to_exynos_encoder(encoder)->manager;
-			if (manager->pipe < 0 ||
-					private->crtc[manager->pipe] != crtc)
-				continue;
-		} else {
-			if (encoder->crtc != crtc)
-				continue;
-		}
-
-		fn(encoder, data);
-	}
-}
-
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int crtc = *(int *)data;
-
-	if (manager->pipe != crtc)
-		return;
-
-	if (manager_ops->enable_vblank)
-		manager_ops->enable_vblank(manager);
-}
-
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int crtc = *(int *)data;
-
-	if (manager->pipe != crtc)
-		return;
-
-	if (manager_ops->disable_vblank)
-		manager_ops->disable_vblank(manager);
-}
-
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-	struct exynos_drm_manager *manager = exynos_encoder->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int mode = *(int *)data;
-
-	if (manager_ops && manager_ops->dpms)
-		manager_ops->dpms(manager, mode);
-
-	/*
-	 * if this condition is ok then it means that the crtc is already
-	 * detached from encoder and last function for detaching is properly
-	 * done, so clear pipe from manager to prevent repeated call.
-	 */
-	if (mode > DRM_MODE_DPMS_ON) {
-		if (!encoder->crtc)
-			manager->pipe = -1;
-	}
-}
-
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	int pipe = *(int *)data;
-
-	/*
-	 * when crtc is detached from encoder, this pipe is used
-	 * to select manager operation
-	 */
-	manager->pipe = pipe;
-}
-
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	struct exynos_drm_overlay *overlay = data;
-
-	if (manager_ops && manager_ops->win_mode_set)
-		manager_ops->win_mode_set(manager, overlay);
-}
-
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int zpos = DEFAULT_ZPOS;
-
-	if (data)
-		zpos = *(int *)data;
-
-	if (manager_ops && manager_ops->win_commit)
-		manager_ops->win_commit(manager, zpos);
-}
-
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int zpos = DEFAULT_ZPOS;
-
-	if (data)
-		zpos = *(int *)data;
-
-	if (manager_ops && manager_ops->win_enable)
-		manager_ops->win_enable(manager, zpos);
-}
-
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
-{
-	struct exynos_drm_manager *manager =
-		to_exynos_encoder(encoder)->manager;
-	struct exynos_drm_manager_ops *manager_ops = manager->ops;
-	int zpos = DEFAULT_ZPOS;
-
-	if (data)
-		zpos = *(int *)data;
-
-	if (manager_ops && manager_ops->win_disable)
-		manager_ops->win_disable(manager, zpos);
+	return to_exynos_encoder(encoder)->display;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
index 0f3e5e2..b7a1620 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h
@@ -18,20 +18,8 @@ struct exynos_drm_manager;
 
 void exynos_drm_encoder_setup(struct drm_device *dev);
 struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
-					       struct exynos_drm_manager *mgr,
-					       unsigned long possible_crtcs);
-struct exynos_drm_manager *
-exynos_drm_get_manager(struct drm_encoder *encoder);
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-			    void (*fn)(struct drm_encoder *, void *));
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+			struct exynos_drm_display *mgr,
+			unsigned long possible_crtcs);
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c
index ea39e0e..c7c08d0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fb.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c
@@ -22,7 +22,7 @@
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_iommu.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 
 #define to_exynos_fb(x)	container_of(x, struct exynos_drm_fb, fb)
 
@@ -71,7 +71,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
 	unsigned int i;
 
 	/* make sure that overlay data are updated before relesing fb. */
-	exynos_drm_encoder_complete_scanout(fb);
+	exynos_drm_crtc_complete_scanout(fb);
 
 	drm_framebuffer_cleanup(fb);
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index b980b05..d2b8ccb 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -105,7 +105,6 @@ struct fimd_win_data {
 };
 
 struct fimd_context {
-	struct exynos_drm_subdrv	subdrv;
 	struct device			*dev;
 	struct drm_device		*drm_dev;
 	int				irq;
@@ -120,6 +119,7 @@ struct fimd_context {
 	u32				vidcon0;
 	u32				vidcon1;
 	bool				suspended;
+	int				pipe;
 	struct mutex			lock;
 	wait_queue_head_t		wait_vsync_queue;
 	atomic_t			wait_vsync_event;
@@ -147,22 +147,22 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
 	return (struct fimd_driver_data *)of_id->data;
 }
 
-static bool fimd_display_is_connected(struct device *dev)
+static bool fimd_display_is_connected(struct exynos_drm_display *display)
 {
 	/* TODO. */
 
 	return true;
 }
 
-static void *fimd_get_panel(struct device *dev)
+static void *fimd_get_panel(struct exynos_drm_display *display)
 {
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-	struct fimd_context *ctx = mgr->ctx;
+	struct fimd_context *ctx = display->ctx;
 
 	return &ctx->panel;
 }
 
-static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
+static int fimd_check_mode(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
 {
 	/* TODO. */
 
@@ -170,12 +170,16 @@ static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
 }
 
 static struct exynos_drm_display_ops fimd_display_ops = {
-	.type = EXYNOS_DISPLAY_TYPE_LCD,
 	.is_connected = fimd_display_is_connected,
 	.get_panel = fimd_get_panel,
 	.check_mode = fimd_check_mode,
 };
 
+static struct exynos_drm_display fimd_display = {
+	.type = EXYNOS_DISPLAY_TYPE_LCD,
+	.ops = &fimd_display_ops,
+};
+
 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
 			struct exynos_drm_overlay *overlay)
 {
@@ -484,15 +488,45 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
 }
 
 static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
-			struct drm_device *drm_dev)
+			struct drm_device *drm_dev, int pipe)
 {
 	struct fimd_context *ctx = mgr->ctx;
 
 	ctx->drm_dev = drm_dev;
+	ctx->pipe = pipe;
+
+	/*
+	 * enable drm irq mode.
+	 * - with irq_enabled = 1, we can use the vblank feature.
+	 *
+	 * P.S. note that we wouldn't use drm irq handler but
+	 *	just specific driver own one instead because
+	 *	drm framework supports only one irq handler.
+	 */
+	ctx->drm_dev->irq_enabled = 1;
+
+	/*
+	 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
+	 * by drm timer once a current process gives up ownership of
+	 * vblank event.(after drm_vblank_put function is called)
+	 */
+	drm_dev->vblank_disable_allowed = 1;
+
+	/* attach this sub driver to iommu mapping if supported. */
+	if (is_drm_iommu_supported(ctx->drm_dev))
+		drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
 
 	return 0;
 }
 
+static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+
+	if (is_drm_iommu_supported(ctx->drm_dev))
+		drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+}
+
 static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 {
 	struct fimd_context *ctx = mgr->ctx;
@@ -526,23 +560,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 	mutex_unlock(&ctx->lock);
 }
 
-static void fimd_apply(struct exynos_drm_manager *mgr)
-{
-	struct fimd_context *ctx = mgr->ctx;
-	struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-	struct fimd_win_data *win_data;
-	int i;
-
-	for (i = 0; i < WINDOWS_NR; i++) {
-		win_data = &ctx->win_data[i];
-		if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
-			mgr_ops->win_commit(mgr, i);
-	}
-
-	if (mgr_ops && mgr_ops->commit)
-		mgr_ops->commit(mgr);
-}
-
 static void fimd_commit(struct exynos_drm_manager *mgr)
 {
 	struct fimd_context *ctx = mgr->ctx;
@@ -599,6 +616,21 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 	writel(val, ctx->regs + VIDCON0);
 }
 
+static void fimd_apply(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+	struct fimd_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		if (win_data->enabled)
+			fimd_win_commit(mgr, i);
+	}
+
+	fimd_commit(mgr);
+}
+
 static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
 {
 	struct fimd_context *ctx = mgr->ctx;
@@ -663,6 +695,7 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 
 static struct exynos_drm_manager_ops fimd_manager_ops = {
 	.initialize = fimd_mgr_initialize,
+	.remove = fimd_mgr_remove,
 	.dpms = fimd_dpms,
 	.commit = fimd_commit,
 	.enable_vblank = fimd_enable_vblank,
@@ -674,16 +707,13 @@ static struct exynos_drm_manager_ops fimd_manager_ops = {
 };
 
 static struct exynos_drm_manager fimd_manager = {
-	.pipe		= -1,
-	.ops		= &fimd_manager_ops,
-	.display_ops	= &fimd_display_ops,
+	.type = EXYNOS_DISPLAY_TYPE_LCD,
+	.ops = &fimd_manager_ops,
 };
 
 static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 {
 	struct fimd_context *ctx = (struct fimd_context *)dev_id;
-	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-	struct exynos_drm_manager *manager = subdrv->manager;
 	u32 val;
 
 	val = readl(ctx->regs + VIDINTCON1);
@@ -693,11 +723,11 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
 		writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
 
 	/* check the crtc is detached already from encoder */
-	if (manager->pipe < 0 || !ctx->drm_dev)
+	if (ctx->pipe < 0 || !ctx->drm_dev)
 		goto out;
 
-	drm_handle_vblank(ctx->drm_dev, manager->pipe);
-	exynos_drm_crtc_finish_pageflip(ctx->drm_dev, manager->pipe);
+	drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+	exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 
 	/* set wait vsync event to zero and wake up queue. */
 	if (atomic_read(&ctx->wait_vsync_event)) {
@@ -708,39 +738,6 @@ out:
 	return IRQ_HANDLED;
 }
 
-static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
-	/*
-	 * enable drm irq mode.
-	 * - with irq_enabled = 1, we can use the vblank feature.
-	 *
-	 * P.S. note that we wouldn't use drm irq handler but
-	 *	just specific driver own one instead because
-	 *	drm framework supports only one irq handler.
-	 */
-	drm_dev->irq_enabled = 1;
-
-	/*
-	 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
-	 * by drm timer once a current process gives up ownership of
-	 * vblank event.(after drm_vblank_put function is called)
-	 */
-	drm_dev->vblank_disable_allowed = 1;
-
-	/* attach this sub driver to iommu mapping if supported. */
-	if (is_drm_iommu_supported(drm_dev))
-		drm_iommu_attach_device(drm_dev, dev);
-
-	return 0;
-}
-
-static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-	/* detach this sub driver from iommu mapping if supported. */
-	if (is_drm_iommu_supported(drm_dev))
-		drm_iommu_detach_device(drm_dev, dev);
-}
-
 static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
 {
 	struct videomode *vm = &ctx->panel.vm;
@@ -826,9 +823,8 @@ static int fimd_clock(struct fimd_context *ctx, bool enable)
 	return 0;
 }
 
-static void fimd_window_suspend(struct device *dev)
+static void fimd_window_suspend(struct exynos_drm_manager *mgr)
 {
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int i;
@@ -841,9 +837,8 @@ static void fimd_window_suspend(struct device *dev)
 	fimd_wait_for_vblank(mgr);
 }
 
-static void fimd_window_resume(struct device *dev)
+static void fimd_window_resume(struct exynos_drm_manager *mgr)
 {
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 	struct fimd_context *ctx = mgr->ctx;
 	struct fimd_win_data *win_data;
 	int i;
@@ -858,7 +853,6 @@ static void fimd_window_resume(struct device *dev)
 static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 {
 	struct fimd_context *ctx = mgr->ctx;
-	struct device *dev = ctx->subdrv.dev;
 
 	if (enable) {
 		int ret;
@@ -873,11 +867,11 @@ static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 		if (test_and_clear_bit(0, &ctx->irq_flags))
 			fimd_enable_vblank(mgr);
 
-		fimd_window_resume(dev);
+		fimd_window_resume(mgr);
 
 		fimd_apply(mgr);
 	} else {
-		fimd_window_suspend(dev);
+		fimd_window_suspend(mgr);
 
 		fimd_clock(ctx, false);
 		ctx->suspended = true;
@@ -914,7 +908,6 @@ static int fimd_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct fimd_context *ctx;
-	struct exynos_drm_subdrv *subdrv;
 	struct resource *res;
 	int win;
 	int ret = -EINVAL;
@@ -961,27 +954,22 @@ static int fimd_probe(struct platform_device *pdev)
 	DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
-	fimd_manager.ctx = ctx;
-
-	subdrv = &ctx->subdrv;
-
-	subdrv->dev = dev;
-	subdrv->manager = &fimd_manager;
-	subdrv->probe = fimd_subdrv_probe;
-	subdrv->remove = fimd_subdrv_remove;
-
 	mutex_init(&ctx->lock);
 
 	platform_set_drvdata(pdev, &fimd_manager);
 
+	fimd_manager.ctx = ctx;
+	exynos_drm_manager_register(&fimd_manager);
+
+	fimd_display.ctx = ctx;
+	exynos_drm_display_register(&fimd_display);
+
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 
 	for (win = 0; win < WINDOWS_NR; win++)
 		fimd_clear_win(ctx, win);
 
-	exynos_drm_subdrv_register(subdrv);
-
 	return 0;
 }
 
@@ -991,7 +979,8 @@ static int fimd_remove(struct platform_device *pdev)
 	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
 	struct fimd_context *ctx = mgr->ctx;
 
-	exynos_drm_subdrv_unregister(&ctx->subdrv);
+	exynos_drm_display_unregister(&fimd_display);
+	exynos_drm_manager_unregister(&fimd_manager);
 
 	if (ctx->suspended)
 		goto out;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
deleted file mode 100644
index f9a9324..0000000
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *	Inki Dae <inki.dae@samsung.com>
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include <drm/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-#define to_context(dev)		platform_get_drvdata(to_platform_device(dev))
-#define to_subdrv(dev)		to_context(dev)
-#define get_ctx_from_subdrv(subdrv)	container_of(subdrv,\
-					struct drm_hdmi_context, subdrv);
-
-/* platform device pointer for common drm hdmi device. */
-static struct platform_device *exynos_drm_hdmi_pdev;
-
-/* Common hdmi subdrv needs to access the hdmi and mixer though context.
-* These should be initialied by the repective drivers */
-static struct exynos_drm_hdmi_context *hdmi_ctx;
-static struct exynos_drm_hdmi_context *mixer_ctx;
-
-/* these callback points shoud be set by specific drivers. */
-static struct exynos_hdmi_ops *hdmi_ops;
-static struct exynos_mixer_ops *mixer_ops;
-
-struct drm_hdmi_context {
-	struct exynos_drm_subdrv	subdrv;
-	struct exynos_drm_hdmi_context	*hdmi_ctx;
-	struct exynos_drm_hdmi_context	*mixer_ctx;
-
-	bool	enabled[MIXER_WIN_NR];
-};
-
-int exynos_platform_device_hdmi_register(void)
-{
-	struct platform_device *pdev;
-
-	if (exynos_drm_hdmi_pdev)
-		return -EEXIST;
-
-	pdev = platform_device_register_simple(
-			"exynos-drm-hdmi", -1, NULL, 0);
-	if (IS_ERR(pdev))
-		return PTR_ERR(pdev);
-
-	exynos_drm_hdmi_pdev = pdev;
-
-	return 0;
-}
-
-void exynos_platform_device_hdmi_unregister(void)
-{
-	if (exynos_drm_hdmi_pdev) {
-		platform_device_unregister(exynos_drm_hdmi_pdev);
-		exynos_drm_hdmi_pdev = NULL;
-	}
-}
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-	if (ctx)
-		hdmi_ctx = ctx;
-}
-
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-	if (ctx)
-		mixer_ctx = ctx;
-}
-
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
-{
-	if (ops)
-		hdmi_ops = ops;
-}
-
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
-{
-	if (ops)
-		mixer_ops = ops;
-}
-
-static int drm_hdmi_display_initialize(struct device *dev,
-		struct drm_device *drm_dev)
-{
-	struct drm_hdmi_context *ctx = to_context(dev);
-
-	if (hdmi_ops && hdmi_ops->initialize)
-		return hdmi_ops->initialize(ctx->hdmi_ctx->ctx, drm_dev);
-
-	return 0;
-}
-
-
-static bool drm_hdmi_is_connected(struct device *dev)
-{
-	struct drm_hdmi_context *ctx = to_context(dev);
-
-	if (hdmi_ops && hdmi_ops->is_connected)
-		return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
-
-	return false;
-}
-
-static struct edid *drm_hdmi_get_edid(struct device *dev,
-			struct drm_connector *connector)
-{
-	struct drm_hdmi_context *ctx = to_context(dev);
-
-	if (hdmi_ops && hdmi_ops->get_edid)
-		return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
-
-	return NULL;
-}
-static int drm_hdmi_check_mode_ctx(struct drm_hdmi_context *ctx,
-		struct drm_display_mode *mode)
-{
-	int ret = 0;
-
-	/*
-	* Both, mixer and hdmi should be able to handle the requested mode.
-	* If any of the two fails, return mode as BAD.
-	*/
-
-	if (mixer_ops && mixer_ops->check_mode)
-		ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode);
-
-	if (ret)
-		return ret;
-
-	if (hdmi_ops && hdmi_ops->check_mode)
-		return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
-
-	return 0;
-}
-
-static int drm_hdmi_check_mode(struct device *dev,
-		struct drm_display_mode *mode)
-{
-	struct drm_hdmi_context *ctx = to_context(dev);
-
-	return drm_hdmi_check_mode_ctx(ctx, mode);
-}
-
-static int drm_hdmi_display_dpms(struct device *dev, int mode)
-{
-	struct drm_hdmi_context *ctx = to_context(dev);
-
-	if (hdmi_ops && hdmi_ops->dpms)
-		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-
-	return 0;
-}
-
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
-	.type = EXYNOS_DISPLAY_TYPE_HDMI,
-	.initialize = drm_hdmi_display_initialize,
-	.is_connected = drm_hdmi_is_connected,
-	.get_edid = drm_hdmi_get_edid,
-	.check_mode = drm_hdmi_check_mode,
-	.dpms = drm_hdmi_display_dpms,
-};
-
-static int drm_hdmi_enable_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-	struct exynos_drm_manager *manager = subdrv->manager;
-
-	if (mixer_ops && mixer_ops->enable_vblank)
-		return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
-						manager->pipe);
-
-	return 0;
-}
-
-static void drm_hdmi_disable_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->disable_vblank)
-		return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_wait_for_vblank(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->wait_for_vblank)
-		mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_mode_fixup(struct exynos_drm_manager *mgr,
-				struct drm_connector *connector,
-				const struct drm_display_mode *mode,
-				struct drm_display_mode *adjusted_mode)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	struct drm_display_mode *m;
-	int mode_ok;
-
-	drm_mode_set_crtcinfo(adjusted_mode, 0);
-
-	mode_ok = drm_hdmi_check_mode_ctx(ctx, adjusted_mode);
-
-	/* just return if user desired mode exists. */
-	if (mode_ok == 0)
-		return;
-
-	/*
-	 * otherwise, find the most suitable mode among modes and change it
-	 * to adjusted_mode.
-	 */
-	list_for_each_entry(m, &connector->modes, head) {
-		mode_ok = drm_hdmi_check_mode_ctx(ctx, m);
-
-		if (mode_ok == 0) {
-			struct drm_mode_object base;
-			struct list_head head;
-
-			DRM_INFO("desired mode doesn't exist so\n");
-			DRM_INFO("use the most suitable mode among modes.\n");
-
-			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
-				m->hdisplay, m->vdisplay, m->vrefresh);
-
-			/* preserve display mode header while copying. */
-			head = adjusted_mode->head;
-			base = adjusted_mode->base;
-			memcpy(adjusted_mode, m, sizeof(*m));
-			adjusted_mode->head = head;
-			adjusted_mode->base = base;
-			break;
-		}
-	}
-}
-
-static void drm_hdmi_mode_set(struct exynos_drm_manager *mgr, void *mode)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (hdmi_ops && hdmi_ops->mode_set)
-		hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_get_max_resol(struct exynos_drm_manager *mgr,
-				unsigned int *width, unsigned int *height)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (hdmi_ops && hdmi_ops->get_max_resol)
-		hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
-}
-
-static void drm_hdmi_commit(struct exynos_drm_manager *mgr)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (hdmi_ops && hdmi_ops->commit)
-		hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static int drm_hdmi_mgr_initialize(struct exynos_drm_manager *mgr, struct drm_device *drm_dev)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int ret = 0;
-
-	if (mixer_ops && mixer_ops->initialize)
-		ret = mixer_ops->initialize(ctx->mixer_ctx->ctx, drm_dev);
-
-	if (mixer_ops->iommu_on)
-		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
-	return ret;
-}
-
-static void drm_hdmi_dpms(struct exynos_drm_manager *mgr, int mode)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->dpms)
-		mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
-
-	if (hdmi_ops && hdmi_ops->dpms)
-		hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_mixer_win_mode_set(struct exynos_drm_manager *mgr,
-				struct exynos_drm_overlay *overlay)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-
-	if (mixer_ops && mixer_ops->win_mode_set)
-		mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
-}
-
-static void drm_mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-	if (win < 0 || win >= MIXER_WIN_NR) {
-		DRM_ERROR("mixer window[%d] is wrong\n", win);
-		return;
-	}
-
-	if (mixer_ops && mixer_ops->win_commit)
-		mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
-
-	ctx->enabled[win] = true;
-}
-
-static void drm_mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
-{
-	struct drm_hdmi_context *ctx = mgr->ctx;
-	int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-	if (win < 0 || win >= MIXER_WIN_NR) {
-		DRM_ERROR("mixer window[%d] is wrong\n", win);
-		return;
-	}
-
-	if (mixer_ops && mixer_ops->win_disable)
-		mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
-
-	ctx->enabled[win] = false;
-}
-
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
-	.initialize = drm_hdmi_mgr_initialize,
-	.dpms = drm_hdmi_dpms,
-	.enable_vblank = drm_hdmi_enable_vblank,
-	.disable_vblank = drm_hdmi_disable_vblank,
-	.wait_for_vblank = drm_hdmi_wait_for_vblank,
-	.mode_fixup = drm_hdmi_mode_fixup,
-	.mode_set = drm_hdmi_mode_set,
-	.get_max_resol = drm_hdmi_get_max_resol,
-	.commit = drm_hdmi_commit,
-	.win_mode_set = drm_mixer_win_mode_set,
-	.win_commit = drm_mixer_win_commit,
-	.win_disable = drm_mixer_win_disable,
-};
-
-static struct exynos_drm_manager hdmi_manager = {
-	.pipe		= -1,
-	.ops		= &drm_hdmi_manager_ops,
-	.display_ops	= &drm_hdmi_display_ops,
-};
-
-static int hdmi_subdrv_probe(struct drm_device *drm_dev,
-		struct device *dev)
-{
-	struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-	struct drm_hdmi_context *ctx;
-
-	if (!hdmi_ctx) {
-		DRM_ERROR("hdmi context not initialized.\n");
-		return -EFAULT;
-	}
-
-	if (!mixer_ctx) {
-		DRM_ERROR("mixer context not initialized.\n");
-		return -EFAULT;
-	}
-
-	ctx = get_ctx_from_subdrv(subdrv);
-
-	if (!ctx) {
-		DRM_ERROR("no drm hdmi context.\n");
-		return -EFAULT;
-	}
-
-	ctx->hdmi_ctx = hdmi_ctx;
-	ctx->mixer_ctx = mixer_ctx;
-
-	return 0;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-	struct drm_hdmi_context *ctx;
-	struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-
-	ctx = get_ctx_from_subdrv(subdrv);
-
-	if (mixer_ops->iommu_on)
-		mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
-static int exynos_drm_hdmi_probe(struct platform_device *pdev)
-{
-	struct device *dev = &pdev->dev;
-	struct exynos_drm_subdrv *subdrv;
-	struct drm_hdmi_context *ctx;
-
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
-		return -ENOMEM;
-
-	hdmi_manager.ctx = ctx;
-
-	subdrv = &ctx->subdrv;
-
-	subdrv->dev = dev;
-	subdrv->manager = &hdmi_manager;
-	subdrv->probe = hdmi_subdrv_probe;
-	subdrv->remove = hdmi_subdrv_remove;
-
-	platform_set_drvdata(pdev, subdrv);
-
-	exynos_drm_subdrv_register(subdrv);
-
-	return 0;
-}
-
-static int exynos_drm_hdmi_remove(struct platform_device *pdev)
-{
-	struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-
-	exynos_drm_subdrv_unregister(&ctx->subdrv);
-
-	return 0;
-}
-
-struct platform_driver exynos_drm_common_hdmi_driver = {
-	.probe		= exynos_drm_hdmi_probe,
-	.remove		= exynos_drm_hdmi_remove,
-	.driver		= {
-		.name	= "exynos-drm-hdmi",
-		.owner	= THIS_MODULE,
-	},
-};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
index 923239b..37059ea 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
@@ -19,10 +19,12 @@
  * exynos hdmi common context structure.
  *
  * @drm_dev: pointer to drm_device.
+ * @pipe: pipe for mixer
  * @ctx: pointer to the context of specific device driver.
  *	this context should be hdmi_context or mixer_context.
  */
 struct exynos_drm_hdmi_context {
+	int			pipe;
 	void			*ctx;
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index cff3aed..e0db2b3 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -13,7 +13,7 @@
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
@@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 			overlay->crtc_x, overlay->crtc_y,
 			overlay->crtc_width, overlay->crtc_height);
 
-	exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+	exynos_drm_crtc_plane_mode_set(crtc, overlay);
 
 	return 0;
 }
@@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane)
 	struct exynos_plane *exynos_plane = to_exynos_plane(plane);
 	struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-	exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-			exynos_drm_encoder_plane_commit);
+	exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
 }
 
 void exynos_plane_dpms(struct drm_plane *plane, int mode)
@@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
 		if (exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-				exynos_drm_encoder_plane_enable);
-
+		exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
 		exynos_plane->enabled = true;
 	} else {
 		if (!exynos_plane->enabled)
 			return;
 
-		exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-				exynos_drm_encoder_plane_disable);
-
+		exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
 		exynos_plane->enabled = false;
 	}
 }
-- 
1.8.4

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

* [PATCH v2 13/26] drm/exynos: hdmi: remove the i2c drivers and use devtree
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (11 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 14/26] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

From: Daniel Kurtz <djkurtz@chromium.org>

The i2c client was previously being passed into the hdmi driver via a
dedicated i2c driver, and then a global variable. This patch removes all
of that and just uses the device tree to get the i2c_client. This patch
also properly references the client so we don't lose it before we're
done with it.

Signed-off-by: Daniel Kurtz <djkurtz@chromium.org>
Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Change include to linux/i2c.h instead of linux/of_i2c.h

 drivers/gpu/drm/exynos/Makefile         |  1 -
 drivers/gpu/drm/exynos/exynos_ddc.c     | 63 --------------------------------
 drivers/gpu/drm/exynos/exynos_hdmi.c    | 59 ++++++++++++++----------------
 drivers/gpu/drm/exynos/exynos_hdmi.h    | 23 ------------
 drivers/gpu/drm/exynos/exynos_hdmiphy.c | 65 ---------------------------------
 5 files changed, 27 insertions(+), 184 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_ddc.c
 delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmi.h
 delete mode 100644 drivers/gpu/drm/exynos/exynos_hdmiphy.c

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 639b49e..819961a 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,7 +12,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
-					   exynos_ddc.o exynos_hdmiphy.o \
 					   exynos_drm_hdmi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
diff --git a/drivers/gpu/drm/exynos/exynos_ddc.c b/drivers/gpu/drm/exynos/exynos_ddc.c
deleted file mode 100644
index 6a8c84e..0000000
--- a/drivers/gpu/drm/exynos/exynos_ddc.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *	Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/of.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_hdmi.h"
-
-static int s5p_ddc_probe(struct i2c_client *client,
-			const struct i2c_device_id *dev_id)
-{
-	hdmi_attach_ddc_client(client);
-
-	dev_info(&client->adapter->dev,
-		"attached %s into i2c adapter successfully\n",
-		client->name);
-
-	return 0;
-}
-
-static int s5p_ddc_remove(struct i2c_client *client)
-{
-	dev_info(&client->adapter->dev,
-		"detached %s from i2c adapter successfully\n",
-		client->name);
-
-	return 0;
-}
-
-static struct of_device_id hdmiddc_match_types[] = {
-	{
-		.compatible = "samsung,exynos5-hdmiddc",
-	}, {
-		.compatible = "samsung,exynos4210-hdmiddc",
-	}, {
-		/* end node */
-	}
-};
-
-struct i2c_driver ddc_driver = {
-	.driver = {
-		.name = "exynos-hdmiddc",
-		.owner = THIS_MODULE,
-		.of_match_table = hdmiddc_match_types,
-	},
-	.probe		= s5p_ddc_probe,
-	.remove		= s5p_ddc_remove,
-	.command		= NULL,
-};
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 0b85c48..d00f783 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -33,6 +33,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/i2c.h>
 #include <linux/of_gpio.h>
 
 #include <drm/exynos_drm.h>
@@ -40,8 +41,6 @@
 #include "exynos_drm_drv.h"
 #include "exynos_drm_hdmi.h"
 
-#include "exynos_hdmi.h"
-
 #include <linux/gpio.h>
 #include <media/s5p_hdmi.h>
 
@@ -1855,20 +1854,6 @@ fail:
 	return -ENODEV;
 }
 
-static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
-
-void hdmi_attach_ddc_client(struct i2c_client *ddc)
-{
-	if (ddc)
-		hdmi_ddc = ddc;
-}
-
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
-{
-	if (hdmiphy)
-		hdmi_hdmiphy = hdmiphy;
-}
-
 static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
 					(struct device *dev)
 {
@@ -1913,6 +1898,7 @@ static int hdmi_probe(struct platform_device *pdev)
 	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
 	const struct of_device_id *match;
+	struct device_node *ddc_node, *phy_node;
 	int ret;
 
 	 if (!dev->of_node)
@@ -1963,21 +1949,30 @@ static int hdmi_probe(struct platform_device *pdev)
 	}
 
 	/* DDC i2c driver */
-	if (i2c_add_driver(&ddc_driver)) {
-		DRM_ERROR("failed to register ddc i2c driver\n");
-		return -ENOENT;
+	ddc_node = of_find_node_by_name(NULL, "hdmiddc");
+	if (!ddc_node) {
+		DRM_ERROR("Failed to find ddc node in device tree\n");
+		return -ENODEV;
+	}
+	hdata->ddc_port = of_find_i2c_device_by_node(ddc_node);
+	if (!hdata->ddc_port) {
+		DRM_ERROR("Failed to get ddc i2c client by node\n");
+		return -ENODEV;
 	}
-
-	hdata->ddc_port = hdmi_ddc;
 
 	/* hdmiphy i2c driver */
-	if (i2c_add_driver(&hdmiphy_driver)) {
-		DRM_ERROR("failed to register hdmiphy i2c driver\n");
-		ret = -ENOENT;
+	phy_node = of_find_node_by_name(NULL, "hdmiphy");
+	if (!phy_node) {
+		DRM_ERROR("Failed to find hdmiphy node in device tree\n");
+		ret = -ENODEV;
+		goto err_ddc;
+	}
+	hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
+	if (!hdata->hdmiphy_port) {
+		DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
+		ret = -ENODEV;
 		goto err_ddc;
 	}
-
-	hdata->hdmiphy_port = hdmi_hdmiphy;
 
 	hdata->irq = gpio_to_irq(hdata->hpd_gpio);
 	if (hdata->irq < 0) {
@@ -2008,22 +2003,22 @@ static int hdmi_probe(struct platform_device *pdev)
 	return 0;
 
 err_hdmiphy:
-	i2c_del_driver(&hdmiphy_driver);
+	put_device(&hdata->hdmiphy_port->dev);
 err_ddc:
-	i2c_del_driver(&ddc_driver);
+	put_device(&hdata->ddc_port->dev);
 	return ret;
 }
 
 static int hdmi_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
+	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
+	struct hdmi_context *hdata = ctx->ctx;
 
 	pm_runtime_disable(dev);
 
-	/* hdmiphy i2c driver */
-	i2c_del_driver(&hdmiphy_driver);
-	/* DDC i2c driver */
-	i2c_del_driver(&ddc_driver);
+	put_device(&hdata->hdmiphy_port->dev);
+	put_device(&hdata->ddc_port->dev);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.h b/drivers/gpu/drm/exynos/exynos_hdmi.h
deleted file mode 100644
index 0ddf395..0000000
--- a/drivers/gpu/drm/exynos/exynos_hdmi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authors:
- *	Inki Dae <inki.dae@samsung.com>
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_HDMI_H_
-#define _EXYNOS_HDMI_H_
-
-void hdmi_attach_ddc_client(struct i2c_client *ddc);
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy);
-
-extern struct i2c_driver hdmiphy_driver;
-extern struct i2c_driver ddc_driver;
-
-#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmiphy.c b/drivers/gpu/drm/exynos/exynos_hdmiphy.c
deleted file mode 100644
index 59abb14..0000000
--- a/drivers/gpu/drm/exynos/exynos_hdmiphy.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *	Seung-Woo Kim <sw0312.kim@samsung.com>
- *	Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/i2c.h>
-#include <linux/of.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_hdmi.h"
-
-
-static int hdmiphy_probe(struct i2c_client *client,
-	const struct i2c_device_id *id)
-{
-	hdmi_attach_hdmiphy_client(client);
-
-	dev_info(&client->adapter->dev, "attached s5p_hdmiphy "
-		"into i2c adapter successfully\n");
-
-	return 0;
-}
-
-static int hdmiphy_remove(struct i2c_client *client)
-{
-	dev_info(&client->adapter->dev, "detached s5p_hdmiphy "
-		"from i2c adapter successfully\n");
-
-	return 0;
-}
-
-static struct of_device_id hdmiphy_match_types[] = {
-	{
-		.compatible = "samsung,exynos5-hdmiphy",
-	}, {
-		.compatible = "samsung,exynos4210-hdmiphy",
-	}, {
-		.compatible = "samsung,exynos4212-hdmiphy",
-	}, {
-		/* end node */
-	}
-};
-
-struct i2c_driver hdmiphy_driver = {
-	.driver = {
-		.name	= "exynos-hdmiphy",
-		.owner	= THIS_MODULE,
-		.of_match_table = hdmiphy_match_types,
-	},
-	.probe		= hdmiphy_probe,
-	.remove		= hdmiphy_remove,
-	.command		= NULL,
-};
-EXPORT_SYMBOL(hdmiphy_driver);
-- 
1.8.4

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

* [PATCH v2 14/26] drm/exynos: Remove exynos_drm_hdmi shim
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (12 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 13/26] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 15/26] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch trims exynos_drm_hdmi out of the driver. The reason it
existed in the first place was to make up for the mixture of
display/overlay/manager ops being spread across hdmi and mixer. With
that code now rationalized, mixer and hdmi map directly to
exynos_drm_crtc and exynos_drm_encoder, respectively. Since there is a
1:1 mapping, we no longer need this layer.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- hdmi/mixer ops now take display/manager instead of context

 drivers/gpu/drm/exynos/Makefile          |   3 +-
 drivers/gpu/drm/exynos/exynos_drm_drv.c  |  13 --
 drivers/gpu/drm/exynos/exynos_drm_hdmi.h |  69 -----------
 drivers/gpu/drm/exynos/exynos_hdmi.c     | 162 +++++++++++++++---------
 drivers/gpu/drm/exynos/exynos_mixer.c    | 204 +++++++++++++++----------------
 drivers/gpu/drm/exynos/exynos_mixer.h    |  20 +++
 6 files changed, 222 insertions(+), 249 deletions(-)
 delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_mixer.h

diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 819961a..afbe499 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -11,8 +11,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o \
-					   exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_IPP)	+= exynos_drm_ipp.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 250903c..4b265bf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -329,13 +329,6 @@ static int __init exynos_drm_init(void)
 	ret = platform_driver_register(&mixer_driver);
 	if (ret < 0)
 		goto out_mixer;
-	ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-	if (ret < 0)
-		goto out_common_hdmi;
-
-	ret = exynos_platform_device_hdmi_register();
-	if (ret < 0)
-		goto out_common_hdmi_dev;
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_VIDI
@@ -428,10 +421,6 @@ out_vidi:
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-	exynos_platform_device_hdmi_unregister();
-out_common_hdmi_dev:
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-out_common_hdmi:
 	platform_driver_unregister(&mixer_driver);
 out_mixer:
 	platform_driver_unregister(&hdmi_driver);
@@ -473,8 +462,6 @@ static void __exit exynos_drm_exit(void)
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-	exynos_platform_device_hdmi_unregister();
-	platform_driver_unregister(&exynos_drm_common_hdmi_driver);
 	platform_driver_unregister(&mixer_driver);
 	platform_driver_unregister(&hdmi_driver);
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
deleted file mode 100644
index 37059ea..0000000
--- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* exynos_drm_hdmi.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authoer: Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_HDMI_H_
-#define _EXYNOS_DRM_HDMI_H_
-
-#define MIXER_WIN_NR		3
-#define MIXER_DEFAULT_WIN	0
-
-/*
- * exynos hdmi common context structure.
- *
- * @drm_dev: pointer to drm_device.
- * @pipe: pipe for mixer
- * @ctx: pointer to the context of specific device driver.
- *	this context should be hdmi_context or mixer_context.
- */
-struct exynos_drm_hdmi_context {
-	int			pipe;
-	void			*ctx;
-};
-
-struct exynos_hdmi_ops {
-	/* display */
-	int (*initialize)(void *ctx, struct drm_device *drm_dev);
-	bool (*is_connected)(void *ctx);
-	struct edid *(*get_edid)(void *ctx,
-			struct drm_connector *connector);
-	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-	void (*dpms)(void *ctx, int mode);
-
-	/* manager */
-	void (*mode_set)(void *ctx, struct drm_display_mode *mode);
-	void (*get_max_resol)(void *ctx, unsigned int *width,
-				unsigned int *height);
-	void (*commit)(void *ctx);
-};
-
-struct exynos_mixer_ops {
-	/* manager */
-	int (*initialize)(void *ctx, struct drm_device *drm_dev);
-	int (*iommu_on)(void *ctx, bool enable);
-	int (*enable_vblank)(void *ctx, int pipe);
-	void (*disable_vblank)(void *ctx);
-	void (*wait_for_vblank)(void *ctx);
-	void (*dpms)(void *ctx, int mode);
-
-	/* overlay */
-	void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
-	void (*win_commit)(void *ctx, int zpos);
-	void (*win_disable)(void *ctx, int zpos);
-
-	/* display */
-	int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-};
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops);
-#endif
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index d00f783..64c5647 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -39,14 +39,14 @@
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
+#include "exynos_mixer.h"
 
 #include <linux/gpio.h>
 #include <media/s5p_hdmi.h>
 
 #define MAX_WIDTH		1920
 #define MAX_HEIGHT		1080
-#define get_hdmi_context(dev)	platform_get_drvdata(to_platform_device(dev))
+#define get_hdmi_display(dev)	platform_get_drvdata(to_platform_device(dev))
 
 /* AVI header and aspect ratio */
 #define HDMI_AVI_VERSION		0x02
@@ -188,7 +188,6 @@ struct hdmi_context {
 	struct mutex			hdmi_mutex;
 
 	void __iomem			*regs;
-	void				*parent_ctx;
 	int				irq;
 
 	struct i2c_client		*ddc_port;
@@ -741,26 +740,28 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
 	}
 }
 
-static int hdmi_initialize(void *ctx, struct drm_device *drm_dev)
+static int hdmi_initialize(struct exynos_drm_display *display,
+			struct drm_device *drm_dev)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	hdata->drm_dev = drm_dev;
 
 	return 0;
 }
 
-static bool hdmi_is_connected(void *ctx)
+static bool hdmi_is_connected(struct exynos_drm_display *display)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	return hdata->hpd;
 }
 
-static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
+static struct edid *hdmi_get_edid(struct exynos_drm_display *display,
+			struct drm_connector *connector)
 {
 	struct edid *raw_edid;
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	if (!hdata->ddc_port)
 		return ERR_PTR(-ENODEV);
@@ -799,9 +800,10 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
 	return -EINVAL;
 }
 
-static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
+static int hdmi_check_mode(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 	int ret;
 
 	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
@@ -809,12 +811,62 @@ static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
 		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
 		false, mode->clock * 1000);
 
+	ret = mixer_check_mode(mode);
+	if (ret)
+		return ret;
+
 	ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
 	if (ret < 0)
 		return ret;
 	return 0;
 }
 
+static void hdmi_mode_fixup(struct exynos_drm_display *display,
+				struct drm_connector *connector,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	struct drm_display_mode *m;
+	int mode_ok;
+
+	DRM_DEBUG_KMS("%s\n", __FILE__);
+
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	mode_ok = hdmi_check_mode(display, adjusted_mode);
+
+	/* just return if user desired mode exists. */
+	if (mode_ok == 0)
+		return;
+
+	/*
+	 * otherwise, find the most suitable mode among modes and change it
+	 * to adjusted_mode.
+	 */
+	list_for_each_entry(m, &connector->modes, head) {
+		mode_ok = hdmi_check_mode(display, m);
+
+		if (mode_ok == 0) {
+			struct drm_mode_object base;
+			struct list_head head;
+
+			DRM_INFO("desired mode doesn't exist so\n");
+			DRM_INFO("use the most suitable mode among modes.\n");
+
+			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
+				m->hdisplay, m->vdisplay, m->vrefresh);
+
+			/* preserve display mode header while copying. */
+			head = adjusted_mode->head;
+			base = adjusted_mode->base;
+			memcpy(adjusted_mode, m, sizeof(*m));
+			adjusted_mode->head = head;
+			adjusted_mode->base = base;
+			break;
+		}
+	}
+}
+
 static void hdmi_set_acr(u32 freq, u8 *acr)
 {
 	u32 n, cts;
@@ -1640,9 +1692,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
 	hdmi_set_reg(tg->tg_3d, 1, 0x0);
 }
 
-static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
+static void hdmi_mode_set(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 	struct drm_display_mode *m = mode;
 
 	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
@@ -1656,16 +1709,16 @@ static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
 		hdmi_v14_mode_set(hdata, mode);
 }
 
-static void hdmi_get_max_resol(void *ctx, unsigned int *width,
-					unsigned int *height)
+static void hdmi_get_max_resol(struct exynos_drm_display *display,
+			unsigned int *width, unsigned int *height)
 {
 	*width = MAX_WIDTH;
 	*height = MAX_HEIGHT;
 }
 
-static void hdmi_commit(void *ctx)
+static void hdmi_commit(struct exynos_drm_display *display)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	mutex_lock(&hdata->hdmi_mutex);
 	if (!hdata->powered) {
@@ -1677,8 +1730,9 @@ static void hdmi_commit(void *ctx)
 	hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweron(struct hdmi_context *hdata)
+static void hdmi_poweron(struct exynos_drm_display *display)
 {
+	struct hdmi_context *hdata = display->ctx;
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -1699,11 +1753,12 @@ static void hdmi_poweron(struct hdmi_context *hdata)
 	clk_prepare_enable(res->sclk_hdmi);
 
 	hdmiphy_poweron(hdata);
-	hdmi_commit(hdata);
+	hdmi_commit(display);
 }
 
-static void hdmi_poweroff(struct hdmi_context *hdata)
+static void hdmi_poweroff(struct exynos_drm_display *display)
 {
+	struct hdmi_context *hdata = display->ctx;
 	struct hdmi_resources *res = &hdata->res;
 
 	mutex_lock(&hdata->hdmi_mutex);
@@ -1731,9 +1786,9 @@ out:
 	mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_dpms(void *ctx, int mode)
+static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
-	struct hdmi_context *hdata = ctx;
+	struct hdmi_context *hdata = display->ctx;
 
 	DRM_DEBUG_KMS("mode %d\n", mode);
 
@@ -1754,24 +1809,26 @@ static void hdmi_dpms(void *ctx, int mode)
 	}
 }
 
-static struct exynos_hdmi_ops hdmi_ops = {
-	/* display */
+static struct exynos_drm_display_ops hdmi_display_ops = {
 	.initialize	= hdmi_initialize,
 	.is_connected	= hdmi_is_connected,
+	.get_max_resol	= hdmi_get_max_resol,
 	.get_edid	= hdmi_get_edid,
 	.check_mode	= hdmi_check_mode,
-	.dpms		= hdmi_dpms,
-
-	/* manager */
+	.mode_fixup	= hdmi_mode_fixup,
 	.mode_set	= hdmi_mode_set,
-	.get_max_resol	= hdmi_get_max_resol,
+	.dpms		= hdmi_dpms,
 	.commit		= hdmi_commit,
 };
 
+static struct exynos_drm_display hdmi_display = {
+	.type = EXYNOS_DISPLAY_TYPE_HDMI,
+	.ops = &hdmi_display_ops,
+};
+
 static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 {
-	struct exynos_drm_hdmi_context *ctx = arg;
-	struct hdmi_context *hdata = ctx->ctx;
+	struct hdmi_context *hdata = arg;
 
 	mutex_lock(&hdata->hdmi_mutex);
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
@@ -1893,7 +1950,6 @@ static struct of_device_id hdmi_match_types[] = {
 static int hdmi_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
 	struct hdmi_context *hdata;
 	struct s5p_hdmi_platform_data *pdata;
 	struct resource *res;
@@ -1908,20 +1964,13 @@ static int hdmi_probe(struct platform_device *pdev)
 	if (!pdata)
 		return -EINVAL;
 
-	drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
-	if (!drm_hdmi_ctx)
-		return -ENOMEM;
-
 	hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
 	if (!hdata)
 		return -ENOMEM;
 
 	mutex_init(&hdata->hdmi_mutex);
 
-	drm_hdmi_ctx->ctx = (void *)hdata;
-	hdata->parent_ctx = (void *)drm_hdmi_ctx;
-
-	platform_set_drvdata(pdev, drm_hdmi_ctx);
+	platform_set_drvdata(pdev, &hdmi_display);
 
 	match = of_match_node(hdmi_match_types, dev->of_node);
 	if (!match)
@@ -1986,17 +2035,14 @@ static int hdmi_probe(struct platform_device *pdev)
 	ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
 			hdmi_irq_thread, IRQF_TRIGGER_RISING |
 			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-			"hdmi", drm_hdmi_ctx);
+			"hdmi", hdata);
 	if (ret) {
 		DRM_ERROR("failed to register hdmi interrupt\n");
 		goto err_hdmiphy;
 	}
 
-	/* Attach HDMI Driver to common hdmi. */
-	exynos_hdmi_drv_attach(drm_hdmi_ctx);
-
-	/* register specific callbacks to common hdmi. */
-	exynos_hdmi_ops_register(&hdmi_ops);
+	hdmi_display.ctx = hdata;
+	exynos_drm_display_register(&hdmi_display);
 
 	pm_runtime_enable(dev);
 
@@ -2012,8 +2058,8 @@ err_ddc:
 static int hdmi_remove(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	pm_runtime_disable(dev);
 
@@ -2026,8 +2072,8 @@ static int hdmi_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int hdmi_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	disable_irq(hdata->irq);
 
@@ -2040,15 +2086,15 @@ static int hdmi_suspend(struct device *dev)
 		return 0;
 	}
 
-	hdmi_poweroff(hdata);
+	hdmi_poweroff(display);
 
 	return 0;
 }
 
 static int hdmi_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
+	struct hdmi_context *hdata = display->ctx;
 
 	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
 
@@ -2059,7 +2105,7 @@ static int hdmi_resume(struct device *dev)
 		return 0;
 	}
 
-	hdmi_poweron(hdata);
+	hdmi_poweron(display);
 
 	return 0;
 }
@@ -2068,20 +2114,18 @@ static int hdmi_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int hdmi_runtime_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
 
-	hdmi_poweroff(hdata);
+	hdmi_poweroff(display);
 
 	return 0;
 }
 
 static int hdmi_runtime_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-	struct hdmi_context *hdata = ctx->ctx;
+	struct exynos_drm_display *display = get_hdmi_display(dev);
 
-	hdmi_poweron(hdata);
+	hdmi_poweron(display);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 60935c4..39aed3e 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -36,10 +36,13 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_hdmi.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_mixer.h"
 
-#define get_mixer_context(dev)	platform_get_drvdata(to_platform_device(dev))
+#define get_mixer_manager(dev)	platform_get_drvdata(to_platform_device(dev))
+
+#define MIXER_WIN_NR		3
+#define MIXER_DEFAULT_WIN	0
 
 struct hdmi_win_data {
 	dma_addr_t		dma_addr;
@@ -94,7 +97,6 @@ struct mixer_context {
 	struct mixer_resources	mixer_res;
 	struct hdmi_win_data	win_data[MIXER_WIN_NR];
 	enum mixer_version_id	mxr_ver;
-	void			*parent_ctx;
 	wait_queue_head_t	wait_vsync_queue;
 	atomic_t		wait_vsync_event;
 };
@@ -685,35 +687,37 @@ static void mixer_win_reset(struct mixer_context *ctx)
 	spin_unlock_irqrestore(&res->reg_slock, flags);
 }
 
-static int mixer_initialize(void *ctx, struct drm_device *drm_dev)
+static int mixer_initialize(struct exynos_drm_manager *mgr,
+			struct drm_device *drm_dev, int pipe)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	mixer_ctx->drm_dev = drm_dev;
+	mixer_ctx->pipe = pipe;
 
-	return 0;
+	if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
+		return 0;
+
+	return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static int mixer_iommu_on(void *ctx, bool enable)
+static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mdata = ctx;
-
-	if (is_drm_iommu_supported(mdata->drm_dev)) {
-		if (enable)
-			return drm_iommu_attach_device(mdata->drm_dev,
-					mdata->dev);
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
-		drm_iommu_detach_device(mdata->drm_dev, mdata->dev);
-	}
-	return 0;
+	if (is_drm_iommu_supported(mixer_ctx->drm_dev))
+		drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
 }
 
-static int mixer_enable_vblank(void *ctx, int pipe)
+static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
-	mixer_ctx->pipe = pipe;
+	if (!mixer_ctx->powered) {
+		mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
+		return 0;
+	}
 
 	/* enable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
@@ -722,19 +726,19 @@ static int mixer_enable_vblank(void *ctx, int pipe)
 	return 0;
 }
 
-static void mixer_disable_vblank(void *ctx)
+static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
 
 	/* disable vsync interrupt */
 	mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(void *ctx,
-			      struct exynos_drm_overlay *overlay)
+static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
+			struct exynos_drm_overlay *overlay)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int win;
 
@@ -783,9 +787,10 @@ static void mixer_win_mode_set(void *ctx,
 	win_data->scan_flags = overlay->scan_flag;
 }
 
-static void mixer_win_commit(void *ctx, int win)
+static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
+	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
 	DRM_DEBUG_KMS("win: %d\n", win);
 
@@ -804,10 +809,11 @@ static void mixer_win_commit(void *ctx, int win)
 	mixer_ctx->win_data[win].enabled = true;
 }
 
-static void mixer_win_disable(void *ctx, int win)
+static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 	struct mixer_resources *res = &mixer_ctx->mixer_res;
+	int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 	unsigned long flags;
 
 	DRM_DEBUG_KMS("win: %d\n", win);
@@ -831,32 +837,9 @@ static void mixer_win_disable(void *ctx, int win)
 	mixer_ctx->win_data[win].enabled = false;
 }
 
-static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
+static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-	struct mixer_context *mixer_ctx = ctx;
-	u32 w, h;
-
-	w = mode->hdisplay;
-	h = mode->vdisplay;
-
-	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
-		mode->hdisplay, mode->vdisplay, mode->vrefresh,
-		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
-
-	if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
-		mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
-		return 0;
-
-	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
-		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
-		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
-		return 0;
-
-	return -EINVAL;
-}
-static void mixer_wait_for_vblank(void *ctx)
-{
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	mutex_lock(&mixer_ctx->mixer_mutex);
 	if (!mixer_ctx->powered) {
@@ -877,21 +860,23 @@ static void mixer_wait_for_vblank(void *ctx)
 		DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-static void mixer_window_suspend(struct mixer_context *ctx)
+static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int i;
 
 	for (i = 0; i < MIXER_WIN_NR; i++) {
 		win_data = &ctx->win_data[i];
 		win_data->resume = win_data->enabled;
-		mixer_win_disable(ctx, i);
+		mixer_win_disable(mgr, i);
 	}
-	mixer_wait_for_vblank(ctx);
+	mixer_wait_for_vblank(mgr);
 }
 
-static void mixer_window_resume(struct mixer_context *ctx)
+static void mixer_window_resume(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct hdmi_win_data *win_data;
 	int i;
 
@@ -900,12 +885,13 @@ static void mixer_window_resume(struct mixer_context *ctx)
 		win_data->enabled = win_data->resume;
 		win_data->resume = false;
 		if (win_data->enabled)
-			mixer_win_commit(ctx, i);
+			mixer_win_commit(mgr, i);
 	}
 }
 
-static void mixer_poweron(struct mixer_context *ctx)
+static void mixer_poweron(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -925,11 +911,12 @@ static void mixer_poweron(struct mixer_context *ctx)
 	mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
 	mixer_win_reset(ctx);
 
-	mixer_window_resume(ctx);
+	mixer_window_resume(mgr);
 }
 
-static void mixer_poweroff(struct mixer_context *ctx)
+static void mixer_poweroff(struct exynos_drm_manager *mgr)
 {
+	struct mixer_context *ctx = mgr->ctx;
 	struct mixer_resources *res = &ctx->mixer_res;
 
 	mutex_lock(&ctx->mixer_mutex);
@@ -937,7 +924,7 @@ static void mixer_poweroff(struct mixer_context *ctx)
 		goto out;
 	mutex_unlock(&ctx->mixer_mutex);
 
-	mixer_window_suspend(ctx);
+	mixer_window_suspend(mgr);
 
 	ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
@@ -954,9 +941,9 @@ out:
 	mutex_unlock(&ctx->mixer_mutex);
 }
 
-static void mixer_dpms(void *ctx, int mode)
+static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct mixer_context *mixer_ctx = ctx;
+	struct mixer_context *mixer_ctx = mgr->ctx;
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
@@ -975,20 +962,41 @@ static void mixer_dpms(void *ctx, int mode)
 	}
 }
 
-static struct exynos_mixer_ops mixer_ops = {
-	/* manager */
+/* Only valid for Mixer version 16.0.33.0 */
+int mixer_check_mode(struct drm_display_mode *mode)
+{
+	u32 w, h;
+
+	w = mode->hdisplay;
+	h = mode->vdisplay;
+
+	DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
+		mode->hdisplay, mode->vdisplay, mode->vrefresh,
+		(mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+	if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
+		(w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
+		(w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
+		return 0;
+
+	return -EINVAL;
+}
+
+static struct exynos_drm_manager_ops mixer_manager_ops = {
 	.initialize		= mixer_initialize,
-	.iommu_on		= mixer_iommu_on,
+	.remove			= mixer_mgr_remove,
+	.dpms			= mixer_dpms,
 	.enable_vblank		= mixer_enable_vblank,
 	.disable_vblank		= mixer_disable_vblank,
 	.wait_for_vblank	= mixer_wait_for_vblank,
-	.dpms			= mixer_dpms,
 	.win_mode_set		= mixer_win_mode_set,
 	.win_commit		= mixer_win_commit,
 	.win_disable		= mixer_win_disable,
+};
 
-	/* display */
-	.check_mode		= mixer_check_mode,
+static struct exynos_drm_manager mixer_manager = {
+	.type			= EXYNOS_DISPLAY_TYPE_HDMI,
+	.ops			= &mixer_manager_ops,
 };
 
 static irqreturn_t mixer_irq_handler(int irq, void *arg)
@@ -1044,10 +1052,9 @@ out:
 	return IRQ_HANDLED;
 }
 
-static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
+static int mixer_resources_init(struct mixer_context *mixer_ctx,
 				struct platform_device *pdev)
 {
-	struct mixer_context *mixer_ctx = ctx->ctx;
 	struct device *dev = &pdev->dev;
 	struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
 	struct resource *res;
@@ -1096,10 +1103,9 @@ static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
 	return 0;
 }
 
-static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
+static int vp_resources_init(struct mixer_context *mixer_ctx,
 			     struct platform_device *pdev)
 {
-	struct mixer_context *mixer_ctx = ctx->ctx;
 	struct device *dev = &pdev->dev;
 	struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
 	struct resource *res;
@@ -1184,21 +1190,17 @@ static struct of_device_id mixer_match_types[] = {
 static int mixer_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx;
 	struct mixer_context *ctx;
 	struct mixer_drv_data *drv;
 	int ret;
 
 	dev_info(dev, "probe start\n");
 
-	drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
-								GFP_KERNEL);
-	if (!drm_hdmi_ctx)
-		return -ENOMEM;
-
-	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-	if (!ctx)
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		DRM_ERROR("failed to alloc mixer context.\n");
 		return -ENOMEM;
+	}
 
 	mutex_init(&ctx->mixer_mutex);
 
@@ -1211,18 +1213,14 @@ static int mixer_probe(struct platform_device *pdev)
 			platform_get_device_id(pdev)->driver_data;
 	}
 
-	ctx->dev = dev;
-	ctx->parent_ctx = (void *)drm_hdmi_ctx;
-	drm_hdmi_ctx->ctx = (void *)ctx;
+	ctx->dev = &pdev->dev;
 	ctx->vp_enabled = drv->is_vp_enabled;
 	ctx->mxr_ver = drv->version;
 	DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
-	platform_set_drvdata(pdev, drm_hdmi_ctx);
-
 	/* acquire resources: regs, irqs, clocks */
-	ret = mixer_resources_init(drm_hdmi_ctx, pdev);
+	ret = mixer_resources_init(ctx, pdev);
 	if (ret) {
 		DRM_ERROR("mixer_resources_init failed\n");
 		goto fail;
@@ -1230,18 +1228,16 @@ static int mixer_probe(struct platform_device *pdev)
 
 	if (ctx->vp_enabled) {
 		/* acquire vp resources: regs, irqs, clocks */
-		ret = vp_resources_init(drm_hdmi_ctx, pdev);
+		ret = vp_resources_init(ctx, pdev);
 		if (ret) {
 			DRM_ERROR("vp_resources_init failed\n");
 			goto fail;
 		}
 	}
 
-	/* attach mixer driver to common hdmi. */
-	exynos_mixer_drv_attach(drm_hdmi_ctx);
-
-	/* register specific callback point to common hdmi. */
-	exynos_mixer_ops_register(&mixer_ops);
+	mixer_manager.ctx = ctx;
+	platform_set_drvdata(pdev, &mixer_manager);
+	exynos_drm_manager_register(&mixer_manager);
 
 	pm_runtime_enable(dev);
 
@@ -1265,30 +1261,28 @@ static int mixer_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int mixer_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
 	if (pm_runtime_suspended(dev)) {
 		DRM_DEBUG_KMS("Already suspended\n");
 		return 0;
 	}
 
-	mixer_poweroff(ctx);
+	mixer_poweroff(mgr);
 
 	return 0;
 }
 
 static int mixer_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
 	if (!pm_runtime_suspended(dev)) {
 		DRM_DEBUG_KMS("Already resumed\n");
 		return 0;
 	}
 
-	mixer_poweron(ctx);
+	mixer_poweron(mgr);
 
 	return 0;
 }
@@ -1297,20 +1291,18 @@ static int mixer_resume(struct device *dev)
 #ifdef CONFIG_PM_RUNTIME
 static int mixer_runtime_suspend(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
-	mixer_poweroff(ctx);
+	mixer_poweroff(mgr);
 
 	return 0;
 }
 
 static int mixer_runtime_resume(struct device *dev)
 {
-	struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-	struct mixer_context *ctx = drm_hdmi_ctx->ctx;
+	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
 
-	mixer_poweron(ctx);
+	mixer_poweron(mgr);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
new file mode 100644
index 0000000..3811e41
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_mixer.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EXYNOS_MIXER_H_
+#define _EXYNOS_MIXER_H_
+
+/* This function returns 0 if the given timing is valid for the mixer */
+int mixer_check_mode(struct drm_display_mode *mode);
+
+#endif
-- 
1.8.4

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

* [PATCH v2 15/26] drm/exynos: Use drm_mode_copy to copy modes
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (13 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 14/26] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 16/26] drm/exynos: Disable unused crtc planes from crtc Sean Paul
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch changes the manual copying of mode to adjusted_mode in
mode_fixup to use drm_mode_copy instead of handling things manually.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_hdmi.c | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 64c5647..afc83c9 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -847,21 +847,13 @@ static void hdmi_mode_fixup(struct exynos_drm_display *display,
 		mode_ok = hdmi_check_mode(display, m);
 
 		if (mode_ok == 0) {
-			struct drm_mode_object base;
-			struct list_head head;
-
 			DRM_INFO("desired mode doesn't exist so\n");
 			DRM_INFO("use the most suitable mode among modes.\n");
 
 			DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
 				m->hdisplay, m->vdisplay, m->vrefresh);
 
-			/* preserve display mode header while copying. */
-			head = adjusted_mode->head;
-			base = adjusted_mode->base;
-			memcpy(adjusted_mode, m, sizeof(*m));
-			adjusted_mode->head = head;
-			adjusted_mode->base = base;
+			drm_mode_copy(adjusted_mode, m);
 			break;
 		}
 	}
-- 
1.8.4

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

* [PATCH v2 16/26] drm/exynos: Disable unused crtc planes from crtc
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (14 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 15/26] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 17/26] drm/exynos: Add mode_set manager operation Sean Paul
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch moves the code which disables unused crtc planes from the
encoder to the crtc. Since there is a 1:1 encoder/crtc mapping in
exynos, the only valid crtc change the pre-existing code could catch is
disconnecting an active crtc from the encoder. Thus it is functionally
equivalent to just disable all planes attached to a crtc when the crtc
is disabled.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_crtc.c    | 13 +++++-
 drivers/gpu/drm/exynos/exynos_drm_encoder.c | 65 ++---------------------------
 2 files changed, 15 insertions(+), 63 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 347d62d..d019385 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -176,10 +176,19 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 
 static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
 {
-	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct drm_plane *plane;
+	int ret;
 
-	exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
 	exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+	list_for_each_entry(plane, &crtc->dev->mode_config.plane_list, head) {
+		if (plane->crtc != crtc)
+			continue;
+
+		ret = plane->funcs->disable_plane(plane);
+		if (ret)
+			DRM_ERROR("Failed to disable plane %d\n", ret);
+	}
 }
 
 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index d4ae664..bfa2f17 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -29,7 +29,6 @@
  * @display: the display structure that maps to this encoder
  */
 struct exynos_drm_encoder {
-	struct drm_crtc			*old_crtc;
 	struct drm_encoder		drm_encoder;
 	struct exynos_drm_display	*display;
 };
@@ -67,71 +66,15 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 	return true;
 }
 
-static void disable_plane_to_crtc(struct drm_device *dev,
-						struct drm_crtc *old_crtc,
-						struct drm_crtc *new_crtc)
-{
-	struct drm_plane *plane;
-
-	/*
-	 * if old_crtc isn't same as encoder->crtc then it means that
-	 * user changed crtc id to another one so the plane to old_crtc
-	 * should be disabled and plane->crtc should be set to new_crtc
-	 * (encoder->crtc)
-	 */
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->crtc == old_crtc) {
-			/*
-			 * do not change below call order.
-			 *
-			 * plane->funcs->disable_plane call checks
-			 * if encoder->crtc is same as plane->crtc and if same
-			 * then manager_ops->win_disable callback will be called
-			 * to diasble current hw overlay so plane->crtc should
-			 * have new_crtc because new_crtc was set to
-			 * encoder->crtc in advance.
-			 */
-			plane->crtc = new_crtc;
-			plane->funcs->disable_plane(plane);
-		}
-	}
-}
-
 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
 					 struct drm_display_mode *mode,
 					 struct drm_display_mode *adjusted_mode)
 {
-	struct drm_device *dev = encoder->dev;
-	struct drm_connector *connector;
-	struct exynos_drm_display *display;
-
-	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-		if (connector->encoder == encoder) {
-			struct exynos_drm_encoder *exynos_encoder;
-
-			exynos_encoder = to_exynos_encoder(encoder);
-
-			if (exynos_encoder->old_crtc != encoder->crtc &&
-					exynos_encoder->old_crtc) {
-
-				/*
-				 * disable a plane to old crtc and change
-				 * crtc of the plane to new one.
-				 */
-				disable_plane_to_crtc(dev,
-						exynos_encoder->old_crtc,
-						encoder->crtc);
-			}
-
-			display = exynos_encoder->display;
-
-			if (display->ops->mode_set)
-				display->ops->mode_set(display,
-							adjusted_mode);
+	struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+	struct exynos_drm_display *display = exynos_encoder->display;
 
-			exynos_encoder->old_crtc = encoder->crtc;
-		}
-	}
+	if (display->ops->mode_set)
+		display->ops->mode_set(display, adjusted_mode);
 }
 
 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
-- 
1.8.4

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

* [PATCH v2 17/26] drm/exynos: Add mode_set manager operation
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (15 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 16/26] drm/exynos: Disable unused crtc planes from crtc Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 18/26] drm/exynos: Implement mode_fixup " Sean Paul
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch adds a mode_set callback to the manager operations which
sets the crtc's current mode to the manager driver.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_crtc.c | 4 ++++
 drivers/gpu/drm/exynos/exynos_drm_drv.h  | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index d019385..a5cb104 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -115,6 +115,7 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 			  struct drm_framebuffer *old_fb)
 {
 	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
 	struct drm_plane *plane = exynos_crtc->plane;
 	unsigned int crtc_w;
 	unsigned int crtc_h;
@@ -129,6 +130,9 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
 	crtc_w = crtc->fb->width - x;
 	crtc_h = crtc->fb->height - y;
 
+	if (manager->ops->mode_set)
+		manager->ops->mode_set(manager, &crtc->mode);
+
 	ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
 				    x, y, crtc_w, crtc_h);
 	if (ret)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index dc730e5..c58a4c7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -184,6 +184,7 @@ struct exynos_drm_display {
  * @initialize: initializes the manager with drm_dev
  * @remove: cleans up the manager for removal
  * @dpms: control device power.
+ * @mode_set: set the given mode to the manager
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -200,6 +201,8 @@ struct exynos_drm_manager_ops {
 				struct drm_device *drm_dev, int pipe);
 	void (*remove)(struct exynos_drm_manager *mgr);
 	void (*dpms)(struct exynos_drm_manager *mgr, int mode);
+	void (*mode_set)(struct exynos_drm_manager *mgr,
+				const struct drm_display_mode *mode);
 	void (*commit)(struct exynos_drm_manager *mgr);
 	int (*enable_vblank)(struct exynos_drm_manager *mgr);
 	void (*disable_vblank)(struct exynos_drm_manager *mgr);
-- 
1.8.4

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

* [PATCH v2 18/26] drm/exynos: Implement mode_fixup manager operation
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (16 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 17/26] drm/exynos: Add mode_set manager operation Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 19/26] drm/exynos: Use mode_set to configure fimd Sean Paul
                   ` (7 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch adds a new manager callback for mode_fixup and pipes it
through exynos_drm_crtc.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_crtc.c | 7 ++++++-
 drivers/gpu/drm/exynos/exynos_drm_drv.h  | 4 ++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index a5cb104..100a561 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -105,7 +105,12 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
 			    const struct drm_display_mode *mode,
 			    struct drm_display_mode *adjusted_mode)
 {
-	/* drm framework doesn't check NULL */
+	struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+	struct exynos_drm_manager *manager = exynos_crtc->manager;
+
+	if (manager->ops->mode_fixup)
+		return manager->ops->mode_fixup(manager, mode, adjusted_mode);
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index c58a4c7..97bdfcc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -184,6 +184,7 @@ struct exynos_drm_display {
  * @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
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
@@ -201,6 +202,9 @@ struct exynos_drm_manager_ops {
 				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,
+				struct drm_display_mode *adjusted_mode);
 	void (*mode_set)(struct exynos_drm_manager *mgr,
 				const struct drm_display_mode *mode);
 	void (*commit)(struct exynos_drm_manager *mgr);
-- 
1.8.4

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

* [PATCH v2 19/26] drm/exynos: Use mode_set to configure fimd
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (17 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 18/26] drm/exynos: Implement mode_fixup " Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 20/26] drm/exynos: Remove unused/useless fimd_context members Sean Paul
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch uses the mode passed into mode_set to configure fimd instead
of directly using the panel from context. This will allow us to move
the exynos_drm_display implementation from fimd into the DP driver
where it belongs.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 159 ++++++++++++++++++-------------
 1 file changed, 91 insertions(+), 68 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index d2b8ccb..f69d6e5 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -104,6 +104,20 @@ struct fimd_win_data {
 	bool			resume;
 };
 
+struct fimd_mode_data {
+	unsigned		vtotal;
+	unsigned		vdisplay;
+	unsigned		vsync_len;
+	unsigned		vbpd;
+	unsigned		vfpd;
+	unsigned		htotal;
+	unsigned		hdisplay;
+	unsigned		hsync_len;
+	unsigned		hbpd;
+	unsigned		hfpd;
+	u32			clkdiv;
+};
+
 struct fimd_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
@@ -112,8 +126,8 @@ struct fimd_context {
 	struct clk			*bus_clk;
 	struct clk			*lcd_clk;
 	void __iomem			*regs;
+	struct fimd_mode_data		mode;
 	struct fimd_win_data		win_data[WINDOWS_NR];
-	unsigned int			clkdiv;
 	unsigned int			default_win;
 	unsigned long			irq_flags;
 	u32				vidcon0;
@@ -560,11 +574,56 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 	mutex_unlock(&ctx->lock);
 }
 
+static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
+		const struct drm_display_mode *mode)
+{
+	unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+	u32 clkdiv;
+
+	/* Find the clock divider value that gets us closest to ideal_clk */
+	clkdiv = DIV_ROUND_CLOSEST(clk_get_rate(ctx->lcd_clk), ideal_clk);
+
+	return (clkdiv < 0x100) ? clkdiv : 0xff;
+}
+
+static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
+		const struct drm_display_mode *mode,
+		struct drm_display_mode *adjusted_mode)
+{
+	if (adjusted_mode->vrefresh == 0)
+		adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
+
+	return true;
+}
+
+static void fimd_mode_set(struct exynos_drm_manager *mgr,
+		const struct drm_display_mode *in_mode)
+{
+	struct fimd_context *ctx = mgr->ctx;
+	struct fimd_mode_data *mode = &ctx->mode;
+	int hblank, vblank;
+
+	vblank = in_mode->crtc_vblank_end - in_mode->crtc_vblank_start;
+	mode->vtotal = in_mode->crtc_vtotal;
+	mode->vdisplay = in_mode->crtc_vdisplay;
+	mode->vsync_len = in_mode->crtc_vsync_end - in_mode->crtc_vsync_start;
+	mode->vbpd = (vblank - mode->vsync_len) / 2;
+	mode->vfpd = vblank - mode->vsync_len - mode->vbpd;
+
+	hblank = in_mode->crtc_hblank_end - in_mode->crtc_hblank_start;
+	mode->htotal = in_mode->crtc_htotal;
+	mode->hdisplay = in_mode->crtc_hdisplay;
+	mode->hsync_len = in_mode->crtc_hsync_end - in_mode->crtc_hsync_start;
+	mode->hbpd = (hblank - mode->hsync_len) / 2;
+	mode->hfpd = hblank - mode->hsync_len - mode->hbpd;
+
+	mode->clkdiv = fimd_calc_clkdiv(ctx, in_mode);
+}
+
 static void fimd_commit(struct exynos_drm_manager *mgr)
 {
 	struct fimd_context *ctx = mgr->ctx;
-	struct exynos_drm_panel_info *panel = &ctx->panel;
-	struct videomode *vm = &panel->vm;
+	struct fimd_mode_data *mode = &ctx->mode;
 	struct fimd_driver_data *driver_data;
 	u32 val;
 
@@ -572,26 +631,30 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 	if (ctx->suspended)
 		return;
 
+	/* nothing to do if we haven't set the mode yet */
+	if (mode->htotal == 0 || mode->vtotal == 0)
+		return;
+
 	/* setup polarity values from machine code. */
 	writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
 
 	/* setup vertical timing values. */
-	val = VIDTCON0_VBPD(vm->vback_porch - 1) |
-	       VIDTCON0_VFPD(vm->vfront_porch - 1) |
-	       VIDTCON0_VSPW(vm->vsync_len - 1);
+	val = VIDTCON0_VBPD(mode->vbpd - 1) |
+		VIDTCON0_VFPD(mode->vfpd - 1) |
+		VIDTCON0_VSPW(mode->vsync_len - 1);
 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
 
 	/* setup horizontal timing values.  */
-	val = VIDTCON1_HBPD(vm->hback_porch - 1) |
-	       VIDTCON1_HFPD(vm->hfront_porch - 1) |
-	       VIDTCON1_HSPW(vm->hsync_len - 1);
+	val = VIDTCON1_HBPD(mode->hbpd - 1) |
+		VIDTCON1_HFPD(mode->hfpd - 1) |
+		VIDTCON1_HSPW(mode->hsync_len - 1);
 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
 
 	/* setup horizontal and vertical display size. */
-	val = VIDTCON2_LINEVAL(vm->vactive - 1) |
-	       VIDTCON2_HOZVAL(vm->hactive - 1) |
-	       VIDTCON2_LINEVAL_E(vm->vactive - 1) |
-	       VIDTCON2_HOZVAL_E(vm->hactive - 1);
+	val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
+	       VIDTCON2_HOZVAL(mode->hdisplay - 1) |
+	       VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
+	       VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
 	writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
 
 	/* setup clock source, clock divider, enable dma. */
@@ -603,8 +666,8 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
 		val |= VIDCON0_CLKSEL_LCD;
 	}
 
-	if (ctx->clkdiv > 1)
-		val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
+	if (mode->clkdiv > 1)
+		val |= VIDCON0_CLKVAL_F(mode->clkdiv - 1) | VIDCON0_CLKDIR;
 	else
 		val &= ~VIDCON0_CLKDIR;	/* 1:1 clock */
 
@@ -697,6 +760,8 @@ 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,
 	.commit = fimd_commit,
 	.enable_vblank = fimd_enable_vblank,
 	.disable_vblank = fimd_disable_vblank,
@@ -738,56 +803,6 @@ out:
 	return IRQ_HANDLED;
 }
 
-static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
-{
-	struct videomode *vm = &ctx->panel.vm;
-	unsigned long clk;
-
-	ctx->bus_clk = devm_clk_get(dev, "fimd");
-	if (IS_ERR(ctx->bus_clk)) {
-		dev_err(dev, "failed to get bus clock\n");
-		return PTR_ERR(ctx->bus_clk);
-	}
-
-	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
-	if (IS_ERR(ctx->lcd_clk)) {
-		dev_err(dev, "failed to get lcd clock\n");
-		return PTR_ERR(ctx->lcd_clk);
-	}
-
-	clk = clk_get_rate(ctx->lcd_clk);
-	if (clk == 0) {
-		dev_err(dev, "error getting sclk_fimd clock rate\n");
-		return -EINVAL;
-	}
-
-	if (vm->pixelclock == 0) {
-		unsigned long c;
-		c = vm->hactive + vm->hback_porch + vm->hfront_porch +
-		    vm->hsync_len;
-		c *= vm->vactive + vm->vback_porch + vm->vfront_porch +
-		     vm->vsync_len;
-		vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE;
-		if (vm->pixelclock == 0) {
-			dev_err(dev, "incorrect display timings\n");
-			return -EINVAL;
-		}
-		dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n",
-			 vm->pixelclock, FIMD_DEFAULT_FRAMERATE);
-	}
-	ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock);
-	if (ctx->clkdiv > 256) {
-		dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n",
-			 ctx->clkdiv);
-		ctx->clkdiv = 256;
-	}
-	vm->pixelclock = clk / ctx->clkdiv;
-	DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock,
-		      ctx->clkdiv);
-
-	return 0;
-}
-
 static void fimd_clear_win(struct fimd_context *ctx, int win)
 {
 	writel(0, ctx->regs + WINCON(win));
@@ -925,9 +940,17 @@ static int fimd_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = fimd_configure_clocks(ctx, dev);
-	if (ret)
-		return ret;
+	ctx->bus_clk = devm_clk_get(dev, "fimd");
+	if (IS_ERR(ctx->bus_clk)) {
+		dev_err(dev, "failed to get bus clock\n");
+		return PTR_ERR(ctx->bus_clk);
+	}
+
+	ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
+	if (IS_ERR(ctx->lcd_clk)) {
+		dev_err(dev, "failed to get lcd clock\n");
+		return PTR_ERR(ctx->lcd_clk);
+	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-- 
1.8.4

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

* [PATCH v2 20/26] drm/exynos: Remove unused/useless fimd_context members
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (18 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 19/26] drm/exynos: Use mode_set to configure fimd Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 21/26] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
                   ` (5 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch removes a few fimd_context members which are either entirely
unused or unneeded.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 13 +------------
 1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index f69d6e5..61124ca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -121,8 +121,6 @@ struct fimd_mode_data {
 struct fimd_context {
 	struct device			*dev;
 	struct drm_device		*drm_dev;
-	int				irq;
-	struct drm_crtc			*crtc;
 	struct clk			*bus_clk;
 	struct clk			*lcd_clk;
 	void __iomem			*regs;
@@ -134,7 +132,6 @@ struct fimd_context {
 	u32				vidcon1;
 	bool				suspended;
 	int				pipe;
-	struct mutex			lock;
 	wait_queue_head_t		wait_vsync_queue;
 	atomic_t			wait_vsync_event;
 
@@ -547,8 +544,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 
 	DRM_DEBUG_KMS("%d\n", mode);
 
-	mutex_lock(&ctx->lock);
-
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
 		/*
@@ -570,8 +565,6 @@ static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
 		break;
 	}
-
-	mutex_unlock(&ctx->lock);
 }
 
 static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
@@ -964,9 +957,7 @@ static int fimd_probe(struct platform_device *pdev)
 		return -ENXIO;
 	}
 
-	ctx->irq = res->start;
-
-	ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
+	ret = devm_request_irq(dev, res->start, fimd_irq_handler,
 							0, "drm_fimd", ctx);
 	if (ret) {
 		dev_err(dev, "irq request failed.\n");
@@ -977,8 +968,6 @@ static int fimd_probe(struct platform_device *pdev)
 	DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
 	atomic_set(&ctx->wait_vsync_event, 0);
 
-	mutex_init(&ctx->lock);
-
 	platform_set_drvdata(pdev, &fimd_manager);
 
 	fimd_manager.ctx = ctx;
-- 
1.8.4

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

* [PATCH v2 21/26] drm/exynos: Move dp driver from video/ to drm/
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (19 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 20/26] drm/exynos: Remove unused/useless fimd_context members Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 22/26] drm/exynos: Move display implementation into dp Sean Paul
                   ` (4 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch moves the code from video/ to drm/

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 drivers/gpu/drm/exynos/Kconfig          |    7 +
 drivers/gpu/drm/exynos/Makefile         |    1 +
 drivers/gpu/drm/exynos/exynos_dp_core.c | 1213 ++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_dp_core.h |  210 ++++++
 drivers/gpu/drm/exynos/exynos_dp_reg.c  | 1245 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_dp_reg.h  |  366 +++++++++
 drivers/video/exynos/Kconfig            |    7 -
 drivers/video/exynos/Makefile           |    1 -
 drivers/video/exynos/exynos_dp_core.c   | 1213 ------------------------------
 drivers/video/exynos/exynos_dp_core.h   |  210 ------
 drivers/video/exynos/exynos_dp_reg.c    | 1245 -------------------------------
 drivers/video/exynos/exynos_dp_reg.h    |  366 ---------
 12 files changed, 3042 insertions(+), 3042 deletions(-)
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_core.h
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.c
 create mode 100644 drivers/gpu/drm/exynos/exynos_dp_reg.h
 delete mode 100644 drivers/video/exynos/exynos_dp_core.c
 delete mode 100644 drivers/video/exynos/exynos_dp_core.h
 delete mode 100644 drivers/video/exynos/exynos_dp_reg.c
 delete mode 100644 drivers/video/exynos/exynos_dp_reg.h

diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 45b6ef5..3ace74f 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -30,6 +30,13 @@ config DRM_EXYNOS_FIMD
 	help
 	  Choose this option if you want to use Exynos FIMD for DRM.
 
+config DRM_EXYNOS_DP
+	bool "EXYNOS DRM DP driver support"
+	depends on ARCH_EXYNOS
+	default n
+	help
+	  This enables support for DP device.
+
 config DRM_EXYNOS_HDMI
 	bool "Exynos DRM HDMI"
 	depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index afbe499..fc8555c 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -11,6 +11,7 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)	+= exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DP)	+= exynos_dp_core.o exynos_dp_reg.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)	+= exynos_hdmi.o exynos_mixer.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)	+= exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)	+= exynos_drm_g2d.o
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
new file mode 100644
index 0000000..089ae22
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -0,0 +1,1213 @@
+/*
+ * Samsung SoC DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+
+#include <video/exynos_dp.h>
+
+#include "exynos_dp_core.h"
+
+static int exynos_dp_init_dp(struct exynos_dp_device *dp)
+{
+	exynos_dp_reset(dp);
+
+	exynos_dp_swreset(dp);
+
+	exynos_dp_init_analog_param(dp);
+	exynos_dp_init_interrupt(dp);
+
+	/* SW defined function Normal operation */
+	exynos_dp_enable_sw_function(dp);
+
+	exynos_dp_config_interrupt(dp);
+	exynos_dp_init_analog_func(dp);
+
+	exynos_dp_init_hpd(dp);
+	exynos_dp_init_aux(dp);
+
+	return 0;
+}
+
+static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
+{
+	int timeout_loop = 0;
+
+	while (exynos_dp_get_plug_in_status(dp) != 0) {
+		timeout_loop++;
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "failed to get hpd plug status\n");
+			return -ETIMEDOUT;
+		}
+		usleep_range(10, 11);
+	}
+
+	return 0;
+}
+
+static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
+{
+	int i;
+	unsigned char sum = 0;
+
+	for (i = 0; i < EDID_BLOCK_LENGTH; i++)
+		sum = sum + edid_data[i];
+
+	return sum;
+}
+
+static int exynos_dp_read_edid(struct exynos_dp_device *dp)
+{
+	unsigned char edid[EDID_BLOCK_LENGTH * 2];
+	unsigned int extend_block = 0;
+	unsigned char sum;
+	unsigned char test_vector;
+	int retval;
+
+	/*
+	 * EDID device address is 0x50.
+	 * However, if necessary, you must have set upper address
+	 * into E-EDID in I2C device, 0x30.
+	 */
+
+	/* Read Extension Flag, Number of 128-byte EDID extension blocks */
+	retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+				EDID_EXTENSION_FLAG,
+				&extend_block);
+	if (retval)
+		return retval;
+
+	if (extend_block > 0) {
+		dev_dbg(dp->dev, "EDID data includes a single extension!\n");
+
+		/* Read EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+						EDID_HEADER_PATTERN,
+						EDID_BLOCK_LENGTH,
+						&edid[EDID_HEADER_PATTERN]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(edid);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		/* Read additional EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp,
+				I2C_EDID_DEVICE_ADDR,
+				EDID_BLOCK_LENGTH,
+				EDID_BLOCK_LENGTH,
+				&edid[EDID_BLOCK_LENGTH]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
+					&test_vector);
+		if (test_vector & DPCD_TEST_EDID_READ) {
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_EDID_CHECKSUM,
+				edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_RESPONSE,
+				DPCD_TEST_EDID_CHECKSUM_WRITE);
+		}
+	} else {
+		dev_info(dp->dev, "EDID data does not include any extensions.\n");
+
+		/* Read EDID data */
+		retval = exynos_dp_read_bytes_from_i2c(dp,
+				I2C_EDID_DEVICE_ADDR,
+				EDID_HEADER_PATTERN,
+				EDID_BLOCK_LENGTH,
+				&edid[EDID_HEADER_PATTERN]);
+		if (retval != 0) {
+			dev_err(dp->dev, "EDID Read failed!\n");
+			return -EIO;
+		}
+		sum = exynos_dp_calc_edid_check_sum(edid);
+		if (sum != 0) {
+			dev_err(dp->dev, "EDID bad checksum!\n");
+			return -EIO;
+		}
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TEST_REQUEST,
+			&test_vector);
+		if (test_vector & DPCD_TEST_EDID_READ) {
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_EDID_CHECKSUM,
+				edid[EDID_CHECKSUM]);
+			exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TEST_RESPONSE,
+				DPCD_TEST_EDID_CHECKSUM_WRITE);
+		}
+	}
+
+	dev_err(dp->dev, "EDID Read success!\n");
+	return 0;
+}
+
+static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
+{
+	u8 buf[12];
+	int i;
+	int retval;
+
+	/* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
+	retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
+				12, buf);
+	if (retval)
+		return retval;
+
+	/* Read EDID */
+	for (i = 0; i < 3; i++) {
+		retval = exynos_dp_read_edid(dp);
+		if (!retval)
+			break;
+	}
+
+	return retval;
+}
+
+static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
+						bool enable)
+{
+	u8 data;
+
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
+
+	if (enable)
+		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+			DPCD_ENHANCED_FRAME_EN |
+			DPCD_LANE_COUNT_SET(data));
+	else
+		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+			DPCD_LANE_COUNT_SET(data));
+}
+
+static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
+{
+	u8 data;
+	int retval;
+
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+	retval = DPCD_ENHANCED_FRAME_CAP(data);
+
+	return retval;
+}
+
+static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
+{
+	u8 data;
+
+	data = exynos_dp_is_enhanced_mode_available(dp);
+	exynos_dp_enable_rx_to_enhanced_mode(dp, data);
+	exynos_dp_enable_enhanced_mode(dp, data);
+}
+
+static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
+{
+	exynos_dp_set_training_pattern(dp, DP_NONE);
+
+	exynos_dp_write_byte_to_dpcd(dp,
+		DPCD_ADDR_TRAINING_PATTERN_SET,
+		DPCD_TRAINING_PATTERN_DISABLED);
+}
+
+static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
+					int pre_emphasis, int lane)
+{
+	switch (lane) {
+	case 0:
+		exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
+		break;
+	case 1:
+		exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
+		break;
+
+	case 2:
+		exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
+		break;
+
+	case 3:
+		exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
+		break;
+	}
+}
+
+static int exynos_dp_link_start(struct exynos_dp_device *dp)
+{
+	u8 buf[4];
+	int lane, lane_count, pll_tries, retval;
+
+	lane_count = dp->link_train.lane_count;
+
+	dp->link_train.lt_state = CLOCK_RECOVERY;
+	dp->link_train.eq_loop = 0;
+
+	for (lane = 0; lane < lane_count; lane++)
+		dp->link_train.cr_loop[lane] = 0;
+
+	/* Set link rate and count as you want to establish*/
+	exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+	exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
+
+	/* Setup RX configuration */
+	buf[0] = dp->link_train.link_rate;
+	buf[1] = dp->link_train.lane_count;
+	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
+				2, buf);
+	if (retval)
+		return retval;
+
+	/* Set TX pre-emphasis to minimum */
+	for (lane = 0; lane < lane_count; lane++)
+		exynos_dp_set_lane_lane_pre_emphasis(dp,
+			PRE_EMPHASIS_LEVEL_0, lane);
+
+	/* Wait for PLL lock */
+	pll_tries = 0;
+	while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+		if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
+			dev_err(dp->dev, "Wait for PLL lock timed out\n");
+			return -ETIMEDOUT;
+		}
+
+		pll_tries++;
+		usleep_range(90, 120);
+	}
+
+	/* Set training pattern 1 */
+	exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
+
+	/* Set RX training pattern */
+	retval = exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
+	if (retval)
+		return retval;
+
+	for (lane = 0; lane < lane_count; lane++)
+		buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
+			    DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
+
+	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+			lane_count, buf);
+
+	return retval;
+}
+
+static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = link_status[lane>>1];
+
+	return (link_value >> shift) & 0xf;
+}
+
+static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
+{
+	int lane;
+	u8 lane_status;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = exynos_dp_get_lane_status(link_status, lane);
+		if ((lane_status & DPCD_LANE_CR_DONE) == 0)
+			return -EINVAL;
+	}
+	return 0;
+}
+
+static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
+				int lane_count)
+{
+	int lane;
+	u8 lane_status;
+
+	if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
+		return -EINVAL;
+
+	for (lane = 0; lane < lane_count; lane++) {
+		lane_status = exynos_dp_get_lane_status(link_status, lane);
+		lane_status &= DPCD_CHANNEL_EQ_BITS;
+		if (lane_status != DPCD_CHANNEL_EQ_BITS)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
+							int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = adjust_request[lane>>1];
+
+	return (link_value >> shift) & 0x3;
+}
+
+static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
+					u8 adjust_request[2],
+					int lane)
+{
+	int shift = (lane & 1) * 4;
+	u8 link_value = adjust_request[lane>>1];
+
+	return ((link_value >> shift) & 0xc) >> 2;
+}
+
+static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
+					u8 training_lane_set, int lane)
+{
+	switch (lane) {
+	case 0:
+		exynos_dp_set_lane0_link_training(dp, training_lane_set);
+		break;
+	case 1:
+		exynos_dp_set_lane1_link_training(dp, training_lane_set);
+		break;
+
+	case 2:
+		exynos_dp_set_lane2_link_training(dp, training_lane_set);
+		break;
+
+	case 3:
+		exynos_dp_set_lane3_link_training(dp, training_lane_set);
+		break;
+	}
+}
+
+static unsigned int exynos_dp_get_lane_link_training(
+				struct exynos_dp_device *dp,
+				int lane)
+{
+	u32 reg;
+
+	switch (lane) {
+	case 0:
+		reg = exynos_dp_get_lane0_link_training(dp);
+		break;
+	case 1:
+		reg = exynos_dp_get_lane1_link_training(dp);
+		break;
+	case 2:
+		reg = exynos_dp_get_lane2_link_training(dp);
+		break;
+	case 3:
+		reg = exynos_dp_get_lane3_link_training(dp);
+		break;
+	default:
+		WARN_ON(1);
+		return 0;
+	}
+
+	return reg;
+}
+
+static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
+{
+	exynos_dp_training_pattern_dis(dp);
+	exynos_dp_set_enhanced_mode(dp);
+
+	dp->link_train.lt_state = FAILED;
+}
+
+static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
+					u8 adjust_request[2])
+{
+	int lane, lane_count;
+	u8 voltage_swing, pre_emphasis, training_lane;
+
+	lane_count = dp->link_train.lane_count;
+	for (lane = 0; lane < lane_count; lane++) {
+		voltage_swing = exynos_dp_get_adjust_request_voltage(
+						adjust_request, lane);
+		pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+						adjust_request, lane);
+		training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+				DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+		if (voltage_swing == VOLTAGE_LEVEL_3)
+			training_lane |= DPCD_MAX_SWING_REACHED;
+		if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+			training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+		dp->link_train.training_lane[lane] = training_lane;
+	}
+}
+
+static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
+{
+	int lane, lane_count, retval;
+	u8 voltage_swing, pre_emphasis, training_lane;
+	u8 link_status[2], adjust_request[2];
+
+	usleep_range(100, 101);
+
+	lane_count = dp->link_train.lane_count;
+
+	retval =  exynos_dp_read_bytes_from_dpcd(dp,
+			DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+	if (retval)
+		return retval;
+
+	retval =  exynos_dp_read_bytes_from_dpcd(dp,
+			DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+	if (retval)
+		return retval;
+
+	if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+		/* set training pattern 2 for EQ */
+		exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
+
+		retval = exynos_dp_write_byte_to_dpcd(dp,
+				DPCD_ADDR_TRAINING_PATTERN_SET,
+				DPCD_SCRAMBLING_DISABLED |
+				DPCD_TRAINING_PATTERN_2);
+		if (retval)
+			return retval;
+
+		dev_info(dp->dev, "Link Training Clock Recovery success\n");
+		dp->link_train.lt_state = EQUALIZER_TRAINING;
+	} else {
+		for (lane = 0; lane < lane_count; lane++) {
+			training_lane = exynos_dp_get_lane_link_training(
+							dp, lane);
+			voltage_swing = exynos_dp_get_adjust_request_voltage(
+							adjust_request, lane);
+			pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+							adjust_request, lane);
+
+			if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
+					voltage_swing &&
+			    DPCD_PRE_EMPHASIS_GET(training_lane) ==
+					pre_emphasis)
+				dp->link_train.cr_loop[lane]++;
+
+			if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
+			    voltage_swing == VOLTAGE_LEVEL_3 ||
+			    pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+				dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
+					dp->link_train.cr_loop[lane],
+					voltage_swing, pre_emphasis);
+				exynos_dp_reduce_link_rate(dp);
+				return -EIO;
+			}
+		}
+	}
+
+	exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+	for (lane = 0; lane < lane_count; lane++)
+		exynos_dp_set_lane_link_training(dp,
+			dp->link_train.training_lane[lane], lane);
+
+	retval = exynos_dp_write_bytes_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
+			dp->link_train.training_lane);
+	if (retval)
+		return retval;
+
+	return retval;
+}
+
+static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
+{
+	int lane, lane_count, retval;
+	u32 reg;
+	u8 link_align, link_status[2], adjust_request[2];
+
+	usleep_range(400, 401);
+
+	lane_count = dp->link_train.lane_count;
+
+	retval = exynos_dp_read_bytes_from_dpcd(dp,
+			DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+	if (retval)
+		return retval;
+
+	if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
+		exynos_dp_reduce_link_rate(dp);
+		return -EIO;
+	}
+
+	retval = exynos_dp_read_bytes_from_dpcd(dp,
+			DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+	if (retval)
+		return retval;
+
+	retval = exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
+	if (retval)
+		return retval;
+
+	exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+	if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
+		/* traing pattern Set to Normal */
+		exynos_dp_training_pattern_dis(dp);
+
+		dev_info(dp->dev, "Link Training success!\n");
+
+		exynos_dp_get_link_bandwidth(dp, &reg);
+		dp->link_train.link_rate = reg;
+		dev_dbg(dp->dev, "final bandwidth = %.2x\n",
+			dp->link_train.link_rate);
+
+		exynos_dp_get_lane_count(dp, &reg);
+		dp->link_train.lane_count = reg;
+		dev_dbg(dp->dev, "final lane count = %.2x\n",
+			dp->link_train.lane_count);
+
+		/* set enhanced mode if available */
+		exynos_dp_set_enhanced_mode(dp);
+		dp->link_train.lt_state = FINISHED;
+
+		return 0;
+	}
+
+	/* not all locked */
+	dp->link_train.eq_loop++;
+
+	if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
+		dev_err(dp->dev, "EQ Max loop\n");
+		exynos_dp_reduce_link_rate(dp);
+		return -EIO;
+	}
+
+	for (lane = 0; lane < lane_count; lane++)
+		exynos_dp_set_lane_link_training(dp,
+			dp->link_train.training_lane[lane], lane);
+
+	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+			lane_count, dp->link_train.training_lane);
+
+	return retval;
+}
+
+static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
+					u8 *bandwidth)
+{
+	u8 data;
+
+	/*
+	 * For DP rev.1.1, Maximum link rate of Main Link lanes
+	 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+	 */
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
+	*bandwidth = data;
+}
+
+static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
+					u8 *lane_count)
+{
+	u8 data;
+
+	/*
+	 * For DP rev.1.1, Maximum number of Main Link lanes
+	 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+	 */
+	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+	*lane_count = DPCD_MAX_LANE_COUNT(data);
+}
+
+static void exynos_dp_init_training(struct exynos_dp_device *dp,
+			enum link_lane_count_type max_lane,
+			enum link_rate_type max_rate)
+{
+	/*
+	 * MACRO_RST must be applied after the PLL_LOCK to avoid
+	 * the DP inter pair skew issue for at least 10 us
+	 */
+	exynos_dp_reset_macro(dp);
+
+	/* Initialize by reading RX's DPCD */
+	exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+	exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+
+	if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+	   (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+		dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
+			dp->link_train.link_rate);
+		dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+	}
+
+	if (dp->link_train.lane_count == 0) {
+		dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
+			dp->link_train.lane_count);
+		dp->link_train.lane_count = (u8)LANE_COUNT1;
+	}
+
+	/* Setup TX lane count & rate */
+	if (dp->link_train.lane_count > max_lane)
+		dp->link_train.lane_count = max_lane;
+	if (dp->link_train.link_rate > max_rate)
+		dp->link_train.link_rate = max_rate;
+
+	/* All DP analog module power up */
+	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+}
+
+static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
+{
+	int retval = 0, training_finished = 0;
+
+	dp->link_train.lt_state = START;
+
+	/* Process here */
+	while (!retval && !training_finished) {
+		switch (dp->link_train.lt_state) {
+		case START:
+			retval = exynos_dp_link_start(dp);
+			if (retval)
+				dev_err(dp->dev, "LT link start failed!\n");
+			break;
+		case CLOCK_RECOVERY:
+			retval = exynos_dp_process_clock_recovery(dp);
+			if (retval)
+				dev_err(dp->dev, "LT CR failed!\n");
+			break;
+		case EQUALIZER_TRAINING:
+			retval = exynos_dp_process_equalizer_training(dp);
+			if (retval)
+				dev_err(dp->dev, "LT EQ failed!\n");
+			break;
+		case FINISHED:
+			training_finished = 1;
+			break;
+		case FAILED:
+			return -EREMOTEIO;
+		}
+	}
+	if (retval)
+		dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
+
+	return retval;
+}
+
+static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
+				u32 count,
+				u32 bwtype)
+{
+	int i;
+	int retval;
+
+	for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
+		exynos_dp_init_training(dp, count, bwtype);
+		retval = exynos_dp_sw_link_training(dp);
+		if (retval == 0)
+			break;
+
+		usleep_range(100, 110);
+	}
+
+	return retval;
+}
+
+static int exynos_dp_config_video(struct exynos_dp_device *dp)
+{
+	int retval = 0;
+	int timeout_loop = 0;
+	int done_count = 0;
+
+	exynos_dp_config_video_slave_mode(dp);
+
+	exynos_dp_set_video_color_format(dp);
+
+	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+		dev_err(dp->dev, "PLL is not locked yet.\n");
+		return -EINVAL;
+	}
+
+	for (;;) {
+		timeout_loop++;
+		if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
+			break;
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "Timeout of video streamclk ok\n");
+			return -ETIMEDOUT;
+		}
+
+		usleep_range(1, 2);
+	}
+
+	/* Set to use the register calculated M/N video */
+	exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+	/* For video bist, Video timing must be generated by register */
+	exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
+
+	/* Disable video mute */
+	exynos_dp_enable_video_mute(dp, 0);
+
+	/* Configure video slave mode */
+	exynos_dp_enable_video_master(dp, 0);
+
+	/* Enable video */
+	exynos_dp_start_video(dp);
+
+	timeout_loop = 0;
+
+	for (;;) {
+		timeout_loop++;
+		if (exynos_dp_is_video_stream_on(dp) == 0) {
+			done_count++;
+			if (done_count > 10)
+				break;
+		} else if (done_count) {
+			done_count = 0;
+		}
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "Timeout of video streamclk ok\n");
+			return -ETIMEDOUT;
+		}
+
+		usleep_range(1000, 1001);
+	}
+
+	if (retval != 0)
+		dev_err(dp->dev, "Video stream is not detected!\n");
+
+	return retval;
+}
+
+static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
+{
+	u8 data;
+
+	if (enable) {
+		exynos_dp_enable_scrambling(dp);
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			&data);
+		exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			(u8)(data & ~DPCD_SCRAMBLING_DISABLED));
+	} else {
+		exynos_dp_disable_scrambling(dp);
+
+		exynos_dp_read_byte_from_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			&data);
+		exynos_dp_write_byte_to_dpcd(dp,
+			DPCD_ADDR_TRAINING_PATTERN_SET,
+			(u8)(data | DPCD_SCRAMBLING_DISABLED));
+	}
+}
+
+static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
+{
+	struct exynos_dp_device *dp = arg;
+
+	enum dp_irq_type irq_type;
+
+	irq_type = exynos_dp_get_irq_type(dp);
+	switch (irq_type) {
+	case DP_IRQ_TYPE_HP_CABLE_IN:
+		dev_dbg(dp->dev, "Received irq - cable in\n");
+		schedule_work(&dp->hotplug_work);
+		exynos_dp_clear_hotplug_interrupts(dp);
+		break;
+	case DP_IRQ_TYPE_HP_CABLE_OUT:
+		dev_dbg(dp->dev, "Received irq - cable out\n");
+		exynos_dp_clear_hotplug_interrupts(dp);
+		break;
+	case DP_IRQ_TYPE_HP_CHANGE:
+		/*
+		 * We get these change notifications once in a while, but there
+		 * is nothing we can do with them. Just ignore it for now and
+		 * only handle cable changes.
+		 */
+		dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
+		exynos_dp_clear_hotplug_interrupts(dp);
+		break;
+	default:
+		dev_err(dp->dev, "Received irq - unknown type!\n");
+		break;
+	}
+	return IRQ_HANDLED;
+}
+
+static void exynos_dp_hotplug(struct work_struct *work)
+{
+	struct exynos_dp_device *dp;
+	int ret;
+
+	dp = container_of(work, struct exynos_dp_device, hotplug_work);
+
+	ret = exynos_dp_detect_hpd(dp);
+	if (ret) {
+		/* Cable has been disconnected, we're done */
+		return;
+	}
+
+	ret = exynos_dp_handle_edid(dp);
+	if (ret) {
+		dev_err(dp->dev, "unable to handle edid\n");
+		return;
+	}
+
+	ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+					dp->video_info->link_rate);
+	if (ret) {
+		dev_err(dp->dev, "unable to do link train\n");
+		return;
+	}
+
+	exynos_dp_enable_scramble(dp, 1);
+	exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+	exynos_dp_enable_enhanced_mode(dp, 1);
+
+	exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+	exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+	exynos_dp_init_video(dp);
+	ret = exynos_dp_config_video(dp);
+	if (ret)
+		dev_err(dp->dev, "unable to config video\n");
+}
+
+#ifdef CONFIG_OF
+static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+	struct device_node *dp_node = dev->of_node;
+	struct exynos_dp_platdata *pd;
+	struct video_info *dp_video_config;
+
+	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
+	if (!pd) {
+		dev_err(dev, "memory allocation for pdata failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	dp_video_config = devm_kzalloc(dev,
+				sizeof(*dp_video_config), GFP_KERNEL);
+
+	if (!dp_video_config) {
+		dev_err(dev, "memory allocation for video config failed\n");
+		return ERR_PTR(-ENOMEM);
+	}
+	pd->video_info = dp_video_config;
+
+	dp_video_config->h_sync_polarity =
+		of_property_read_bool(dp_node, "hsync-active-high");
+
+	dp_video_config->v_sync_polarity =
+		of_property_read_bool(dp_node, "vsync-active-high");
+
+	dp_video_config->interlaced =
+		of_property_read_bool(dp_node, "interlaced");
+
+	if (of_property_read_u32(dp_node, "samsung,color-space",
+				&dp_video_config->color_space)) {
+		dev_err(dev, "failed to get color-space\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(dp_node, "samsung,dynamic-range",
+				&dp_video_config->dynamic_range)) {
+		dev_err(dev, "failed to get dynamic-range\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
+				&dp_video_config->ycbcr_coeff)) {
+		dev_err(dev, "failed to get ycbcr-coeff\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(dp_node, "samsung,color-depth",
+				&dp_video_config->color_depth)) {
+		dev_err(dev, "failed to get color-depth\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(dp_node, "samsung,link-rate",
+				&dp_video_config->link_rate)) {
+		dev_err(dev, "failed to get link-rate\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(dp_node, "samsung,lane-count",
+				&dp_video_config->lane_count)) {
+		dev_err(dev, "failed to get lane-count\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return pd;
+}
+
+static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+	struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
+	u32 phy_base;
+	int ret = 0;
+
+	dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
+	if (!dp_phy_node) {
+		dev_err(dp->dev, "could not find dptx-phy node\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
+		dev_err(dp->dev, "failed to get reg for dptx-phy\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
+				&dp->enable_mask)) {
+		dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
+		ret = -EINVAL;
+		goto err;
+	}
+
+	dp->phy_addr = ioremap(phy_base, SZ_4);
+	if (!dp->phy_addr) {
+		dev_err(dp->dev, "failed to ioremap dp-phy\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+err:
+	of_node_put(dp_phy_node);
+
+	return ret;
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = __raw_readl(dp->phy_addr);
+	reg |= dp->enable_mask;
+	__raw_writel(reg, dp->phy_addr);
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = __raw_readl(dp->phy_addr);
+	reg &= ~(dp->enable_mask);
+	__raw_writel(reg, dp->phy_addr);
+}
+#else
+static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+	return NULL;
+}
+
+static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+	return -EINVAL;
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+	return;
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+	return;
+}
+#endif /* CONFIG_OF */
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	struct exynos_dp_device *dp;
+	struct exynos_dp_platdata *pdata;
+
+	int ret = 0;
+
+	dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
+				GFP_KERNEL);
+	if (!dp) {
+		dev_err(&pdev->dev, "no memory for device data\n");
+		return -ENOMEM;
+	}
+
+	dp->dev = &pdev->dev;
+
+	if (pdev->dev.of_node) {
+		pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+
+		ret = exynos_dp_dt_parse_phydata(dp);
+		if (ret)
+			return ret;
+	} else {
+		pdata = pdev->dev.platform_data;
+		if (!pdata) {
+			dev_err(&pdev->dev, "no platform data\n");
+			return -EINVAL;
+		}
+	}
+
+	dp->clock = devm_clk_get(&pdev->dev, "dp");
+	if (IS_ERR(dp->clock)) {
+		dev_err(&pdev->dev, "failed to get clock\n");
+		return PTR_ERR(dp->clock);
+	}
+
+	clk_prepare_enable(dp->clock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(dp->reg_base))
+		return PTR_ERR(dp->reg_base);
+
+	dp->irq = platform_get_irq(pdev, 0);
+	if (dp->irq == -ENXIO) {
+		dev_err(&pdev->dev, "failed to get irq\n");
+		return -ENODEV;
+	}
+
+	INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
+
+	dp->video_info = pdata->video_info;
+
+	if (pdev->dev.of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_init(dp);
+	} else {
+		if (pdata->phy_init)
+			pdata->phy_init();
+	}
+
+	exynos_dp_init_dp(dp);
+
+	ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
+				"exynos-dp", dp);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request irq\n");
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, dp);
+
+	return 0;
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
+	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+
+	flush_work(&dp->hotplug_work);
+
+	if (pdev->dev.of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_exit(dp);
+	} else {
+		if (pdata->phy_exit)
+			pdata->phy_exit();
+	}
+
+	clk_disable_unprepare(dp->clock);
+
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_dp_suspend(struct device *dev)
+{
+	struct exynos_dp_platdata *pdata = dev->platform_data;
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	disable_irq(dp->irq);
+
+	flush_work(&dp->hotplug_work);
+
+	if (dev->of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_exit(dp);
+	} else {
+		if (pdata->phy_exit)
+			pdata->phy_exit();
+	}
+
+	clk_disable_unprepare(dp->clock);
+
+	return 0;
+}
+
+static int exynos_dp_resume(struct device *dev)
+{
+	struct exynos_dp_platdata *pdata = dev->platform_data;
+	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+
+	if (dev->of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_init(dp);
+	} else {
+		if (pdata->phy_init)
+			pdata->phy_init();
+	}
+
+	clk_prepare_enable(dp->clock);
+
+	exynos_dp_init_dp(dp);
+
+	enable_irq(dp->irq);
+
+	return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dp_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
+};
+
+static const struct of_device_id exynos_dp_match[] = {
+	{ .compatible = "samsung,exynos5-dp" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, exynos_dp_match);
+
+static struct platform_driver exynos_dp_driver = {
+	.probe		= exynos_dp_probe,
+	.remove		= exynos_dp_remove,
+	.driver		= {
+		.name	= "exynos-dp",
+		.owner	= THIS_MODULE,
+		.pm	= &exynos_dp_pm_ops,
+		.of_match_table = of_match_ptr(exynos_dp_match),
+	},
+};
+
+module_platform_driver(exynos_dp_driver);
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
new file mode 100644
index 0000000..6c567bbf
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -0,0 +1,210 @@
+/*
+ * Header file for Samsung DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DP_CORE_H
+#define _EXYNOS_DP_CORE_H
+
+enum dp_irq_type {
+	DP_IRQ_TYPE_HP_CABLE_IN,
+	DP_IRQ_TYPE_HP_CABLE_OUT,
+	DP_IRQ_TYPE_HP_CHANGE,
+	DP_IRQ_TYPE_UNKNOWN,
+};
+
+struct link_train {
+	int eq_loop;
+	int cr_loop[4];
+
+	u8 link_rate;
+	u8 lane_count;
+	u8 training_lane[4];
+
+	enum link_training_state lt_state;
+};
+
+struct exynos_dp_device {
+	struct device		*dev;
+	struct clk		*clock;
+	unsigned int		irq;
+	void __iomem		*reg_base;
+	void __iomem		*phy_addr;
+	unsigned int		enable_mask;
+
+	struct video_info	*video_info;
+	struct link_train	link_train;
+	struct work_struct	hotplug_work;
+};
+
+/* exynos_dp_reg.c */
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_stop_video(struct exynos_dp_device *dp);
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
+void exynos_dp_reset(struct exynos_dp_device *dp);
+void exynos_dp_swreset(struct exynos_dp_device *dp);
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+				enum analog_power_block block,
+				bool enable);
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
+void exynos_dp_init_hpd(struct exynos_dp_device *dp);
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
+void exynos_dp_reset_aux(struct exynos_dp_device *dp);
+void exynos_dp_init_aux(struct exynos_dp_device *dp);
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char data);
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char *data);
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[]);
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[]);
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr);
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int *data);
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char edid[]);
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+				 enum pattern_set pattern);
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+				u32 training_lane);
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
+void exynos_dp_reset_macro(struct exynos_dp_device *dp);
+void exynos_dp_init_video(struct exynos_dp_device *dp);
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+			enum clock_recovery_m_value_type type,
+			u32 m_value,
+			u32 n_value);
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_start_video(struct exynos_dp_device *dp);
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR			0x50
+#define I2C_E_EDID_DEVICE_ADDR			0x30
+
+#define EDID_BLOCK_LENGTH			0x80
+#define EDID_HEADER_PATTERN			0x00
+#define EDID_EXTENSION_FLAG			0x7e
+#define EDID_CHECKSUM				0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV			0x0000
+#define DPCD_ADDR_MAX_LINK_RATE			0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT		0x0002
+#define DPCD_ADDR_LINK_BW_SET			0x0100
+#define DPCD_ADDR_LANE_COUNT_SET		0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET		0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET		0x0103
+#define DPCD_ADDR_LANE0_1_STATUS		0x0202
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED	0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1	0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3	0x0207
+#define DPCD_ADDR_TEST_REQUEST			0x0218
+#define DPCD_ADDR_TEST_RESPONSE			0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM		0x0261
+#define DPCD_ADDR_SINK_POWER_STATE		0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x)		(((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x)			((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN			(0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x)			((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED		(0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED			(0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2			(0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1			(0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED		(0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED		(0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x)		(((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x)		(((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0	(0x0 << 3)
+#define DPCD_MAX_SWING_REACHED			(0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x)		(((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x)		(((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0	(0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED			(0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE		(0x1 << 1)
+#define DPCD_LANE_CR_DONE			(0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS			(DPCD_LANE_CR_DONE|	\
+						 DPCD_LANE_CHANNEL_EQ_DONE|\
+						 DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED		(0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED	(0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE		(0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ			(0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE		(0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0			(0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4			(0x2 << 0)
+
+#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c
new file mode 100644
index 0000000..29d9d03
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_reg.c
@@ -0,0 +1,1245 @@
+/*
+ * Samsung DP (Display port) register interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include <video/exynos_dp.h>
+
+#include "exynos_dp_core.h"
+#include "exynos_dp_reg.h"
+
+#define COMMON_INT_MASK_1	0
+#define COMMON_INT_MASK_2	0
+#define COMMON_INT_MASK_3	0
+#define COMMON_INT_MASK_4	(HOTPLUG_CHG | HPD_LOST | PLUG)
+#define INT_STA_MASK		INT_HPD
+
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+		reg |= HDCP_VIDEO_MUTE;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+		reg &= ~HDCP_VIDEO_MUTE;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	}
+}
+
+void exynos_dp_stop_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	reg &= ~VIDEO_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable)
+		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+			LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+	else
+		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+			LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+	writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
+}
+
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = TX_TERMINAL_CTRL_50_OHM;
+	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
+
+	reg = SEL_24M | TX_DVDD_BIT_1_0625V;
+	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
+
+	reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
+	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
+
+	reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
+		TX_CUR1_2X | TX_CUR_16_MA;
+	writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
+
+	reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
+		CH1_AMP_400_MV | CH0_AMP_400_MV;
+	writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
+}
+
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
+{
+	/* Set interrupt pin assertion polarity as high */
+	writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
+
+	/* Clear pending regisers */
+	writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+	writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
+	writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
+	writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+	writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	/* 0:mask,1: unmask */
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+	writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+void exynos_dp_reset(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	exynos_dp_stop_video(dp);
+	exynos_dp_enable_video_mute(dp, 0);
+
+	reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+		AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+		HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+	reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+		SERDES_FIFO_FUNC_EN_N |
+		LS_CLK_DOMAIN_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+
+	usleep_range(20, 30);
+
+	exynos_dp_lane_swap(dp, 0);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+	writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
+	writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
+
+	writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
+	writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
+
+	writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+	writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
+	writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
+
+	writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
+	writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
+
+	writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_swreset(struct exynos_dp_device *dp)
+{
+	writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
+}
+
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* 0: mask, 1: unmask */
+	reg = COMMON_INT_MASK_1;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+
+	reg = COMMON_INT_MASK_2;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+
+	reg = COMMON_INT_MASK_3;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+
+	reg = COMMON_INT_MASK_4;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+
+	reg = INT_STA_MASK;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+	if (reg & PLL_LOCK)
+		return PLL_LOCKED;
+	else
+		return PLL_UNLOCKED;
+}
+
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+		reg |= DP_PLL_PD;
+		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+		reg &= ~DP_PLL_PD;
+		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+	}
+}
+
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+				enum analog_power_block block,
+				bool enable)
+{
+	u32 reg;
+
+	switch (block) {
+	case AUX_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= AUX_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~AUX_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH0_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH1_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH1_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH1_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH2_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH2_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH2_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case CH3_BLOCK:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= CH3_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~CH3_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case ANALOG_TOTAL:
+		if (enable) {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg |= DP_PHY_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+			reg &= ~DP_PHY_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	case POWER_ALL:
+		if (enable) {
+			reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
+				CH1_PD | CH0_PD;
+			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+		} else {
+			writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
+{
+	u32 reg;
+	int timeout_loop = 0;
+
+	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+	reg = PLL_LOCK_CHG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+	reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+	writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+
+	/* Power up PLL */
+	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+		exynos_dp_set_pll_power_down(dp, 0);
+
+		while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+			timeout_loop++;
+			if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+				dev_err(dp->dev, "failed to get pll lock status\n");
+				return;
+			}
+			usleep_range(10, 20);
+		}
+	}
+
+	/* Enable Serdes FIFO function and Link symbol clock domain module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+		| AUX_FUNC_EN_N);
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = HOTPLUG_CHG | HPD_LOST | PLUG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+	reg = INT_HPD;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+}
+
+void exynos_dp_init_hpd(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	exynos_dp_clear_hotplug_interrupts(dp);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	reg &= ~(F_HPD | HPD_CTRL);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+}
+
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Parse hotplug interrupt status register */
+	reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+	if (reg & PLUG)
+		return DP_IRQ_TYPE_HP_CABLE_IN;
+
+	if (reg & HPD_LOST)
+		return DP_IRQ_TYPE_HP_CABLE_OUT;
+
+	if (reg & HOTPLUG_CHG)
+		return DP_IRQ_TYPE_HP_CHANGE;
+
+	return DP_IRQ_TYPE_UNKNOWN;
+}
+
+void exynos_dp_reset_aux(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Disable AUX channel module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg |= AUX_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_init_aux(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Clear inerrupts related to AUX channel */
+	reg = RPLY_RECEIV | AUX_ERR;
+	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	exynos_dp_reset_aux(dp);
+
+	/* Disable AUX transaction H/W retry */
+	reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
+		AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
+
+	/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+	reg = DEFER_CTRL_EN | DEFER_COUNT(1);
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
+
+	/* Enable AUX channel module */
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+	reg &= ~AUX_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	if (reg & HPD_STATUS)
+		return 0;
+
+	return -EINVAL;
+}
+
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+	reg &= ~SW_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+}
+
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
+{
+	int reg;
+	int retval = 0;
+	int timeout_loop = 0;
+
+	/* Enable AUX CH operation */
+	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+	reg |= AUX_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+	/* Is AUX CH command reply received? */
+	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+	while (!(reg & RPLY_RECEIV)) {
+		timeout_loop++;
+		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+			dev_err(dp->dev, "AUX CH command reply failed!\n");
+			return -ETIMEDOUT;
+		}
+		reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+		usleep_range(10, 11);
+	}
+
+	/* Clear interrupt source for AUX CH command reply */
+	writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
+
+	/* Clear interrupt source for AUX CH access error */
+	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+	if (reg & AUX_ERR) {
+		writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
+		return -EREMOTEIO;
+	}
+
+	/* Check AUX CH error access status */
+	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
+	if ((reg & AUX_STATUS_MASK) != 0) {
+		dev_err(dp->dev, "AUX CH error happens: %d\n\n",
+			reg & AUX_STATUS_MASK);
+		return -EREMOTEIO;
+	}
+
+	return retval;
+}
+
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 3; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select DPCD device address */
+		reg = AUX_ADDR_7_0(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+		reg = AUX_ADDR_15_8(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+		reg = AUX_ADDR_19_16(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+		/* Write data buffer */
+		reg = (unsigned int)data;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+		/*
+		 * Set DisplayPort transaction and write 1 byte
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+				__func__);
+	}
+
+	return retval;
+}
+
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned char *data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 3; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select DPCD device address */
+		reg = AUX_ADDR_7_0(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+		reg = AUX_ADDR_15_8(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+		reg = AUX_ADDR_19_16(reg_addr);
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+		/*
+		 * Set DisplayPort transaction and read 1 byte
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+				__func__);
+	}
+
+	/* Read data buffer */
+	reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+	*data = (unsigned char)(reg & 0xff);
+
+	return retval;
+}
+
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[])
+{
+	u32 reg;
+	unsigned int start_offset;
+	unsigned int cur_data_count;
+	unsigned int cur_data_idx;
+	int i;
+	int retval = 0;
+
+	/* Clear AUX CH data buffer */
+	reg = BUF_CLR;
+	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+	start_offset = 0;
+	while (start_offset < count) {
+		/* Buffer size of AUX CH is 16 * 4bytes */
+		if ((count - start_offset) > 16)
+			cur_data_count = 16;
+		else
+			cur_data_count = count - start_offset;
+
+		for (i = 0; i < 3; i++) {
+			/* Select DPCD device address */
+			reg = AUX_ADDR_7_0(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+			reg = AUX_ADDR_15_8(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+			reg = AUX_ADDR_19_16(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+			for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+			     cur_data_idx++) {
+				reg = data[start_offset + cur_data_idx];
+				writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
+							  + 4 * cur_data_idx);
+			}
+
+			/*
+			 * Set DisplayPort transaction and write
+			 * If bit 3 is 1, DisplayPort transaction.
+			 * If Bit 3 is 0, I2C transaction.
+			 */
+			reg = AUX_LENGTH(cur_data_count) |
+				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+			/* Start AUX transaction */
+			retval = exynos_dp_start_aux_transaction(dp);
+			if (retval == 0)
+				break;
+			else
+				dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+					__func__);
+		}
+
+		start_offset += cur_data_count;
+	}
+
+	return retval;
+}
+
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char data[])
+{
+	u32 reg;
+	unsigned int start_offset;
+	unsigned int cur_data_count;
+	unsigned int cur_data_idx;
+	int i;
+	int retval = 0;
+
+	/* Clear AUX CH data buffer */
+	reg = BUF_CLR;
+	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+	start_offset = 0;
+	while (start_offset < count) {
+		/* Buffer size of AUX CH is 16 * 4bytes */
+		if ((count - start_offset) > 16)
+			cur_data_count = 16;
+		else
+			cur_data_count = count - start_offset;
+
+		/* AUX CH Request Transaction process */
+		for (i = 0; i < 3; i++) {
+			/* Select DPCD device address */
+			reg = AUX_ADDR_7_0(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+			reg = AUX_ADDR_15_8(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+			reg = AUX_ADDR_19_16(reg_addr + start_offset);
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+			/*
+			 * Set DisplayPort transaction and read
+			 * If bit 3 is 1, DisplayPort transaction.
+			 * If Bit 3 is 0, I2C transaction.
+			 */
+			reg = AUX_LENGTH(cur_data_count) |
+				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+			/* Start AUX transaction */
+			retval = exynos_dp_start_aux_transaction(dp);
+			if (retval == 0)
+				break;
+			else
+				dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+					__func__);
+		}
+
+		for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+		    cur_data_idx++) {
+			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+						 + 4 * cur_data_idx);
+			data[start_offset + cur_data_idx] =
+				(unsigned char)reg;
+		}
+
+		start_offset += cur_data_count;
+	}
+
+	return retval;
+}
+
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr)
+{
+	u32 reg;
+	int retval;
+
+	/* Set EDID device address */
+	reg = device_addr;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+	/* Set offset from base address of EDID device */
+	writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+	/*
+	 * Set I2C transaction and write address
+	 * If bit 3 is 1, DisplayPort transaction.
+	 * If Bit 3 is 0, I2C transaction.
+	 */
+	reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+		AUX_TX_COMM_WRITE;
+	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+	/* Start AUX transaction */
+	retval = exynos_dp_start_aux_transaction(dp);
+	if (retval != 0)
+		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
+
+	return retval;
+}
+
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int *data)
+{
+	u32 reg;
+	int i;
+	int retval;
+
+	for (i = 0; i < 3; i++) {
+		/* Clear AUX CH data buffer */
+		reg = BUF_CLR;
+		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+		/* Select EDID device */
+		retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
+		if (retval != 0)
+			continue;
+
+		/*
+		 * Set I2C transaction and read data
+		 * If bit 3 is 1, DisplayPort transaction.
+		 * If Bit 3 is 0, I2C transaction.
+		 */
+		reg = AUX_TX_COMM_I2C_TRANSACTION |
+			AUX_TX_COMM_READ;
+		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+		/* Start AUX transaction */
+		retval = exynos_dp_start_aux_transaction(dp);
+		if (retval == 0)
+			break;
+		else
+			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+				__func__);
+	}
+
+	/* Read data */
+	if (retval == 0)
+		*data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+	return retval;
+}
+
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+				unsigned int device_addr,
+				unsigned int reg_addr,
+				unsigned int count,
+				unsigned char edid[])
+{
+	u32 reg;
+	unsigned int i, j;
+	unsigned int cur_data_idx;
+	unsigned int defer = 0;
+	int retval = 0;
+
+	for (i = 0; i < count; i += 16) {
+		for (j = 0; j < 3; j++) {
+			/* Clear AUX CH data buffer */
+			reg = BUF_CLR;
+			writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+			/* Set normal AUX CH command */
+			reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+			reg &= ~ADDR_ONLY;
+			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+			/*
+			 * If Rx sends defer, Tx sends only reads
+			 * request without sending address
+			 */
+			if (!defer)
+				retval = exynos_dp_select_i2c_device(dp,
+						device_addr, reg_addr + i);
+			else
+				defer = 0;
+
+			if (retval == 0) {
+				/*
+				 * Set I2C transaction and write data
+				 * If bit 3 is 1, DisplayPort transaction.
+				 * If Bit 3 is 0, I2C transaction.
+				 */
+				reg = AUX_LENGTH(16) |
+					AUX_TX_COMM_I2C_TRANSACTION |
+					AUX_TX_COMM_READ;
+				writel(reg, dp->reg_base +
+					EXYNOS_DP_AUX_CH_CTL_1);
+
+				/* Start AUX transaction */
+				retval = exynos_dp_start_aux_transaction(dp);
+				if (retval == 0)
+					break;
+				else
+					dev_dbg(dp->dev,
+						"%s: Aux Transaction fail!\n",
+						__func__);
+			}
+			/* Check if Rx sends defer */
+			reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
+			if (reg == AUX_RX_COMM_AUX_DEFER ||
+				reg == AUX_RX_COMM_I2C_DEFER) {
+				dev_err(dp->dev, "Defer: %d\n\n", reg);
+				defer = 1;
+			}
+		}
+
+		for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+						 + 4 * cur_data_idx);
+			edid[i + cur_data_idx] = (unsigned char)reg;
+		}
+	}
+
+	return retval;
+}
+
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
+{
+	u32 reg;
+
+	reg = bwtype;
+	if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+		writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+}
+
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+	*bwtype = reg;
+}
+
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
+{
+	u32 reg;
+
+	reg = count;
+	writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+}
+
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+	*count = reg;
+}
+
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg |= ENHANCED;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg &= ~ENHANCED;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+	}
+}
+
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+				 enum pattern_set pattern)
+{
+	u32 reg;
+
+	switch (pattern) {
+	case PRBS7:
+		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case D10_2:
+		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case TRAINING_PTN1:
+		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case TRAINING_PTN2:
+		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	case DP_NONE:
+		reg = SCRAMBLING_ENABLE |
+			LINK_QUAL_PATTERN_SET_DISABLE |
+			SW_TRAINING_PATTERN_SET_NORMAL;
+		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+		break;
+	default:
+		break;
+	}
+}
+
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+	reg &= ~PRE_EMPHASIS_SET_MASK;
+	reg |= level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+	reg &= ~PRE_EMPHASIS_SET_MASK;
+	reg |= level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+	reg &= ~PRE_EMPHASIS_SET_MASK;
+	reg |= level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+	reg &= ~PRE_EMPHASIS_SET_MASK;
+	reg |= level << PRE_EMPHASIS_SET_SHIFT;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+					u32 training_lane)
+{
+	u32 reg;
+
+	reg = training_lane;
+	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+	return reg;
+}
+
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+	return reg;
+}
+
+void exynos_dp_reset_macro(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
+	reg |= MACRO_RST;
+	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+	/* 10 us is the minimum reset time. */
+	usleep_range(10, 20);
+
+	reg &= ~MACRO_RST;
+	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+}
+
+void exynos_dp_init_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+	reg = 0x0;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	reg = CHA_CRI(4) | CHA_CTRL;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+	reg = 0x0;
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+	reg = VID_HRES_TH(2) | VID_VRES_TH(0);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
+}
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	/* Configure the input color depth, color space, dynamic range */
+	reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
+		(dp->video_info->color_depth << IN_BPC_SHIFT) |
+		(dp->video_info->color_space << IN_COLOR_F_SHIFT);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
+
+	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+	reg &= ~IN_YC_COEFFI_MASK;
+	if (dp->video_info->ycbcr_coeff)
+		reg |= IN_YC_COEFFI_ITU709;
+	else
+		reg |= IN_YC_COEFFI_ITU601;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+}
+
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+	if (!(reg & DET_STA)) {
+		dev_dbg(dp->dev, "Input stream clock not detected.\n");
+		return -EINVAL;
+	}
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+	dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
+
+	if (reg & CHA_STA) {
+		dev_dbg(dp->dev, "Input stream clk is changing\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+		enum clock_recovery_m_value_type type,
+		u32 m_value,
+		u32 n_value)
+{
+	u32 reg;
+
+	if (type == REGISTER_M) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg |= FIX_M_VID;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg = m_value & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
+		reg = (m_value >> 8) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
+		reg = (m_value >> 16) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
+
+		reg = n_value & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
+		reg = (n_value >> 8) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
+		reg = (n_value >> 16) & 0xff;
+		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
+	} else  {
+		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+		reg &= ~FIX_M_VID;
+		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
+		writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
+		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
+	}
+}
+
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
+{
+	u32 reg;
+
+	if (type == VIDEO_TIMING_FROM_CAPTURE) {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+		reg &= ~FORMAT_SEL;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+		reg |= FORMAT_SEL;
+		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	}
+}
+
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
+{
+	u32 reg;
+
+	if (enable) {
+		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+		reg &= ~VIDEO_MODE_MASK;
+		reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
+		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+	} else {
+		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+		reg &= ~VIDEO_MODE_MASK;
+		reg |= VIDEO_MODE_SLAVE_MODE;
+		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+	}
+}
+
+void exynos_dp_start_video(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+	reg |= VIDEO_EN;
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+	if (!(reg & STRM_VALID)) {
+		dev_dbg(dp->dev, "Input video stream is not detected.\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+	reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+	reg |= MASTER_VID_FUNC_EN_N;
+	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~INTERACE_SCAN_CFG;
+	reg |= (dp->video_info->interlaced << 2);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~VSYNC_POLARITY_CFG;
+	reg |= (dp->video_info->v_sync_polarity << 1);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+	reg &= ~HSYNC_POLARITY_CFG;
+	reg |= (dp->video_info->h_sync_polarity << 0);
+	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+	writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+	reg &= ~SCRAMBLING_DISABLE;
+	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
+
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
+{
+	u32 reg;
+
+	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+	reg |= SCRAMBLING_DISABLE;
+	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.h b/drivers/gpu/drm/exynos/exynos_dp_reg.h
new file mode 100644
index 0000000..2e9bd0e
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_dp_reg.h
@@ -0,0 +1,366 @@
+/*
+ * Register definition file for Samsung DP driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _EXYNOS_DP_REG_H
+#define _EXYNOS_DP_REG_H
+
+#define EXYNOS_DP_TX_SW_RESET			0x14
+#define EXYNOS_DP_FUNC_EN_1			0x18
+#define EXYNOS_DP_FUNC_EN_2			0x1C
+#define EXYNOS_DP_VIDEO_CTL_1			0x20
+#define EXYNOS_DP_VIDEO_CTL_2			0x24
+#define EXYNOS_DP_VIDEO_CTL_3			0x28
+
+#define EXYNOS_DP_VIDEO_CTL_8			0x3C
+#define EXYNOS_DP_VIDEO_CTL_10			0x44
+
+#define EXYNOS_DP_LANE_MAP			0x35C
+
+#define EXYNOS_DP_ANALOG_CTL_1			0x370
+#define EXYNOS_DP_ANALOG_CTL_2			0x374
+#define EXYNOS_DP_ANALOG_CTL_3			0x378
+#define EXYNOS_DP_PLL_FILTER_CTL_1		0x37C
+#define EXYNOS_DP_TX_AMP_TUNING_CTL		0x380
+
+#define EXYNOS_DP_AUX_HW_RETRY_CTL		0x390
+
+#define EXYNOS_DP_COMMON_INT_STA_1		0x3C4
+#define EXYNOS_DP_COMMON_INT_STA_2		0x3C8
+#define EXYNOS_DP_COMMON_INT_STA_3		0x3CC
+#define EXYNOS_DP_COMMON_INT_STA_4		0x3D0
+#define EXYNOS_DP_INT_STA			0x3DC
+#define EXYNOS_DP_COMMON_INT_MASK_1		0x3E0
+#define EXYNOS_DP_COMMON_INT_MASK_2		0x3E4
+#define EXYNOS_DP_COMMON_INT_MASK_3		0x3E8
+#define EXYNOS_DP_COMMON_INT_MASK_4		0x3EC
+#define EXYNOS_DP_INT_STA_MASK			0x3F8
+#define EXYNOS_DP_INT_CTL			0x3FC
+
+#define EXYNOS_DP_SYS_CTL_1			0x600
+#define EXYNOS_DP_SYS_CTL_2			0x604
+#define EXYNOS_DP_SYS_CTL_3			0x608
+#define EXYNOS_DP_SYS_CTL_4			0x60C
+
+#define EXYNOS_DP_PKT_SEND_CTL			0x640
+#define EXYNOS_DP_HDCP_CTL			0x648
+
+#define EXYNOS_DP_LINK_BW_SET			0x680
+#define EXYNOS_DP_LANE_COUNT_SET		0x684
+#define EXYNOS_DP_TRAINING_PTN_SET		0x688
+#define EXYNOS_DP_LN0_LINK_TRAINING_CTL		0x68C
+#define EXYNOS_DP_LN1_LINK_TRAINING_CTL		0x690
+#define EXYNOS_DP_LN2_LINK_TRAINING_CTL		0x694
+#define EXYNOS_DP_LN3_LINK_TRAINING_CTL		0x698
+
+#define EXYNOS_DP_DEBUG_CTL			0x6C0
+#define EXYNOS_DP_HPD_DEGLITCH_L		0x6C4
+#define EXYNOS_DP_HPD_DEGLITCH_H		0x6C8
+#define EXYNOS_DP_LINK_DEBUG_CTL		0x6E0
+
+#define EXYNOS_DP_M_VID_0			0x700
+#define EXYNOS_DP_M_VID_1			0x704
+#define EXYNOS_DP_M_VID_2			0x708
+#define EXYNOS_DP_N_VID_0			0x70C
+#define EXYNOS_DP_N_VID_1			0x710
+#define EXYNOS_DP_N_VID_2			0x714
+
+#define EXYNOS_DP_PLL_CTL			0x71C
+#define EXYNOS_DP_PHY_PD			0x720
+#define EXYNOS_DP_PHY_TEST			0x724
+
+#define EXYNOS_DP_VIDEO_FIFO_THRD		0x730
+#define EXYNOS_DP_AUDIO_MARGIN			0x73C
+
+#define EXYNOS_DP_M_VID_GEN_FILTER_TH		0x764
+#define EXYNOS_DP_M_AUD_GEN_FILTER_TH		0x778
+#define EXYNOS_DP_AUX_CH_STA			0x780
+#define EXYNOS_DP_AUX_CH_DEFER_CTL		0x788
+#define EXYNOS_DP_AUX_RX_COMM			0x78C
+#define EXYNOS_DP_BUFFER_DATA_CTL		0x790
+#define EXYNOS_DP_AUX_CH_CTL_1			0x794
+#define EXYNOS_DP_AUX_ADDR_7_0			0x798
+#define EXYNOS_DP_AUX_ADDR_15_8			0x79C
+#define EXYNOS_DP_AUX_ADDR_19_16		0x7A0
+#define EXYNOS_DP_AUX_CH_CTL_2			0x7A4
+
+#define EXYNOS_DP_BUF_DATA_0			0x7C0
+
+#define EXYNOS_DP_SOC_GENERAL_CTL		0x800
+
+/* EXYNOS_DP_TX_SW_RESET */
+#define RESET_DP_TX				(0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_1 */
+#define MASTER_VID_FUNC_EN_N			(0x1 << 7)
+#define SLAVE_VID_FUNC_EN_N			(0x1 << 5)
+#define AUD_FIFO_FUNC_EN_N			(0x1 << 4)
+#define AUD_FUNC_EN_N				(0x1 << 3)
+#define HDCP_FUNC_EN_N				(0x1 << 2)
+#define CRC_FUNC_EN_N				(0x1 << 1)
+#define SW_FUNC_EN_N				(0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_2 */
+#define SSC_FUNC_EN_N				(0x1 << 7)
+#define AUX_FUNC_EN_N				(0x1 << 2)
+#define SERDES_FIFO_FUNC_EN_N			(0x1 << 1)
+#define LS_CLK_DOMAIN_FUNC_EN_N			(0x1 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define VIDEO_EN				(0x1 << 7)
+#define HDCP_VIDEO_MUTE				(0x1 << 6)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define IN_D_RANGE_MASK				(0x1 << 7)
+#define IN_D_RANGE_SHIFT			(7)
+#define IN_D_RANGE_CEA				(0x1 << 7)
+#define IN_D_RANGE_VESA				(0x0 << 7)
+#define IN_BPC_MASK				(0x7 << 4)
+#define IN_BPC_SHIFT				(4)
+#define IN_BPC_12_BITS				(0x3 << 4)
+#define IN_BPC_10_BITS				(0x2 << 4)
+#define IN_BPC_8_BITS				(0x1 << 4)
+#define IN_BPC_6_BITS				(0x0 << 4)
+#define IN_COLOR_F_MASK				(0x3 << 0)
+#define IN_COLOR_F_SHIFT			(0)
+#define IN_COLOR_F_YCBCR444			(0x2 << 0)
+#define IN_COLOR_F_YCBCR422			(0x1 << 0)
+#define IN_COLOR_F_RGB				(0x0 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_3 */
+#define IN_YC_COEFFI_MASK			(0x1 << 7)
+#define IN_YC_COEFFI_SHIFT			(7)
+#define IN_YC_COEFFI_ITU709			(0x1 << 7)
+#define IN_YC_COEFFI_ITU601			(0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK		(0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT		(4)
+#define VID_CHK_UPDATE_TYPE_1			(0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0			(0x0 << 4)
+
+/* EXYNOS_DP_VIDEO_CTL_8 */
+#define VID_HRES_TH(x)				(((x) & 0xf) << 4)
+#define VID_VRES_TH(x)				(((x) & 0xf) << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_10 */
+#define FORMAT_SEL				(0x1 << 4)
+#define INTERACE_SCAN_CFG			(0x1 << 2)
+#define VSYNC_POLARITY_CFG			(0x1 << 1)
+#define HSYNC_POLARITY_CFG			(0x1 << 0)
+
+/* EXYNOS_DP_LANE_MAP */
+#define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1			(0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2			(0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3			(0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0			(0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1			(0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2			(0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3			(0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0			(0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1			(0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2			(0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3			(0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0			(0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
+
+/* EXYNOS_DP_ANALOG_CTL_2 */
+#define SEL_24M					(0x1 << 3)
+#define TX_DVDD_BIT_1_0625V			(0x4 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V			(0x4 << 5)
+#define VCO_BIT_600_MICRO			(0x5 << 0)
+
+/* EXYNOS_DP_PLL_FILTER_CTL_1 */
+#define PD_RING_OSC				(0x1 << 6)
+#define AUX_TERMINAL_CTRL_50_OHM		(0x2 << 4)
+#define TX_CUR1_2X				(0x1 << 2)
+#define TX_CUR_16_MA				(0x3 << 0)
+
+/* EXYNOS_DP_TX_AMP_TUNING_CTL */
+#define CH3_AMP_400_MV				(0x0 << 24)
+#define CH2_AMP_400_MV				(0x0 << 16)
+#define CH1_AMP_400_MV				(0x0 << 8)
+#define CH0_AMP_400_MV				(0x0 << 0)
+
+/* EXYNOS_DP_AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x)	(((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK		(0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS	(0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS	(0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS	(0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS	(0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x)		(((x) & 0x7) << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_1 */
+#define VSYNC_DET				(0x1 << 7)
+#define PLL_LOCK_CHG				(0x1 << 6)
+#define SPDIF_ERR				(0x1 << 5)
+#define SPDIF_UNSTBL				(0x1 << 4)
+#define VID_FORMAT_CHG				(0x1 << 3)
+#define AUD_CLK_CHG				(0x1 << 2)
+#define VID_CLK_CHG				(0x1 << 1)
+#define SW_INT					(0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_2 */
+#define ENC_EN_CHG				(0x1 << 6)
+#define HW_BKSV_RDY				(0x1 << 3)
+#define HW_SHA_DONE				(0x1 << 2)
+#define HW_AUTH_STATE_CHG			(0x1 << 1)
+#define HW_AUTH_DONE				(0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_3 */
+#define AFIFO_UNDER				(0x1 << 7)
+#define AFIFO_OVER				(0x1 << 6)
+#define R0_CHK_FLAG				(0x1 << 5)
+
+/* EXYNOS_DP_COMMON_INT_STA_4 */
+#define PSR_ACTIVE				(0x1 << 7)
+#define PSR_INACTIVE				(0x1 << 6)
+#define SPDIF_BI_PHASE_ERR			(0x1 << 5)
+#define HOTPLUG_CHG				(0x1 << 2)
+#define HPD_LOST				(0x1 << 1)
+#define PLUG					(0x1 << 0)
+
+/* EXYNOS_DP_INT_STA */
+#define INT_HPD					(0x1 << 6)
+#define HW_TRAINING_FINISH			(0x1 << 5)
+#define RPLY_RECEIV				(0x1 << 1)
+#define AUX_ERR					(0x1 << 0)
+
+/* EXYNOS_DP_INT_CTL */
+#define SOFT_INT_CTRL				(0x1 << 2)
+#define INT_POL1				(0x1 << 1)
+#define INT_POL0				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_1 */
+#define DET_STA					(0x1 << 2)
+#define FORCE_DET				(0x1 << 1)
+#define DET_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_2 */
+#define CHA_CRI(x)				(((x) & 0xf) << 4)
+#define CHA_STA					(0x1 << 2)
+#define FORCE_CHA				(0x1 << 1)
+#define CHA_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_3 */
+#define HPD_STATUS				(0x1 << 6)
+#define F_HPD					(0x1 << 5)
+#define HPD_CTRL				(0x1 << 4)
+#define HDCP_RDY				(0x1 << 3)
+#define STRM_VALID				(0x1 << 2)
+#define F_VALID					(0x1 << 1)
+#define VALID_CTRL				(0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_4 */
+#define FIX_M_AUD				(0x1 << 4)
+#define ENHANCED				(0x1 << 3)
+#define FIX_M_VID				(0x1 << 2)
+#define M_VID_UPDATE_CTRL			(0x3 << 0)
+
+/* EXYNOS_DP_TRAINING_PTN_SET */
+#define SCRAMBLER_TYPE				(0x1 << 9)
+#define HW_LINK_TRAINING_PATTERN		(0x1 << 8)
+#define SCRAMBLING_DISABLE			(0x1 << 5)
+#define SCRAMBLING_ENABLE			(0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK		(0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7		(0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2		(0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE		(0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK		(0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2		(0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1		(0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_NORMAL		(0x0 << 0)
+
+/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK			(0x3 << 3)
+#define PRE_EMPHASIS_SET_SHIFT			(3)
+
+/* EXYNOS_DP_DEBUG_CTL */
+#define PLL_LOCK				(0x1 << 4)
+#define F_PLL_LOCK				(0x1 << 3)
+#define PLL_LOCK_CTRL				(0x1 << 2)
+#define PN_INV					(0x1 << 0)
+
+/* EXYNOS_DP_PLL_CTL */
+#define DP_PLL_PD				(0x1 << 7)
+#define DP_PLL_RESET				(0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT			(0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V			(0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V			(0x7 << 0)
+
+/* EXYNOS_DP_PHY_PD */
+#define DP_PHY_PD				(0x1 << 5)
+#define AUX_PD					(0x1 << 4)
+#define CH3_PD					(0x1 << 3)
+#define CH2_PD					(0x1 << 2)
+#define CH1_PD					(0x1 << 1)
+#define CH0_PD					(0x1 << 0)
+
+/* EXYNOS_DP_PHY_TEST */
+#define MACRO_RST				(0x1 << 5)
+#define CH1_TEST				(0x1 << 1)
+#define CH0_TEST				(0x1 << 0)
+
+/* EXYNOS_DP_AUX_CH_STA */
+#define AUX_BUSY				(0x1 << 4)
+#define AUX_STATUS_MASK				(0xf << 0)
+
+/* EXYNOS_DP_AUX_CH_DEFER_CTL */
+#define DEFER_CTRL_EN				(0x1 << 7)
+#define DEFER_COUNT(x)				(((x) & 0x7f) << 0)
+
+/* EXYNOS_DP_AUX_RX_COMM */
+#define AUX_RX_COMM_I2C_DEFER			(0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER			(0x2 << 0)
+
+/* EXYNOS_DP_BUFFER_DATA_CTL */
+#define BUF_CLR					(0x1 << 7)
+#define BUF_DATA_COUNT(x)			(((x) & 0x1f) << 0)
+
+/* EXYNOS_DP_AUX_CH_CTL_1 */
+#define AUX_LENGTH(x)				(((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK			(0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION		(0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION		(0x0 << 3)
+#define AUX_TX_COMM_MOT				(0x1 << 2)
+#define AUX_TX_COMM_WRITE			(0x0 << 0)
+#define AUX_TX_COMM_READ			(0x1 << 0)
+
+/* EXYNOS_DP_AUX_ADDR_7_0 */
+#define AUX_ADDR_7_0(x)				(((x) >> 0) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_15_8 */
+#define AUX_ADDR_15_8(x)			(((x) >> 8) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_19_16 */
+#define AUX_ADDR_19_16(x)			(((x) >> 16) & 0x0f)
+
+/* EXYNOS_DP_AUX_CH_CTL_2 */
+#define ADDR_ONLY				(0x1 << 1)
+#define AUX_EN					(0x1 << 0)
+
+/* EXYNOS_DP_SOC_GENERAL_CTL */
+#define AUDIO_MODE_SPDIF_MODE			(0x1 << 8)
+#define AUDIO_MODE_MASTER_MODE			(0x0 << 8)
+#define MASTER_VIDEO_INTERLACE_EN		(0x1 << 4)
+#define VIDEO_MASTER_CLK_SEL			(0x1 << 2)
+#define VIDEO_MASTER_MODE_EN			(0x1 << 1)
+#define VIDEO_MODE_MASK				(0x1 << 0)
+#define VIDEO_MODE_SLAVE_MODE			(0x1 << 0)
+#define VIDEO_MODE_MASTER_MODE			(0x0 << 0)
+
+#endif /* _EXYNOS_DP_REG_H */
diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig
index 1b035b2..7032ad9 100644
--- a/drivers/video/exynos/Kconfig
+++ b/drivers/video/exynos/Kconfig
@@ -27,11 +27,4 @@ config EXYNOS_LCD_S6E8AX0
 	  If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
 	  LCD control driver.
 
-config EXYNOS_DP
-	bool "EXYNOS DP driver support"
-	depends on ARCH_EXYNOS
-	default n
-	help
-	  This enables support for DP device.
-
 endif # EXYNOS_VIDEO
diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile
index ec7772e..b5b1bd2 100644
--- a/drivers/video/exynos/Makefile
+++ b/drivers/video/exynos/Makefile
@@ -5,4 +5,3 @@
 obj-$(CONFIG_EXYNOS_MIPI_DSI)		+= exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				     	exynos_mipi_dsi_lowlevel.o
 obj-$(CONFIG_EXYNOS_LCD_S6E8AX0)	+= s6e8ax0.o
-obj-$(CONFIG_EXYNOS_DP)			+= exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
deleted file mode 100644
index 089ae22..0000000
--- a/drivers/video/exynos/exynos_dp_core.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*
- * Samsung SoC DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-
-#include <video/exynos_dp.h>
-
-#include "exynos_dp_core.h"
-
-static int exynos_dp_init_dp(struct exynos_dp_device *dp)
-{
-	exynos_dp_reset(dp);
-
-	exynos_dp_swreset(dp);
-
-	exynos_dp_init_analog_param(dp);
-	exynos_dp_init_interrupt(dp);
-
-	/* SW defined function Normal operation */
-	exynos_dp_enable_sw_function(dp);
-
-	exynos_dp_config_interrupt(dp);
-	exynos_dp_init_analog_func(dp);
-
-	exynos_dp_init_hpd(dp);
-	exynos_dp_init_aux(dp);
-
-	return 0;
-}
-
-static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
-{
-	int timeout_loop = 0;
-
-	while (exynos_dp_get_plug_in_status(dp) != 0) {
-		timeout_loop++;
-		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-			dev_err(dp->dev, "failed to get hpd plug status\n");
-			return -ETIMEDOUT;
-		}
-		usleep_range(10, 11);
-	}
-
-	return 0;
-}
-
-static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
-{
-	int i;
-	unsigned char sum = 0;
-
-	for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-		sum = sum + edid_data[i];
-
-	return sum;
-}
-
-static int exynos_dp_read_edid(struct exynos_dp_device *dp)
-{
-	unsigned char edid[EDID_BLOCK_LENGTH * 2];
-	unsigned int extend_block = 0;
-	unsigned char sum;
-	unsigned char test_vector;
-	int retval;
-
-	/*
-	 * EDID device address is 0x50.
-	 * However, if necessary, you must have set upper address
-	 * into E-EDID in I2C device, 0x30.
-	 */
-
-	/* Read Extension Flag, Number of 128-byte EDID extension blocks */
-	retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-				EDID_EXTENSION_FLAG,
-				&extend_block);
-	if (retval)
-		return retval;
-
-	if (extend_block > 0) {
-		dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-		/* Read EDID data */
-		retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-						EDID_HEADER_PATTERN,
-						EDID_BLOCK_LENGTH,
-						&edid[EDID_HEADER_PATTERN]);
-		if (retval != 0) {
-			dev_err(dp->dev, "EDID Read failed!\n");
-			return -EIO;
-		}
-		sum = exynos_dp_calc_edid_check_sum(edid);
-		if (sum != 0) {
-			dev_err(dp->dev, "EDID bad checksum!\n");
-			return -EIO;
-		}
-
-		/* Read additional EDID data */
-		retval = exynos_dp_read_bytes_from_i2c(dp,
-				I2C_EDID_DEVICE_ADDR,
-				EDID_BLOCK_LENGTH,
-				EDID_BLOCK_LENGTH,
-				&edid[EDID_BLOCK_LENGTH]);
-		if (retval != 0) {
-			dev_err(dp->dev, "EDID Read failed!\n");
-			return -EIO;
-		}
-		sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
-		if (sum != 0) {
-			dev_err(dp->dev, "EDID bad checksum!\n");
-			return -EIO;
-		}
-
-		exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
-					&test_vector);
-		if (test_vector & DPCD_TEST_EDID_READ) {
-			exynos_dp_write_byte_to_dpcd(dp,
-				DPCD_ADDR_TEST_EDID_CHECKSUM,
-				edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-			exynos_dp_write_byte_to_dpcd(dp,
-				DPCD_ADDR_TEST_RESPONSE,
-				DPCD_TEST_EDID_CHECKSUM_WRITE);
-		}
-	} else {
-		dev_info(dp->dev, "EDID data does not include any extensions.\n");
-
-		/* Read EDID data */
-		retval = exynos_dp_read_bytes_from_i2c(dp,
-				I2C_EDID_DEVICE_ADDR,
-				EDID_HEADER_PATTERN,
-				EDID_BLOCK_LENGTH,
-				&edid[EDID_HEADER_PATTERN]);
-		if (retval != 0) {
-			dev_err(dp->dev, "EDID Read failed!\n");
-			return -EIO;
-		}
-		sum = exynos_dp_calc_edid_check_sum(edid);
-		if (sum != 0) {
-			dev_err(dp->dev, "EDID bad checksum!\n");
-			return -EIO;
-		}
-
-		exynos_dp_read_byte_from_dpcd(dp,
-			DPCD_ADDR_TEST_REQUEST,
-			&test_vector);
-		if (test_vector & DPCD_TEST_EDID_READ) {
-			exynos_dp_write_byte_to_dpcd(dp,
-				DPCD_ADDR_TEST_EDID_CHECKSUM,
-				edid[EDID_CHECKSUM]);
-			exynos_dp_write_byte_to_dpcd(dp,
-				DPCD_ADDR_TEST_RESPONSE,
-				DPCD_TEST_EDID_CHECKSUM_WRITE);
-		}
-	}
-
-	dev_err(dp->dev, "EDID Read success!\n");
-	return 0;
-}
-
-static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
-{
-	u8 buf[12];
-	int i;
-	int retval;
-
-	/* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
-	retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
-				12, buf);
-	if (retval)
-		return retval;
-
-	/* Read EDID */
-	for (i = 0; i < 3; i++) {
-		retval = exynos_dp_read_edid(dp);
-		if (!retval)
-			break;
-	}
-
-	return retval;
-}
-
-static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
-						bool enable)
-{
-	u8 data;
-
-	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
-
-	if (enable)
-		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
-			DPCD_ENHANCED_FRAME_EN |
-			DPCD_LANE_COUNT_SET(data));
-	else
-		exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
-			DPCD_LANE_COUNT_SET(data));
-}
-
-static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
-{
-	u8 data;
-	int retval;
-
-	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
-	retval = DPCD_ENHANCED_FRAME_CAP(data);
-
-	return retval;
-}
-
-static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
-{
-	u8 data;
-
-	data = exynos_dp_is_enhanced_mode_available(dp);
-	exynos_dp_enable_rx_to_enhanced_mode(dp, data);
-	exynos_dp_enable_enhanced_mode(dp, data);
-}
-
-static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
-{
-	exynos_dp_set_training_pattern(dp, DP_NONE);
-
-	exynos_dp_write_byte_to_dpcd(dp,
-		DPCD_ADDR_TRAINING_PATTERN_SET,
-		DPCD_TRAINING_PATTERN_DISABLED);
-}
-
-static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
-					int pre_emphasis, int lane)
-{
-	switch (lane) {
-	case 0:
-		exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
-		break;
-	case 1:
-		exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
-		break;
-
-	case 2:
-		exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
-		break;
-
-	case 3:
-		exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
-		break;
-	}
-}
-
-static int exynos_dp_link_start(struct exynos_dp_device *dp)
-{
-	u8 buf[4];
-	int lane, lane_count, pll_tries, retval;
-
-	lane_count = dp->link_train.lane_count;
-
-	dp->link_train.lt_state = CLOCK_RECOVERY;
-	dp->link_train.eq_loop = 0;
-
-	for (lane = 0; lane < lane_count; lane++)
-		dp->link_train.cr_loop[lane] = 0;
-
-	/* Set link rate and count as you want to establish*/
-	exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
-	exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
-
-	/* Setup RX configuration */
-	buf[0] = dp->link_train.link_rate;
-	buf[1] = dp->link_train.lane_count;
-	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
-				2, buf);
-	if (retval)
-		return retval;
-
-	/* Set TX pre-emphasis to minimum */
-	for (lane = 0; lane < lane_count; lane++)
-		exynos_dp_set_lane_lane_pre_emphasis(dp,
-			PRE_EMPHASIS_LEVEL_0, lane);
-
-	/* Wait for PLL lock */
-	pll_tries = 0;
-	while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-		if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
-			dev_err(dp->dev, "Wait for PLL lock timed out\n");
-			return -ETIMEDOUT;
-		}
-
-		pll_tries++;
-		usleep_range(90, 120);
-	}
-
-	/* Set training pattern 1 */
-	exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
-
-	/* Set RX training pattern */
-	retval = exynos_dp_write_byte_to_dpcd(dp,
-			DPCD_ADDR_TRAINING_PATTERN_SET,
-			DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
-	if (retval)
-		return retval;
-
-	for (lane = 0; lane < lane_count; lane++)
-		buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
-			    DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
-
-	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
-			lane_count, buf);
-
-	return retval;
-}
-
-static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
-{
-	int shift = (lane & 1) * 4;
-	u8 link_value = link_status[lane>>1];
-
-	return (link_value >> shift) & 0xf;
-}
-
-static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
-{
-	int lane;
-	u8 lane_status;
-
-	for (lane = 0; lane < lane_count; lane++) {
-		lane_status = exynos_dp_get_lane_status(link_status, lane);
-		if ((lane_status & DPCD_LANE_CR_DONE) == 0)
-			return -EINVAL;
-	}
-	return 0;
-}
-
-static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
-				int lane_count)
-{
-	int lane;
-	u8 lane_status;
-
-	if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
-		return -EINVAL;
-
-	for (lane = 0; lane < lane_count; lane++) {
-		lane_status = exynos_dp_get_lane_status(link_status, lane);
-		lane_status &= DPCD_CHANNEL_EQ_BITS;
-		if (lane_status != DPCD_CHANNEL_EQ_BITS)
-			return -EINVAL;
-	}
-
-	return 0;
-}
-
-static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
-							int lane)
-{
-	int shift = (lane & 1) * 4;
-	u8 link_value = adjust_request[lane>>1];
-
-	return (link_value >> shift) & 0x3;
-}
-
-static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
-					u8 adjust_request[2],
-					int lane)
-{
-	int shift = (lane & 1) * 4;
-	u8 link_value = adjust_request[lane>>1];
-
-	return ((link_value >> shift) & 0xc) >> 2;
-}
-
-static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
-					u8 training_lane_set, int lane)
-{
-	switch (lane) {
-	case 0:
-		exynos_dp_set_lane0_link_training(dp, training_lane_set);
-		break;
-	case 1:
-		exynos_dp_set_lane1_link_training(dp, training_lane_set);
-		break;
-
-	case 2:
-		exynos_dp_set_lane2_link_training(dp, training_lane_set);
-		break;
-
-	case 3:
-		exynos_dp_set_lane3_link_training(dp, training_lane_set);
-		break;
-	}
-}
-
-static unsigned int exynos_dp_get_lane_link_training(
-				struct exynos_dp_device *dp,
-				int lane)
-{
-	u32 reg;
-
-	switch (lane) {
-	case 0:
-		reg = exynos_dp_get_lane0_link_training(dp);
-		break;
-	case 1:
-		reg = exynos_dp_get_lane1_link_training(dp);
-		break;
-	case 2:
-		reg = exynos_dp_get_lane2_link_training(dp);
-		break;
-	case 3:
-		reg = exynos_dp_get_lane3_link_training(dp);
-		break;
-	default:
-		WARN_ON(1);
-		return 0;
-	}
-
-	return reg;
-}
-
-static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
-{
-	exynos_dp_training_pattern_dis(dp);
-	exynos_dp_set_enhanced_mode(dp);
-
-	dp->link_train.lt_state = FAILED;
-}
-
-static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
-					u8 adjust_request[2])
-{
-	int lane, lane_count;
-	u8 voltage_swing, pre_emphasis, training_lane;
-
-	lane_count = dp->link_train.lane_count;
-	for (lane = 0; lane < lane_count; lane++) {
-		voltage_swing = exynos_dp_get_adjust_request_voltage(
-						adjust_request, lane);
-		pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
-						adjust_request, lane);
-		training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
-				DPCD_PRE_EMPHASIS_SET(pre_emphasis);
-
-		if (voltage_swing == VOLTAGE_LEVEL_3)
-			training_lane |= DPCD_MAX_SWING_REACHED;
-		if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
-			training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
-
-		dp->link_train.training_lane[lane] = training_lane;
-	}
-}
-
-static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
-{
-	int lane, lane_count, retval;
-	u8 voltage_swing, pre_emphasis, training_lane;
-	u8 link_status[2], adjust_request[2];
-
-	usleep_range(100, 101);
-
-	lane_count = dp->link_train.lane_count;
-
-	retval =  exynos_dp_read_bytes_from_dpcd(dp,
-			DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
-	if (retval)
-		return retval;
-
-	retval =  exynos_dp_read_bytes_from_dpcd(dp,
-			DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-	if (retval)
-		return retval;
-
-	if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
-		/* set training pattern 2 for EQ */
-		exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
-
-		retval = exynos_dp_write_byte_to_dpcd(dp,
-				DPCD_ADDR_TRAINING_PATTERN_SET,
-				DPCD_SCRAMBLING_DISABLED |
-				DPCD_TRAINING_PATTERN_2);
-		if (retval)
-			return retval;
-
-		dev_info(dp->dev, "Link Training Clock Recovery success\n");
-		dp->link_train.lt_state = EQUALIZER_TRAINING;
-	} else {
-		for (lane = 0; lane < lane_count; lane++) {
-			training_lane = exynos_dp_get_lane_link_training(
-							dp, lane);
-			voltage_swing = exynos_dp_get_adjust_request_voltage(
-							adjust_request, lane);
-			pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
-							adjust_request, lane);
-
-			if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
-					voltage_swing &&
-			    DPCD_PRE_EMPHASIS_GET(training_lane) ==
-					pre_emphasis)
-				dp->link_train.cr_loop[lane]++;
-
-			if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
-			    voltage_swing == VOLTAGE_LEVEL_3 ||
-			    pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
-				dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
-					dp->link_train.cr_loop[lane],
-					voltage_swing, pre_emphasis);
-				exynos_dp_reduce_link_rate(dp);
-				return -EIO;
-			}
-		}
-	}
-
-	exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
-	for (lane = 0; lane < lane_count; lane++)
-		exynos_dp_set_lane_link_training(dp,
-			dp->link_train.training_lane[lane], lane);
-
-	retval = exynos_dp_write_bytes_to_dpcd(dp,
-			DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
-			dp->link_train.training_lane);
-	if (retval)
-		return retval;
-
-	return retval;
-}
-
-static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
-{
-	int lane, lane_count, retval;
-	u32 reg;
-	u8 link_align, link_status[2], adjust_request[2];
-
-	usleep_range(400, 401);
-
-	lane_count = dp->link_train.lane_count;
-
-	retval = exynos_dp_read_bytes_from_dpcd(dp,
-			DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
-	if (retval)
-		return retval;
-
-	if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
-		exynos_dp_reduce_link_rate(dp);
-		return -EIO;
-	}
-
-	retval = exynos_dp_read_bytes_from_dpcd(dp,
-			DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-	if (retval)
-		return retval;
-
-	retval = exynos_dp_read_byte_from_dpcd(dp,
-			DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
-	if (retval)
-		return retval;
-
-	exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
-	if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
-		/* traing pattern Set to Normal */
-		exynos_dp_training_pattern_dis(dp);
-
-		dev_info(dp->dev, "Link Training success!\n");
-
-		exynos_dp_get_link_bandwidth(dp, &reg);
-		dp->link_train.link_rate = reg;
-		dev_dbg(dp->dev, "final bandwidth = %.2x\n",
-			dp->link_train.link_rate);
-
-		exynos_dp_get_lane_count(dp, &reg);
-		dp->link_train.lane_count = reg;
-		dev_dbg(dp->dev, "final lane count = %.2x\n",
-			dp->link_train.lane_count);
-
-		/* set enhanced mode if available */
-		exynos_dp_set_enhanced_mode(dp);
-		dp->link_train.lt_state = FINISHED;
-
-		return 0;
-	}
-
-	/* not all locked */
-	dp->link_train.eq_loop++;
-
-	if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
-		dev_err(dp->dev, "EQ Max loop\n");
-		exynos_dp_reduce_link_rate(dp);
-		return -EIO;
-	}
-
-	for (lane = 0; lane < lane_count; lane++)
-		exynos_dp_set_lane_link_training(dp,
-			dp->link_train.training_lane[lane], lane);
-
-	retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
-			lane_count, dp->link_train.training_lane);
-
-	return retval;
-}
-
-static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
-					u8 *bandwidth)
-{
-	u8 data;
-
-	/*
-	 * For DP rev.1.1, Maximum link rate of Main Link lanes
-	 * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
-	 */
-	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
-	*bandwidth = data;
-}
-
-static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
-					u8 *lane_count)
-{
-	u8 data;
-
-	/*
-	 * For DP rev.1.1, Maximum number of Main Link lanes
-	 * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
-	 */
-	exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
-	*lane_count = DPCD_MAX_LANE_COUNT(data);
-}
-
-static void exynos_dp_init_training(struct exynos_dp_device *dp,
-			enum link_lane_count_type max_lane,
-			enum link_rate_type max_rate)
-{
-	/*
-	 * MACRO_RST must be applied after the PLL_LOCK to avoid
-	 * the DP inter pair skew issue for at least 10 us
-	 */
-	exynos_dp_reset_macro(dp);
-
-	/* Initialize by reading RX's DPCD */
-	exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
-	exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
-
-	if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
-	   (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
-		dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
-			dp->link_train.link_rate);
-		dp->link_train.link_rate = LINK_RATE_1_62GBPS;
-	}
-
-	if (dp->link_train.lane_count == 0) {
-		dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
-			dp->link_train.lane_count);
-		dp->link_train.lane_count = (u8)LANE_COUNT1;
-	}
-
-	/* Setup TX lane count & rate */
-	if (dp->link_train.lane_count > max_lane)
-		dp->link_train.lane_count = max_lane;
-	if (dp->link_train.link_rate > max_rate)
-		dp->link_train.link_rate = max_rate;
-
-	/* All DP analog module power up */
-	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-}
-
-static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
-{
-	int retval = 0, training_finished = 0;
-
-	dp->link_train.lt_state = START;
-
-	/* Process here */
-	while (!retval && !training_finished) {
-		switch (dp->link_train.lt_state) {
-		case START:
-			retval = exynos_dp_link_start(dp);
-			if (retval)
-				dev_err(dp->dev, "LT link start failed!\n");
-			break;
-		case CLOCK_RECOVERY:
-			retval = exynos_dp_process_clock_recovery(dp);
-			if (retval)
-				dev_err(dp->dev, "LT CR failed!\n");
-			break;
-		case EQUALIZER_TRAINING:
-			retval = exynos_dp_process_equalizer_training(dp);
-			if (retval)
-				dev_err(dp->dev, "LT EQ failed!\n");
-			break;
-		case FINISHED:
-			training_finished = 1;
-			break;
-		case FAILED:
-			return -EREMOTEIO;
-		}
-	}
-	if (retval)
-		dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
-
-	return retval;
-}
-
-static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
-				u32 count,
-				u32 bwtype)
-{
-	int i;
-	int retval;
-
-	for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
-		exynos_dp_init_training(dp, count, bwtype);
-		retval = exynos_dp_sw_link_training(dp);
-		if (retval == 0)
-			break;
-
-		usleep_range(100, 110);
-	}
-
-	return retval;
-}
-
-static int exynos_dp_config_video(struct exynos_dp_device *dp)
-{
-	int retval = 0;
-	int timeout_loop = 0;
-	int done_count = 0;
-
-	exynos_dp_config_video_slave_mode(dp);
-
-	exynos_dp_set_video_color_format(dp);
-
-	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-		dev_err(dp->dev, "PLL is not locked yet.\n");
-		return -EINVAL;
-	}
-
-	for (;;) {
-		timeout_loop++;
-		if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
-			break;
-		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-			dev_err(dp->dev, "Timeout of video streamclk ok\n");
-			return -ETIMEDOUT;
-		}
-
-		usleep_range(1, 2);
-	}
-
-	/* Set to use the register calculated M/N video */
-	exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
-
-	/* For video bist, Video timing must be generated by register */
-	exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
-
-	/* Disable video mute */
-	exynos_dp_enable_video_mute(dp, 0);
-
-	/* Configure video slave mode */
-	exynos_dp_enable_video_master(dp, 0);
-
-	/* Enable video */
-	exynos_dp_start_video(dp);
-
-	timeout_loop = 0;
-
-	for (;;) {
-		timeout_loop++;
-		if (exynos_dp_is_video_stream_on(dp) == 0) {
-			done_count++;
-			if (done_count > 10)
-				break;
-		} else if (done_count) {
-			done_count = 0;
-		}
-		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-			dev_err(dp->dev, "Timeout of video streamclk ok\n");
-			return -ETIMEDOUT;
-		}
-
-		usleep_range(1000, 1001);
-	}
-
-	if (retval != 0)
-		dev_err(dp->dev, "Video stream is not detected!\n");
-
-	return retval;
-}
-
-static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
-{
-	u8 data;
-
-	if (enable) {
-		exynos_dp_enable_scrambling(dp);
-
-		exynos_dp_read_byte_from_dpcd(dp,
-			DPCD_ADDR_TRAINING_PATTERN_SET,
-			&data);
-		exynos_dp_write_byte_to_dpcd(dp,
-			DPCD_ADDR_TRAINING_PATTERN_SET,
-			(u8)(data & ~DPCD_SCRAMBLING_DISABLED));
-	} else {
-		exynos_dp_disable_scrambling(dp);
-
-		exynos_dp_read_byte_from_dpcd(dp,
-			DPCD_ADDR_TRAINING_PATTERN_SET,
-			&data);
-		exynos_dp_write_byte_to_dpcd(dp,
-			DPCD_ADDR_TRAINING_PATTERN_SET,
-			(u8)(data | DPCD_SCRAMBLING_DISABLED));
-	}
-}
-
-static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
-{
-	struct exynos_dp_device *dp = arg;
-
-	enum dp_irq_type irq_type;
-
-	irq_type = exynos_dp_get_irq_type(dp);
-	switch (irq_type) {
-	case DP_IRQ_TYPE_HP_CABLE_IN:
-		dev_dbg(dp->dev, "Received irq - cable in\n");
-		schedule_work(&dp->hotplug_work);
-		exynos_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CABLE_OUT:
-		dev_dbg(dp->dev, "Received irq - cable out\n");
-		exynos_dp_clear_hotplug_interrupts(dp);
-		break;
-	case DP_IRQ_TYPE_HP_CHANGE:
-		/*
-		 * We get these change notifications once in a while, but there
-		 * is nothing we can do with them. Just ignore it for now and
-		 * only handle cable changes.
-		 */
-		dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
-		exynos_dp_clear_hotplug_interrupts(dp);
-		break;
-	default:
-		dev_err(dp->dev, "Received irq - unknown type!\n");
-		break;
-	}
-	return IRQ_HANDLED;
-}
-
-static void exynos_dp_hotplug(struct work_struct *work)
-{
-	struct exynos_dp_device *dp;
-	int ret;
-
-	dp = container_of(work, struct exynos_dp_device, hotplug_work);
-
-	ret = exynos_dp_detect_hpd(dp);
-	if (ret) {
-		/* Cable has been disconnected, we're done */
-		return;
-	}
-
-	ret = exynos_dp_handle_edid(dp);
-	if (ret) {
-		dev_err(dp->dev, "unable to handle edid\n");
-		return;
-	}
-
-	ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
-					dp->video_info->link_rate);
-	if (ret) {
-		dev_err(dp->dev, "unable to do link train\n");
-		return;
-	}
-
-	exynos_dp_enable_scramble(dp, 1);
-	exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
-	exynos_dp_enable_enhanced_mode(dp, 1);
-
-	exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
-	exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
-
-	exynos_dp_init_video(dp);
-	ret = exynos_dp_config_video(dp);
-	if (ret)
-		dev_err(dp->dev, "unable to config video\n");
-}
-
-#ifdef CONFIG_OF
-static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
-{
-	struct device_node *dp_node = dev->of_node;
-	struct exynos_dp_platdata *pd;
-	struct video_info *dp_video_config;
-
-	pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
-	if (!pd) {
-		dev_err(dev, "memory allocation for pdata failed\n");
-		return ERR_PTR(-ENOMEM);
-	}
-	dp_video_config = devm_kzalloc(dev,
-				sizeof(*dp_video_config), GFP_KERNEL);
-
-	if (!dp_video_config) {
-		dev_err(dev, "memory allocation for video config failed\n");
-		return ERR_PTR(-ENOMEM);
-	}
-	pd->video_info = dp_video_config;
-
-	dp_video_config->h_sync_polarity =
-		of_property_read_bool(dp_node, "hsync-active-high");
-
-	dp_video_config->v_sync_polarity =
-		of_property_read_bool(dp_node, "vsync-active-high");
-
-	dp_video_config->interlaced =
-		of_property_read_bool(dp_node, "interlaced");
-
-	if (of_property_read_u32(dp_node, "samsung,color-space",
-				&dp_video_config->color_space)) {
-		dev_err(dev, "failed to get color-space\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (of_property_read_u32(dp_node, "samsung,dynamic-range",
-				&dp_video_config->dynamic_range)) {
-		dev_err(dev, "failed to get dynamic-range\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
-				&dp_video_config->ycbcr_coeff)) {
-		dev_err(dev, "failed to get ycbcr-coeff\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (of_property_read_u32(dp_node, "samsung,color-depth",
-				&dp_video_config->color_depth)) {
-		dev_err(dev, "failed to get color-depth\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (of_property_read_u32(dp_node, "samsung,link-rate",
-				&dp_video_config->link_rate)) {
-		dev_err(dev, "failed to get link-rate\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	if (of_property_read_u32(dp_node, "samsung,lane-count",
-				&dp_video_config->lane_count)) {
-		dev_err(dev, "failed to get lane-count\n");
-		return ERR_PTR(-EINVAL);
-	}
-
-	return pd;
-}
-
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
-	struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
-	u32 phy_base;
-	int ret = 0;
-
-	dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
-	if (!dp_phy_node) {
-		dev_err(dp->dev, "could not find dptx-phy node\n");
-		return -ENODEV;
-	}
-
-	if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
-		dev_err(dp->dev, "failed to get reg for dptx-phy\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
-				&dp->enable_mask)) {
-		dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
-		ret = -EINVAL;
-		goto err;
-	}
-
-	dp->phy_addr = ioremap(phy_base, SZ_4);
-	if (!dp->phy_addr) {
-		dev_err(dp->dev, "failed to ioremap dp-phy\n");
-		ret = -ENOMEM;
-		goto err;
-	}
-
-err:
-	of_node_put(dp_phy_node);
-
-	return ret;
-}
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = __raw_readl(dp->phy_addr);
-	reg |= dp->enable_mask;
-	__raw_writel(reg, dp->phy_addr);
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = __raw_readl(dp->phy_addr);
-	reg &= ~(dp->enable_mask);
-	__raw_writel(reg, dp->phy_addr);
-}
-#else
-static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
-{
-	return NULL;
-}
-
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
-	return -EINVAL;
-}
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
-	return;
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
-	return;
-}
-#endif /* CONFIG_OF */
-
-static int exynos_dp_probe(struct platform_device *pdev)
-{
-	struct resource *res;
-	struct exynos_dp_device *dp;
-	struct exynos_dp_platdata *pdata;
-
-	int ret = 0;
-
-	dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
-				GFP_KERNEL);
-	if (!dp) {
-		dev_err(&pdev->dev, "no memory for device data\n");
-		return -ENOMEM;
-	}
-
-	dp->dev = &pdev->dev;
-
-	if (pdev->dev.of_node) {
-		pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
-		if (IS_ERR(pdata))
-			return PTR_ERR(pdata);
-
-		ret = exynos_dp_dt_parse_phydata(dp);
-		if (ret)
-			return ret;
-	} else {
-		pdata = pdev->dev.platform_data;
-		if (!pdata) {
-			dev_err(&pdev->dev, "no platform data\n");
-			return -EINVAL;
-		}
-	}
-
-	dp->clock = devm_clk_get(&pdev->dev, "dp");
-	if (IS_ERR(dp->clock)) {
-		dev_err(&pdev->dev, "failed to get clock\n");
-		return PTR_ERR(dp->clock);
-	}
-
-	clk_prepare_enable(dp->clock);
-
-	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-	dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(dp->reg_base))
-		return PTR_ERR(dp->reg_base);
-
-	dp->irq = platform_get_irq(pdev, 0);
-	if (dp->irq == -ENXIO) {
-		dev_err(&pdev->dev, "failed to get irq\n");
-		return -ENODEV;
-	}
-
-	INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
-
-	dp->video_info = pdata->video_info;
-
-	if (pdev->dev.of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_init(dp);
-	} else {
-		if (pdata->phy_init)
-			pdata->phy_init();
-	}
-
-	exynos_dp_init_dp(dp);
-
-	ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
-				"exynos-dp", dp);
-	if (ret) {
-		dev_err(&pdev->dev, "failed to request irq\n");
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, dp);
-
-	return 0;
-}
-
-static int exynos_dp_remove(struct platform_device *pdev)
-{
-	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
-	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
-
-	flush_work(&dp->hotplug_work);
-
-	if (pdev->dev.of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_exit(dp);
-	} else {
-		if (pdata->phy_exit)
-			pdata->phy_exit();
-	}
-
-	clk_disable_unprepare(dp->clock);
-
-
-	return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos_dp_suspend(struct device *dev)
-{
-	struct exynos_dp_platdata *pdata = dev->platform_data;
-	struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
-	disable_irq(dp->irq);
-
-	flush_work(&dp->hotplug_work);
-
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_exit(dp);
-	} else {
-		if (pdata->phy_exit)
-			pdata->phy_exit();
-	}
-
-	clk_disable_unprepare(dp->clock);
-
-	return 0;
-}
-
-static int exynos_dp_resume(struct device *dev)
-{
-	struct exynos_dp_platdata *pdata = dev->platform_data;
-	struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_init(dp);
-	} else {
-		if (pdata->phy_init)
-			pdata->phy_init();
-	}
-
-	clk_prepare_enable(dp->clock);
-
-	exynos_dp_init_dp(dp);
-
-	enable_irq(dp->irq);
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops exynos_dp_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
-};
-
-static const struct of_device_id exynos_dp_match[] = {
-	{ .compatible = "samsung,exynos5-dp" },
-	{},
-};
-MODULE_DEVICE_TABLE(of, exynos_dp_match);
-
-static struct platform_driver exynos_dp_driver = {
-	.probe		= exynos_dp_probe,
-	.remove		= exynos_dp_remove,
-	.driver		= {
-		.name	= "exynos-dp",
-		.owner	= THIS_MODULE,
-		.pm	= &exynos_dp_pm_ops,
-		.of_match_table = of_match_ptr(exynos_dp_match),
-	},
-};
-
-module_platform_driver(exynos_dp_driver);
-
-MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DP Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
deleted file mode 100644
index 6c567bbf..0000000
--- a/drivers/video/exynos/exynos_dp_core.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Header file for Samsung DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DP_CORE_H
-#define _EXYNOS_DP_CORE_H
-
-enum dp_irq_type {
-	DP_IRQ_TYPE_HP_CABLE_IN,
-	DP_IRQ_TYPE_HP_CABLE_OUT,
-	DP_IRQ_TYPE_HP_CHANGE,
-	DP_IRQ_TYPE_UNKNOWN,
-};
-
-struct link_train {
-	int eq_loop;
-	int cr_loop[4];
-
-	u8 link_rate;
-	u8 lane_count;
-	u8 training_lane[4];
-
-	enum link_training_state lt_state;
-};
-
-struct exynos_dp_device {
-	struct device		*dev;
-	struct clk		*clock;
-	unsigned int		irq;
-	void __iomem		*reg_base;
-	void __iomem		*phy_addr;
-	unsigned int		enable_mask;
-
-	struct video_info	*video_info;
-	struct link_train	link_train;
-	struct work_struct	hotplug_work;
-};
-
-/* exynos_dp_reg.c */
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_stop_video(struct exynos_dp_device *dp);
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
-void exynos_dp_reset(struct exynos_dp_device *dp);
-void exynos_dp_swreset(struct exynos_dp_device *dp);
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
-				enum analog_power_block block,
-				bool enable);
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
-void exynos_dp_init_hpd(struct exynos_dp_device *dp);
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
-void exynos_dp_reset_aux(struct exynos_dp_device *dp);
-void exynos_dp_init_aux(struct exynos_dp_device *dp);
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned char data);
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned char *data);
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char data[]);
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char data[]);
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr);
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr,
-				unsigned int *data);
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char edid[]);
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
-				 enum pattern_set pattern);
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
-				u32 training_lane);
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
-				u32 training_lane);
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
-				u32 training_lane);
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
-				u32 training_lane);
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
-void exynos_dp_reset_macro(struct exynos_dp_device *dp);
-void exynos_dp_init_video(struct exynos_dp_device *dp);
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
-			enum clock_recovery_m_value_type type,
-			u32 m_value,
-			u32 n_value);
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_start_video(struct exynos_dp_device *dp);
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
-
-/* I2C EDID Chip ID, Slave Address */
-#define I2C_EDID_DEVICE_ADDR			0x50
-#define I2C_E_EDID_DEVICE_ADDR			0x30
-
-#define EDID_BLOCK_LENGTH			0x80
-#define EDID_HEADER_PATTERN			0x00
-#define EDID_EXTENSION_FLAG			0x7e
-#define EDID_CHECKSUM				0x7f
-
-/* Definition for DPCD Register */
-#define DPCD_ADDR_DPCD_REV			0x0000
-#define DPCD_ADDR_MAX_LINK_RATE			0x0001
-#define DPCD_ADDR_MAX_LANE_COUNT		0x0002
-#define DPCD_ADDR_LINK_BW_SET			0x0100
-#define DPCD_ADDR_LANE_COUNT_SET		0x0101
-#define DPCD_ADDR_TRAINING_PATTERN_SET		0x0102
-#define DPCD_ADDR_TRAINING_LANE0_SET		0x0103
-#define DPCD_ADDR_LANE0_1_STATUS		0x0202
-#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED	0x0204
-#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1	0x0206
-#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3	0x0207
-#define DPCD_ADDR_TEST_REQUEST			0x0218
-#define DPCD_ADDR_TEST_RESPONSE			0x0260
-#define DPCD_ADDR_TEST_EDID_CHECKSUM		0x0261
-#define DPCD_ADDR_SINK_POWER_STATE		0x0600
-
-/* DPCD_ADDR_MAX_LANE_COUNT */
-#define DPCD_ENHANCED_FRAME_CAP(x)		(((x) >> 7) & 0x1)
-#define DPCD_MAX_LANE_COUNT(x)			((x) & 0x1f)
-
-/* DPCD_ADDR_LANE_COUNT_SET */
-#define DPCD_ENHANCED_FRAME_EN			(0x1 << 7)
-#define DPCD_LANE_COUNT_SET(x)			((x) & 0x1f)
-
-/* DPCD_ADDR_TRAINING_PATTERN_SET */
-#define DPCD_SCRAMBLING_DISABLED		(0x1 << 5)
-#define DPCD_SCRAMBLING_ENABLED			(0x0 << 5)
-#define DPCD_TRAINING_PATTERN_2			(0x2 << 0)
-#define DPCD_TRAINING_PATTERN_1			(0x1 << 0)
-#define DPCD_TRAINING_PATTERN_DISABLED		(0x0 << 0)
-
-/* DPCD_ADDR_TRAINING_LANE0_SET */
-#define DPCD_MAX_PRE_EMPHASIS_REACHED		(0x1 << 5)
-#define DPCD_PRE_EMPHASIS_SET(x)		(((x) & 0x3) << 3)
-#define DPCD_PRE_EMPHASIS_GET(x)		(((x) >> 3) & 0x3)
-#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0	(0x0 << 3)
-#define DPCD_MAX_SWING_REACHED			(0x1 << 2)
-#define DPCD_VOLTAGE_SWING_SET(x)		(((x) & 0x3) << 0)
-#define DPCD_VOLTAGE_SWING_GET(x)		(((x) >> 0) & 0x3)
-#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0	(0x0 << 0)
-
-/* DPCD_ADDR_LANE0_1_STATUS */
-#define DPCD_LANE_SYMBOL_LOCKED			(0x1 << 2)
-#define DPCD_LANE_CHANNEL_EQ_DONE		(0x1 << 1)
-#define DPCD_LANE_CR_DONE			(0x1 << 0)
-#define DPCD_CHANNEL_EQ_BITS			(DPCD_LANE_CR_DONE|	\
-						 DPCD_LANE_CHANNEL_EQ_DONE|\
-						 DPCD_LANE_SYMBOL_LOCKED)
-
-/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
-#define DPCD_LINK_STATUS_UPDATED		(0x1 << 7)
-#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED	(0x1 << 6)
-#define DPCD_INTERLANE_ALIGN_DONE		(0x1 << 0)
-
-/* DPCD_ADDR_TEST_REQUEST */
-#define DPCD_TEST_EDID_READ			(0x1 << 2)
-
-/* DPCD_ADDR_TEST_RESPONSE */
-#define DPCD_TEST_EDID_CHECKSUM_WRITE		(0x1 << 2)
-
-/* DPCD_ADDR_SINK_POWER_STATE */
-#define DPCD_SET_POWER_STATE_D0			(0x1 << 0)
-#define DPCD_SET_POWER_STATE_D4			(0x2 << 0)
-
-#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
deleted file mode 100644
index 29d9d03..0000000
--- a/drivers/video/exynos/exynos_dp_reg.c
+++ /dev/null
@@ -1,1245 +0,0 @@
-/*
- * Samsung DP (Display port) register interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include <video/exynos_dp.h>
-
-#include "exynos_dp_core.h"
-#include "exynos_dp_reg.h"
-
-#define COMMON_INT_MASK_1	0
-#define COMMON_INT_MASK_2	0
-#define COMMON_INT_MASK_3	0
-#define COMMON_INT_MASK_4	(HOTPLUG_CHG | HPD_LOST | PLUG)
-#define INT_STA_MASK		INT_HPD
-
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
-{
-	u32 reg;
-
-	if (enable) {
-		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-		reg |= HDCP_VIDEO_MUTE;
-		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-	} else {
-		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-		reg &= ~HDCP_VIDEO_MUTE;
-		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-	}
-}
-
-void exynos_dp_stop_video(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-	reg &= ~VIDEO_EN;
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
-{
-	u32 reg;
-
-	if (enable)
-		reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
-			LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
-	else
-		reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
-			LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
-
-	writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
-}
-
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = TX_TERMINAL_CTRL_50_OHM;
-	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
-
-	reg = SEL_24M | TX_DVDD_BIT_1_0625V;
-	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
-
-	reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
-	writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
-
-	reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
-		TX_CUR1_2X | TX_CUR_16_MA;
-	writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
-
-	reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
-		CH1_AMP_400_MV | CH0_AMP_400_MV;
-	writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
-}
-
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
-{
-	/* Set interrupt pin assertion polarity as high */
-	writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
-
-	/* Clear pending regisers */
-	writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-	writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
-	writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
-	writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-	writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
-
-	/* 0:mask,1: unmask */
-	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
-	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
-	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
-	writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
-	writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-void exynos_dp_reset(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	exynos_dp_stop_video(dp);
-	exynos_dp_enable_video_mute(dp, 0);
-
-	reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
-		AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
-		HDCP_FUNC_EN_N | SW_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
-	reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
-		SERDES_FIFO_FUNC_EN_N |
-		LS_CLK_DOMAIN_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-
-	usleep_range(20, 30);
-
-	exynos_dp_lane_swap(dp, 0);
-
-	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-	writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-	writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
-	writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
-	writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
-
-	writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
-	writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
-
-	writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
-
-	writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
-	writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
-	writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
-
-	writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
-	writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
-
-	writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_swreset(struct exynos_dp_device *dp)
-{
-	writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
-}
-
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	/* 0: mask, 1: unmask */
-	reg = COMMON_INT_MASK_1;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
-
-	reg = COMMON_INT_MASK_2;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
-
-	reg = COMMON_INT_MASK_3;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
-
-	reg = COMMON_INT_MASK_4;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
-
-	reg = INT_STA_MASK;
-	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-	if (reg & PLL_LOCK)
-		return PLL_LOCKED;
-	else
-		return PLL_UNLOCKED;
-}
-
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
-{
-	u32 reg;
-
-	if (enable) {
-		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
-		reg |= DP_PLL_PD;
-		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
-	} else {
-		reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
-		reg &= ~DP_PLL_PD;
-		writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
-	}
-}
-
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
-				enum analog_power_block block,
-				bool enable)
-{
-	u32 reg;
-
-	switch (block) {
-	case AUX_BLOCK:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= AUX_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~AUX_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case CH0_BLOCK:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= CH0_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~CH0_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case CH1_BLOCK:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= CH1_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~CH1_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case CH2_BLOCK:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= CH2_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~CH2_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case CH3_BLOCK:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= CH3_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~CH3_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case ANALOG_TOTAL:
-		if (enable) {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg |= DP_PHY_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-			reg &= ~DP_PHY_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	case POWER_ALL:
-		if (enable) {
-			reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
-				CH1_PD | CH0_PD;
-			writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-		} else {
-			writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
-		}
-		break;
-	default:
-		break;
-	}
-}
-
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
-{
-	u32 reg;
-	int timeout_loop = 0;
-
-	exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-
-	reg = PLL_LOCK_CHG;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-	reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
-	writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-
-	/* Power up PLL */
-	if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-		exynos_dp_set_pll_power_down(dp, 0);
-
-		while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-			timeout_loop++;
-			if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-				dev_err(dp->dev, "failed to get pll lock status\n");
-				return;
-			}
-			usleep_range(10, 20);
-		}
-	}
-
-	/* Enable Serdes FIFO function and Link symbol clock domain module */
-	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-	reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
-		| AUX_FUNC_EN_N);
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = HOTPLUG_CHG | HPD_LOST | PLUG;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
-	reg = INT_HPD;
-	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-}
-
-void exynos_dp_init_hpd(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	exynos_dp_clear_hotplug_interrupts(dp);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-	reg &= ~(F_HPD | HPD_CTRL);
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-}
-
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	/* Parse hotplug interrupt status register */
-	reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
-	if (reg & PLUG)
-		return DP_IRQ_TYPE_HP_CABLE_IN;
-
-	if (reg & HPD_LOST)
-		return DP_IRQ_TYPE_HP_CABLE_OUT;
-
-	if (reg & HOTPLUG_CHG)
-		return DP_IRQ_TYPE_HP_CHANGE;
-
-	return DP_IRQ_TYPE_UNKNOWN;
-}
-
-void exynos_dp_reset_aux(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	/* Disable AUX channel module */
-	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-	reg |= AUX_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_init_aux(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	/* Clear inerrupts related to AUX channel */
-	reg = RPLY_RECEIV | AUX_ERR;
-	writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-
-	exynos_dp_reset_aux(dp);
-
-	/* Disable AUX transaction H/W retry */
-	reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
-		AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
-	writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
-
-	/* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
-	reg = DEFER_CTRL_EN | DEFER_COUNT(1);
-	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
-
-	/* Enable AUX channel module */
-	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-	reg &= ~AUX_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-	if (reg & HPD_STATUS)
-		return 0;
-
-	return -EINVAL;
-}
-
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-	reg &= ~SW_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-}
-
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
-{
-	int reg;
-	int retval = 0;
-	int timeout_loop = 0;
-
-	/* Enable AUX CH operation */
-	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-	reg |= AUX_EN;
-	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
-	/* Is AUX CH command reply received? */
-	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-	while (!(reg & RPLY_RECEIV)) {
-		timeout_loop++;
-		if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-			dev_err(dp->dev, "AUX CH command reply failed!\n");
-			return -ETIMEDOUT;
-		}
-		reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-		usleep_range(10, 11);
-	}
-
-	/* Clear interrupt source for AUX CH command reply */
-	writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
-
-	/* Clear interrupt source for AUX CH access error */
-	reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-	if (reg & AUX_ERR) {
-		writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
-		return -EREMOTEIO;
-	}
-
-	/* Check AUX CH error access status */
-	reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
-	if ((reg & AUX_STATUS_MASK) != 0) {
-		dev_err(dp->dev, "AUX CH error happens: %d\n\n",
-			reg & AUX_STATUS_MASK);
-		return -EREMOTEIO;
-	}
-
-	return retval;
-}
-
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned char data)
-{
-	u32 reg;
-	int i;
-	int retval;
-
-	for (i = 0; i < 3; i++) {
-		/* Clear AUX CH data buffer */
-		reg = BUF_CLR;
-		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-		/* Select DPCD device address */
-		reg = AUX_ADDR_7_0(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-		reg = AUX_ADDR_15_8(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-		reg = AUX_ADDR_19_16(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-		/* Write data buffer */
-		reg = (unsigned int)data;
-		writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-		/*
-		 * Set DisplayPort transaction and write 1 byte
-		 * If bit 3 is 1, DisplayPort transaction.
-		 * If Bit 3 is 0, I2C transaction.
-		 */
-		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-		/* Start AUX transaction */
-		retval = exynos_dp_start_aux_transaction(dp);
-		if (retval == 0)
-			break;
-		else
-			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-				__func__);
-	}
-
-	return retval;
-}
-
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned char *data)
-{
-	u32 reg;
-	int i;
-	int retval;
-
-	for (i = 0; i < 3; i++) {
-		/* Clear AUX CH data buffer */
-		reg = BUF_CLR;
-		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-		/* Select DPCD device address */
-		reg = AUX_ADDR_7_0(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-		reg = AUX_ADDR_15_8(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-		reg = AUX_ADDR_19_16(reg_addr);
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-		/*
-		 * Set DisplayPort transaction and read 1 byte
-		 * If bit 3 is 1, DisplayPort transaction.
-		 * If Bit 3 is 0, I2C transaction.
-		 */
-		reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-		/* Start AUX transaction */
-		retval = exynos_dp_start_aux_transaction(dp);
-		if (retval == 0)
-			break;
-		else
-			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-				__func__);
-	}
-
-	/* Read data buffer */
-	reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-	*data = (unsigned char)(reg & 0xff);
-
-	return retval;
-}
-
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char data[])
-{
-	u32 reg;
-	unsigned int start_offset;
-	unsigned int cur_data_count;
-	unsigned int cur_data_idx;
-	int i;
-	int retval = 0;
-
-	/* Clear AUX CH data buffer */
-	reg = BUF_CLR;
-	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-	start_offset = 0;
-	while (start_offset < count) {
-		/* Buffer size of AUX CH is 16 * 4bytes */
-		if ((count - start_offset) > 16)
-			cur_data_count = 16;
-		else
-			cur_data_count = count - start_offset;
-
-		for (i = 0; i < 3; i++) {
-			/* Select DPCD device address */
-			reg = AUX_ADDR_7_0(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-			reg = AUX_ADDR_15_8(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-			reg = AUX_ADDR_19_16(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-			for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-			     cur_data_idx++) {
-				reg = data[start_offset + cur_data_idx];
-				writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
-							  + 4 * cur_data_idx);
-			}
-
-			/*
-			 * Set DisplayPort transaction and write
-			 * If bit 3 is 1, DisplayPort transaction.
-			 * If Bit 3 is 0, I2C transaction.
-			 */
-			reg = AUX_LENGTH(cur_data_count) |
-				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-			/* Start AUX transaction */
-			retval = exynos_dp_start_aux_transaction(dp);
-			if (retval == 0)
-				break;
-			else
-				dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-					__func__);
-		}
-
-		start_offset += cur_data_count;
-	}
-
-	return retval;
-}
-
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char data[])
-{
-	u32 reg;
-	unsigned int start_offset;
-	unsigned int cur_data_count;
-	unsigned int cur_data_idx;
-	int i;
-	int retval = 0;
-
-	/* Clear AUX CH data buffer */
-	reg = BUF_CLR;
-	writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-	start_offset = 0;
-	while (start_offset < count) {
-		/* Buffer size of AUX CH is 16 * 4bytes */
-		if ((count - start_offset) > 16)
-			cur_data_count = 16;
-		else
-			cur_data_count = count - start_offset;
-
-		/* AUX CH Request Transaction process */
-		for (i = 0; i < 3; i++) {
-			/* Select DPCD device address */
-			reg = AUX_ADDR_7_0(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-			reg = AUX_ADDR_15_8(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-			reg = AUX_ADDR_19_16(reg_addr + start_offset);
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-			/*
-			 * Set DisplayPort transaction and read
-			 * If bit 3 is 1, DisplayPort transaction.
-			 * If Bit 3 is 0, I2C transaction.
-			 */
-			reg = AUX_LENGTH(cur_data_count) |
-				AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-			/* Start AUX transaction */
-			retval = exynos_dp_start_aux_transaction(dp);
-			if (retval == 0)
-				break;
-			else
-				dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-					__func__);
-		}
-
-		for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-		    cur_data_idx++) {
-			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
-						 + 4 * cur_data_idx);
-			data[start_offset + cur_data_idx] =
-				(unsigned char)reg;
-		}
-
-		start_offset += cur_data_count;
-	}
-
-	return retval;
-}
-
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr)
-{
-	u32 reg;
-	int retval;
-
-	/* Set EDID device address */
-	reg = device_addr;
-	writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-	writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-	/* Set offset from base address of EDID device */
-	writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-	/*
-	 * Set I2C transaction and write address
-	 * If bit 3 is 1, DisplayPort transaction.
-	 * If Bit 3 is 0, I2C transaction.
-	 */
-	reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
-		AUX_TX_COMM_WRITE;
-	writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-	/* Start AUX transaction */
-	retval = exynos_dp_start_aux_transaction(dp);
-	if (retval != 0)
-		dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-
-	return retval;
-}
-
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr,
-				unsigned int *data)
-{
-	u32 reg;
-	int i;
-	int retval;
-
-	for (i = 0; i < 3; i++) {
-		/* Clear AUX CH data buffer */
-		reg = BUF_CLR;
-		writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-		/* Select EDID device */
-		retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
-		if (retval != 0)
-			continue;
-
-		/*
-		 * Set I2C transaction and read data
-		 * If bit 3 is 1, DisplayPort transaction.
-		 * If Bit 3 is 0, I2C transaction.
-		 */
-		reg = AUX_TX_COMM_I2C_TRANSACTION |
-			AUX_TX_COMM_READ;
-		writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-		/* Start AUX transaction */
-		retval = exynos_dp_start_aux_transaction(dp);
-		if (retval == 0)
-			break;
-		else
-			dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-				__func__);
-	}
-
-	/* Read data */
-	if (retval == 0)
-		*data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-	return retval;
-}
-
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
-				unsigned int device_addr,
-				unsigned int reg_addr,
-				unsigned int count,
-				unsigned char edid[])
-{
-	u32 reg;
-	unsigned int i, j;
-	unsigned int cur_data_idx;
-	unsigned int defer = 0;
-	int retval = 0;
-
-	for (i = 0; i < count; i += 16) {
-		for (j = 0; j < 3; j++) {
-			/* Clear AUX CH data buffer */
-			reg = BUF_CLR;
-			writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-			/* Set normal AUX CH command */
-			reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-			reg &= ~ADDR_ONLY;
-			writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
-			/*
-			 * If Rx sends defer, Tx sends only reads
-			 * request without sending address
-			 */
-			if (!defer)
-				retval = exynos_dp_select_i2c_device(dp,
-						device_addr, reg_addr + i);
-			else
-				defer = 0;
-
-			if (retval == 0) {
-				/*
-				 * Set I2C transaction and write data
-				 * If bit 3 is 1, DisplayPort transaction.
-				 * If Bit 3 is 0, I2C transaction.
-				 */
-				reg = AUX_LENGTH(16) |
-					AUX_TX_COMM_I2C_TRANSACTION |
-					AUX_TX_COMM_READ;
-				writel(reg, dp->reg_base +
-					EXYNOS_DP_AUX_CH_CTL_1);
-
-				/* Start AUX transaction */
-				retval = exynos_dp_start_aux_transaction(dp);
-				if (retval == 0)
-					break;
-				else
-					dev_dbg(dp->dev,
-						"%s: Aux Transaction fail!\n",
-						__func__);
-			}
-			/* Check if Rx sends defer */
-			reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
-			if (reg == AUX_RX_COMM_AUX_DEFER ||
-				reg == AUX_RX_COMM_I2C_DEFER) {
-				dev_err(dp->dev, "Defer: %d\n\n", reg);
-				defer = 1;
-			}
-		}
-
-		for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
-			reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
-						 + 4 * cur_data_idx);
-			edid[i + cur_data_idx] = (unsigned char)reg;
-		}
-	}
-
-	return retval;
-}
-
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
-{
-	u32 reg;
-
-	reg = bwtype;
-	if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
-		writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
-}
-
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
-	*bwtype = reg;
-}
-
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
-{
-	u32 reg;
-
-	reg = count;
-	writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
-}
-
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
-	*count = reg;
-}
-
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
-{
-	u32 reg;
-
-	if (enable) {
-		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-		reg |= ENHANCED;
-		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-	} else {
-		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-		reg &= ~ENHANCED;
-		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-	}
-}
-
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
-				 enum pattern_set pattern)
-{
-	u32 reg;
-
-	switch (pattern) {
-	case PRBS7:
-		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
-		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-		break;
-	case D10_2:
-		reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
-		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-		break;
-	case TRAINING_PTN1:
-		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
-		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-		break;
-	case TRAINING_PTN2:
-		reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
-		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-		break;
-	case DP_NONE:
-		reg = SCRAMBLING_ENABLE |
-			LINK_QUAL_PATTERN_SET_DISABLE |
-			SW_TRAINING_PATTERN_SET_NORMAL;
-		writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-		break;
-	default:
-		break;
-	}
-}
-
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-	reg &= ~PRE_EMPHASIS_SET_MASK;
-	reg |= level << PRE_EMPHASIS_SET_SHIFT;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-	reg &= ~PRE_EMPHASIS_SET_MASK;
-	reg |= level << PRE_EMPHASIS_SET_SHIFT;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-	reg &= ~PRE_EMPHASIS_SET_MASK;
-	reg |= level << PRE_EMPHASIS_SET_SHIFT;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-	reg &= ~PRE_EMPHASIS_SET_MASK;
-	reg |= level << PRE_EMPHASIS_SET_SHIFT;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
-					u32 training_lane)
-{
-	u32 reg;
-
-	reg = training_lane;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
-					u32 training_lane)
-{
-	u32 reg;
-
-	reg = training_lane;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
-					u32 training_lane)
-{
-	u32 reg;
-
-	reg = training_lane;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
-					u32 training_lane)
-{
-	u32 reg;
-
-	reg = training_lane;
-	writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-	return reg;
-}
-
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-	return reg;
-}
-
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-	return reg;
-}
-
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-	return reg;
-}
-
-void exynos_dp_reset_macro(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
-	reg |= MACRO_RST;
-	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
-	/* 10 us is the minimum reset time. */
-	usleep_range(10, 20);
-
-	reg &= ~MACRO_RST;
-	writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-}
-
-void exynos_dp_init_video(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
-	writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
-	reg = 0x0;
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-	reg = CHA_CRI(4) | CHA_CTRL;
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
-	reg = 0x0;
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
-	reg = VID_HRES_TH(2) | VID_VRES_TH(0);
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
-}
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	/* Configure the input color depth, color space, dynamic range */
-	reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
-		(dp->video_info->color_depth << IN_BPC_SHIFT) |
-		(dp->video_info->color_space << IN_COLOR_F_SHIFT);
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
-
-	/* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
-	reg &= ~IN_YC_COEFFI_MASK;
-	if (dp->video_info->ycbcr_coeff)
-		reg |= IN_YC_COEFFI_ITU709;
-	else
-		reg |= IN_YC_COEFFI_ITU601;
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
-}
-
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-	if (!(reg & DET_STA)) {
-		dev_dbg(dp->dev, "Input stream clock not detected.\n");
-		return -EINVAL;
-	}
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-	dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
-
-	if (reg & CHA_STA) {
-		dev_dbg(dp->dev, "Input stream clk is changing\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
-		enum clock_recovery_m_value_type type,
-		u32 m_value,
-		u32 n_value)
-{
-	u32 reg;
-
-	if (type == REGISTER_M) {
-		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-		reg |= FIX_M_VID;
-		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-		reg = m_value & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
-		reg = (m_value >> 8) & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
-		reg = (m_value >> 16) & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
-
-		reg = n_value & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
-		reg = (n_value >> 8) & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
-		reg = (n_value >> 16) & 0xff;
-		writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
-	} else  {
-		reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-		reg &= ~FIX_M_VID;
-		writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
-		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
-		writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
-		writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
-	}
-}
-
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
-{
-	u32 reg;
-
-	if (type == VIDEO_TIMING_FROM_CAPTURE) {
-		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-		reg &= ~FORMAT_SEL;
-		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-	} else {
-		reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-		reg |= FORMAT_SEL;
-		writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-	}
-}
-
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
-{
-	u32 reg;
-
-	if (enable) {
-		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-		reg &= ~VIDEO_MODE_MASK;
-		reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
-		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-	} else {
-		reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-		reg &= ~VIDEO_MODE_MASK;
-		reg |= VIDEO_MODE_SLAVE_MODE;
-		writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-	}
-}
-
-void exynos_dp_start_video(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-	reg |= VIDEO_EN;
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-	writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-	if (!(reg & STRM_VALID)) {
-		dev_dbg(dp->dev, "Input video stream is not detected.\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-	reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
-	reg |= MASTER_VID_FUNC_EN_N;
-	writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-	reg &= ~INTERACE_SCAN_CFG;
-	reg |= (dp->video_info->interlaced << 2);
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-	reg &= ~VSYNC_POLARITY_CFG;
-	reg |= (dp->video_info->v_sync_polarity << 1);
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-	reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-	reg &= ~HSYNC_POLARITY_CFG;
-	reg |= (dp->video_info->h_sync_polarity << 0);
-	writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-	reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
-	writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-	reg &= ~SCRAMBLING_DISABLE;
-	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
-
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-	reg |= SCRAMBLING_DISABLE;
-	writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
deleted file mode 100644
index 2e9bd0e..0000000
--- a/drivers/video/exynos/exynos_dp_reg.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Register definition file for Samsung DP driver
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _EXYNOS_DP_REG_H
-#define _EXYNOS_DP_REG_H
-
-#define EXYNOS_DP_TX_SW_RESET			0x14
-#define EXYNOS_DP_FUNC_EN_1			0x18
-#define EXYNOS_DP_FUNC_EN_2			0x1C
-#define EXYNOS_DP_VIDEO_CTL_1			0x20
-#define EXYNOS_DP_VIDEO_CTL_2			0x24
-#define EXYNOS_DP_VIDEO_CTL_3			0x28
-
-#define EXYNOS_DP_VIDEO_CTL_8			0x3C
-#define EXYNOS_DP_VIDEO_CTL_10			0x44
-
-#define EXYNOS_DP_LANE_MAP			0x35C
-
-#define EXYNOS_DP_ANALOG_CTL_1			0x370
-#define EXYNOS_DP_ANALOG_CTL_2			0x374
-#define EXYNOS_DP_ANALOG_CTL_3			0x378
-#define EXYNOS_DP_PLL_FILTER_CTL_1		0x37C
-#define EXYNOS_DP_TX_AMP_TUNING_CTL		0x380
-
-#define EXYNOS_DP_AUX_HW_RETRY_CTL		0x390
-
-#define EXYNOS_DP_COMMON_INT_STA_1		0x3C4
-#define EXYNOS_DP_COMMON_INT_STA_2		0x3C8
-#define EXYNOS_DP_COMMON_INT_STA_3		0x3CC
-#define EXYNOS_DP_COMMON_INT_STA_4		0x3D0
-#define EXYNOS_DP_INT_STA			0x3DC
-#define EXYNOS_DP_COMMON_INT_MASK_1		0x3E0
-#define EXYNOS_DP_COMMON_INT_MASK_2		0x3E4
-#define EXYNOS_DP_COMMON_INT_MASK_3		0x3E8
-#define EXYNOS_DP_COMMON_INT_MASK_4		0x3EC
-#define EXYNOS_DP_INT_STA_MASK			0x3F8
-#define EXYNOS_DP_INT_CTL			0x3FC
-
-#define EXYNOS_DP_SYS_CTL_1			0x600
-#define EXYNOS_DP_SYS_CTL_2			0x604
-#define EXYNOS_DP_SYS_CTL_3			0x608
-#define EXYNOS_DP_SYS_CTL_4			0x60C
-
-#define EXYNOS_DP_PKT_SEND_CTL			0x640
-#define EXYNOS_DP_HDCP_CTL			0x648
-
-#define EXYNOS_DP_LINK_BW_SET			0x680
-#define EXYNOS_DP_LANE_COUNT_SET		0x684
-#define EXYNOS_DP_TRAINING_PTN_SET		0x688
-#define EXYNOS_DP_LN0_LINK_TRAINING_CTL		0x68C
-#define EXYNOS_DP_LN1_LINK_TRAINING_CTL		0x690
-#define EXYNOS_DP_LN2_LINK_TRAINING_CTL		0x694
-#define EXYNOS_DP_LN3_LINK_TRAINING_CTL		0x698
-
-#define EXYNOS_DP_DEBUG_CTL			0x6C0
-#define EXYNOS_DP_HPD_DEGLITCH_L		0x6C4
-#define EXYNOS_DP_HPD_DEGLITCH_H		0x6C8
-#define EXYNOS_DP_LINK_DEBUG_CTL		0x6E0
-
-#define EXYNOS_DP_M_VID_0			0x700
-#define EXYNOS_DP_M_VID_1			0x704
-#define EXYNOS_DP_M_VID_2			0x708
-#define EXYNOS_DP_N_VID_0			0x70C
-#define EXYNOS_DP_N_VID_1			0x710
-#define EXYNOS_DP_N_VID_2			0x714
-
-#define EXYNOS_DP_PLL_CTL			0x71C
-#define EXYNOS_DP_PHY_PD			0x720
-#define EXYNOS_DP_PHY_TEST			0x724
-
-#define EXYNOS_DP_VIDEO_FIFO_THRD		0x730
-#define EXYNOS_DP_AUDIO_MARGIN			0x73C
-
-#define EXYNOS_DP_M_VID_GEN_FILTER_TH		0x764
-#define EXYNOS_DP_M_AUD_GEN_FILTER_TH		0x778
-#define EXYNOS_DP_AUX_CH_STA			0x780
-#define EXYNOS_DP_AUX_CH_DEFER_CTL		0x788
-#define EXYNOS_DP_AUX_RX_COMM			0x78C
-#define EXYNOS_DP_BUFFER_DATA_CTL		0x790
-#define EXYNOS_DP_AUX_CH_CTL_1			0x794
-#define EXYNOS_DP_AUX_ADDR_7_0			0x798
-#define EXYNOS_DP_AUX_ADDR_15_8			0x79C
-#define EXYNOS_DP_AUX_ADDR_19_16		0x7A0
-#define EXYNOS_DP_AUX_CH_CTL_2			0x7A4
-
-#define EXYNOS_DP_BUF_DATA_0			0x7C0
-
-#define EXYNOS_DP_SOC_GENERAL_CTL		0x800
-
-/* EXYNOS_DP_TX_SW_RESET */
-#define RESET_DP_TX				(0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_1 */
-#define MASTER_VID_FUNC_EN_N			(0x1 << 7)
-#define SLAVE_VID_FUNC_EN_N			(0x1 << 5)
-#define AUD_FIFO_FUNC_EN_N			(0x1 << 4)
-#define AUD_FUNC_EN_N				(0x1 << 3)
-#define HDCP_FUNC_EN_N				(0x1 << 2)
-#define CRC_FUNC_EN_N				(0x1 << 1)
-#define SW_FUNC_EN_N				(0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_2 */
-#define SSC_FUNC_EN_N				(0x1 << 7)
-#define AUX_FUNC_EN_N				(0x1 << 2)
-#define SERDES_FIFO_FUNC_EN_N			(0x1 << 1)
-#define LS_CLK_DOMAIN_FUNC_EN_N			(0x1 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define VIDEO_EN				(0x1 << 7)
-#define HDCP_VIDEO_MUTE				(0x1 << 6)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define IN_D_RANGE_MASK				(0x1 << 7)
-#define IN_D_RANGE_SHIFT			(7)
-#define IN_D_RANGE_CEA				(0x1 << 7)
-#define IN_D_RANGE_VESA				(0x0 << 7)
-#define IN_BPC_MASK				(0x7 << 4)
-#define IN_BPC_SHIFT				(4)
-#define IN_BPC_12_BITS				(0x3 << 4)
-#define IN_BPC_10_BITS				(0x2 << 4)
-#define IN_BPC_8_BITS				(0x1 << 4)
-#define IN_BPC_6_BITS				(0x0 << 4)
-#define IN_COLOR_F_MASK				(0x3 << 0)
-#define IN_COLOR_F_SHIFT			(0)
-#define IN_COLOR_F_YCBCR444			(0x2 << 0)
-#define IN_COLOR_F_YCBCR422			(0x1 << 0)
-#define IN_COLOR_F_RGB				(0x0 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_3 */
-#define IN_YC_COEFFI_MASK			(0x1 << 7)
-#define IN_YC_COEFFI_SHIFT			(7)
-#define IN_YC_COEFFI_ITU709			(0x1 << 7)
-#define IN_YC_COEFFI_ITU601			(0x0 << 7)
-#define VID_CHK_UPDATE_TYPE_MASK		(0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_SHIFT		(4)
-#define VID_CHK_UPDATE_TYPE_1			(0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_0			(0x0 << 4)
-
-/* EXYNOS_DP_VIDEO_CTL_8 */
-#define VID_HRES_TH(x)				(((x) & 0xf) << 4)
-#define VID_VRES_TH(x)				(((x) & 0xf) << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_10 */
-#define FORMAT_SEL				(0x1 << 4)
-#define INTERACE_SCAN_CFG			(0x1 << 2)
-#define VSYNC_POLARITY_CFG			(0x1 << 1)
-#define HSYNC_POLARITY_CFG			(0x1 << 0)
-
-/* EXYNOS_DP_LANE_MAP */
-#define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
-#define LANE3_MAP_LOGIC_LANE_1			(0x1 << 6)
-#define LANE3_MAP_LOGIC_LANE_2			(0x2 << 6)
-#define LANE3_MAP_LOGIC_LANE_3			(0x3 << 6)
-#define LANE2_MAP_LOGIC_LANE_0			(0x0 << 4)
-#define LANE2_MAP_LOGIC_LANE_1			(0x1 << 4)
-#define LANE2_MAP_LOGIC_LANE_2			(0x2 << 4)
-#define LANE2_MAP_LOGIC_LANE_3			(0x3 << 4)
-#define LANE1_MAP_LOGIC_LANE_0			(0x0 << 2)
-#define LANE1_MAP_LOGIC_LANE_1			(0x1 << 2)
-#define LANE1_MAP_LOGIC_LANE_2			(0x2 << 2)
-#define LANE1_MAP_LOGIC_LANE_3			(0x3 << 2)
-#define LANE0_MAP_LOGIC_LANE_0			(0x0 << 0)
-#define LANE0_MAP_LOGIC_LANE_1			(0x1 << 0)
-#define LANE0_MAP_LOGIC_LANE_2			(0x2 << 0)
-#define LANE0_MAP_LOGIC_LANE_3			(0x3 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_1 */
-#define TX_TERMINAL_CTRL_50_OHM			(0x1 << 4)
-
-/* EXYNOS_DP_ANALOG_CTL_2 */
-#define SEL_24M					(0x1 << 3)
-#define TX_DVDD_BIT_1_0625V			(0x4 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_3 */
-#define DRIVE_DVDD_BIT_1_0625V			(0x4 << 5)
-#define VCO_BIT_600_MICRO			(0x5 << 0)
-
-/* EXYNOS_DP_PLL_FILTER_CTL_1 */
-#define PD_RING_OSC				(0x1 << 6)
-#define AUX_TERMINAL_CTRL_50_OHM		(0x2 << 4)
-#define TX_CUR1_2X				(0x1 << 2)
-#define TX_CUR_16_MA				(0x3 << 0)
-
-/* EXYNOS_DP_TX_AMP_TUNING_CTL */
-#define CH3_AMP_400_MV				(0x0 << 24)
-#define CH2_AMP_400_MV				(0x0 << 16)
-#define CH1_AMP_400_MV				(0x0 << 8)
-#define CH0_AMP_400_MV				(0x0 << 0)
-
-/* EXYNOS_DP_AUX_HW_RETRY_CTL */
-#define AUX_BIT_PERIOD_EXPECTED_DELAY(x)	(((x) & 0x7) << 8)
-#define AUX_HW_RETRY_INTERVAL_MASK		(0x3 << 3)
-#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS	(0x0 << 3)
-#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS	(0x1 << 3)
-#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS	(0x2 << 3)
-#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS	(0x3 << 3)
-#define AUX_HW_RETRY_COUNT_SEL(x)		(((x) & 0x7) << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_1 */
-#define VSYNC_DET				(0x1 << 7)
-#define PLL_LOCK_CHG				(0x1 << 6)
-#define SPDIF_ERR				(0x1 << 5)
-#define SPDIF_UNSTBL				(0x1 << 4)
-#define VID_FORMAT_CHG				(0x1 << 3)
-#define AUD_CLK_CHG				(0x1 << 2)
-#define VID_CLK_CHG				(0x1 << 1)
-#define SW_INT					(0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_2 */
-#define ENC_EN_CHG				(0x1 << 6)
-#define HW_BKSV_RDY				(0x1 << 3)
-#define HW_SHA_DONE				(0x1 << 2)
-#define HW_AUTH_STATE_CHG			(0x1 << 1)
-#define HW_AUTH_DONE				(0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_3 */
-#define AFIFO_UNDER				(0x1 << 7)
-#define AFIFO_OVER				(0x1 << 6)
-#define R0_CHK_FLAG				(0x1 << 5)
-
-/* EXYNOS_DP_COMMON_INT_STA_4 */
-#define PSR_ACTIVE				(0x1 << 7)
-#define PSR_INACTIVE				(0x1 << 6)
-#define SPDIF_BI_PHASE_ERR			(0x1 << 5)
-#define HOTPLUG_CHG				(0x1 << 2)
-#define HPD_LOST				(0x1 << 1)
-#define PLUG					(0x1 << 0)
-
-/* EXYNOS_DP_INT_STA */
-#define INT_HPD					(0x1 << 6)
-#define HW_TRAINING_FINISH			(0x1 << 5)
-#define RPLY_RECEIV				(0x1 << 1)
-#define AUX_ERR					(0x1 << 0)
-
-/* EXYNOS_DP_INT_CTL */
-#define SOFT_INT_CTRL				(0x1 << 2)
-#define INT_POL1				(0x1 << 1)
-#define INT_POL0				(0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_1 */
-#define DET_STA					(0x1 << 2)
-#define FORCE_DET				(0x1 << 1)
-#define DET_CTRL				(0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_2 */
-#define CHA_CRI(x)				(((x) & 0xf) << 4)
-#define CHA_STA					(0x1 << 2)
-#define FORCE_CHA				(0x1 << 1)
-#define CHA_CTRL				(0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_3 */
-#define HPD_STATUS				(0x1 << 6)
-#define F_HPD					(0x1 << 5)
-#define HPD_CTRL				(0x1 << 4)
-#define HDCP_RDY				(0x1 << 3)
-#define STRM_VALID				(0x1 << 2)
-#define F_VALID					(0x1 << 1)
-#define VALID_CTRL				(0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_4 */
-#define FIX_M_AUD				(0x1 << 4)
-#define ENHANCED				(0x1 << 3)
-#define FIX_M_VID				(0x1 << 2)
-#define M_VID_UPDATE_CTRL			(0x3 << 0)
-
-/* EXYNOS_DP_TRAINING_PTN_SET */
-#define SCRAMBLER_TYPE				(0x1 << 9)
-#define HW_LINK_TRAINING_PATTERN		(0x1 << 8)
-#define SCRAMBLING_DISABLE			(0x1 << 5)
-#define SCRAMBLING_ENABLE			(0x0 << 5)
-#define LINK_QUAL_PATTERN_SET_MASK		(0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_PRBS7		(0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_D10_2		(0x1 << 2)
-#define LINK_QUAL_PATTERN_SET_DISABLE		(0x0 << 2)
-#define SW_TRAINING_PATTERN_SET_MASK		(0x3 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN2		(0x2 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN1		(0x1 << 0)
-#define SW_TRAINING_PATTERN_SET_NORMAL		(0x0 << 0)
-
-/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
-#define PRE_EMPHASIS_SET_MASK			(0x3 << 3)
-#define PRE_EMPHASIS_SET_SHIFT			(3)
-
-/* EXYNOS_DP_DEBUG_CTL */
-#define PLL_LOCK				(0x1 << 4)
-#define F_PLL_LOCK				(0x1 << 3)
-#define PLL_LOCK_CTRL				(0x1 << 2)
-#define PN_INV					(0x1 << 0)
-
-/* EXYNOS_DP_PLL_CTL */
-#define DP_PLL_PD				(0x1 << 7)
-#define DP_PLL_RESET				(0x1 << 6)
-#define DP_PLL_LOOP_BIT_DEFAULT			(0x1 << 4)
-#define DP_PLL_REF_BIT_1_1250V			(0x5 << 0)
-#define DP_PLL_REF_BIT_1_2500V			(0x7 << 0)
-
-/* EXYNOS_DP_PHY_PD */
-#define DP_PHY_PD				(0x1 << 5)
-#define AUX_PD					(0x1 << 4)
-#define CH3_PD					(0x1 << 3)
-#define CH2_PD					(0x1 << 2)
-#define CH1_PD					(0x1 << 1)
-#define CH0_PD					(0x1 << 0)
-
-/* EXYNOS_DP_PHY_TEST */
-#define MACRO_RST				(0x1 << 5)
-#define CH1_TEST				(0x1 << 1)
-#define CH0_TEST				(0x1 << 0)
-
-/* EXYNOS_DP_AUX_CH_STA */
-#define AUX_BUSY				(0x1 << 4)
-#define AUX_STATUS_MASK				(0xf << 0)
-
-/* EXYNOS_DP_AUX_CH_DEFER_CTL */
-#define DEFER_CTRL_EN				(0x1 << 7)
-#define DEFER_COUNT(x)				(((x) & 0x7f) << 0)
-
-/* EXYNOS_DP_AUX_RX_COMM */
-#define AUX_RX_COMM_I2C_DEFER			(0x2 << 2)
-#define AUX_RX_COMM_AUX_DEFER			(0x2 << 0)
-
-/* EXYNOS_DP_BUFFER_DATA_CTL */
-#define BUF_CLR					(0x1 << 7)
-#define BUF_DATA_COUNT(x)			(((x) & 0x1f) << 0)
-
-/* EXYNOS_DP_AUX_CH_CTL_1 */
-#define AUX_LENGTH(x)				(((x - 1) & 0xf) << 4)
-#define AUX_TX_COMM_MASK			(0xf << 0)
-#define AUX_TX_COMM_DP_TRANSACTION		(0x1 << 3)
-#define AUX_TX_COMM_I2C_TRANSACTION		(0x0 << 3)
-#define AUX_TX_COMM_MOT				(0x1 << 2)
-#define AUX_TX_COMM_WRITE			(0x0 << 0)
-#define AUX_TX_COMM_READ			(0x1 << 0)
-
-/* EXYNOS_DP_AUX_ADDR_7_0 */
-#define AUX_ADDR_7_0(x)				(((x) >> 0) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_15_8 */
-#define AUX_ADDR_15_8(x)			(((x) >> 8) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_19_16 */
-#define AUX_ADDR_19_16(x)			(((x) >> 16) & 0x0f)
-
-/* EXYNOS_DP_AUX_CH_CTL_2 */
-#define ADDR_ONLY				(0x1 << 1)
-#define AUX_EN					(0x1 << 0)
-
-/* EXYNOS_DP_SOC_GENERAL_CTL */
-#define AUDIO_MODE_SPDIF_MODE			(0x1 << 8)
-#define AUDIO_MODE_MASTER_MODE			(0x0 << 8)
-#define MASTER_VIDEO_INTERLACE_EN		(0x1 << 4)
-#define VIDEO_MASTER_CLK_SEL			(0x1 << 2)
-#define VIDEO_MASTER_MODE_EN			(0x1 << 1)
-#define VIDEO_MODE_MASK				(0x1 << 0)
-#define VIDEO_MODE_SLAVE_MODE			(0x1 << 0)
-#define VIDEO_MODE_MASTER_MODE			(0x0 << 0)
-
-#endif /* _EXYNOS_DP_REG_H */
-- 
1.8.4

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

* [PATCH v2 22/26] drm/exynos: Move display implementation into dp
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (20 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 21/26] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 23/26] ARM: dts: Move display-timings node from fimd to dp Sean Paul
                   ` (3 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch moves the exynos_drm_display implementation from fimd into
the dp driver. This will allow for tighter integration of the dp driver
into the exynos drm driver.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 .../devicetree/bindings/video/exynos_dp.txt        |  17 +++
 .../devicetree/bindings/video/samsung-fimd.txt     |   2 +
 drivers/gpu/drm/exynos/exynos_dp_core.c            | 137 ++++++++++++++++-----
 drivers/gpu/drm/exynos/exynos_dp_core.h            |   5 +
 drivers/gpu/drm/exynos/exynos_drm_drv.c            |  14 +++
 drivers/gpu/drm/exynos/exynos_drm_drv.h            |   1 +
 drivers/gpu/drm/exynos/exynos_drm_fimd.c           |  78 +++---------
 7 files changed, 156 insertions(+), 98 deletions(-)

diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt
index 84f10c1..a073e15 100644
--- a/Documentation/devicetree/bindings/video/exynos_dp.txt
+++ b/Documentation/devicetree/bindings/video/exynos_dp.txt
@@ -45,6 +45,8 @@ Required properties for dp-controller:
 	-samsung,lane-count:
 		number of lanes supported by the panel.
 			LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
+	- display-timings: timings for the connected panel as described by
+		Documentation/devicetree/bindings/video/display-timing.txt
 
 Optional properties for dp-controller:
 	-interlaced:
@@ -83,4 +85,19 @@ Board Specific portion:
 		samsung,color-depth = <1>;
 		samsung,link-rate = <0x0a>;
 		samsung,lane-count = <4>;
+
+		display-timings {
+			native-mode = <&lcd_timing>;
+			lcd_timing: 1366x768 {
+				clock-frequency = <70589280>;
+				hactive = <1366>;
+				vactive = <768>;
+				hfront-porch = <40>;
+				hback-porch = <40>;
+				hsync-len = <32>;
+				vback-porch = <10>;
+				vfront-porch = <12>;
+				vsync-len = <6>;
+			};
+		};
 	};
diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt
index 778838a..fa465c3 100644
--- a/Documentation/devicetree/bindings/video/samsung-fimd.txt
+++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt
@@ -39,6 +39,8 @@ Required properties:
 
 Optional Properties:
 - samsung,power-domain: a phandle to FIMD power domain node.
+- samsung,invert-vden: video enable signal is inverted
+- samsung,invert_vclk: video clock signal is inverted
 
 Example:
 
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 089ae22..13ea8b7 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,9 +18,12 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/of.h>
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
 
-#include <video/exynos_dp.h>
+#include <drm/drmP.h>
 
+#include "exynos_drm_drv.h"
 #include "exynos_dp_core.h"
 
 static int exynos_dp_init_dp(struct exynos_dp_device *dp)
@@ -893,6 +896,35 @@ static void exynos_dp_hotplug(struct work_struct *work)
 		dev_err(dp->dev, "unable to config video\n");
 }
 
+static bool exynos_dp_display_is_connected(struct exynos_drm_display *display)
+{
+	return true;
+}
+
+static void *exynos_dp_get_panel(struct exynos_drm_display *display)
+{
+	struct exynos_dp_device *dp = display->ctx;
+
+	return &dp->panel;
+}
+
+static int exynos_dp_check_mode(struct exynos_drm_display *display,
+			struct drm_display_mode *mode)
+{
+	return 0;
+}
+
+static struct exynos_drm_display_ops exynos_dp_display_ops = {
+	.is_connected = exynos_dp_display_is_connected,
+	.get_panel = exynos_dp_get_panel,
+	.check_mode = exynos_dp_check_mode,
+};
+
+static struct exynos_drm_display exynos_dp_display = {
+	.type = EXYNOS_DISPLAY_TYPE_LCD,
+	.ops = &exynos_dp_display_ops,
+};
+
 #ifdef CONFIG_OF
 static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
 {
@@ -1000,6 +1032,19 @@ err:
 	return ret;
 }
 
+static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
+{
+	int ret;
+
+	ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm,
+			OF_USE_NATIVE_MODE);
+	if (ret) {
+		DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
+		return ret;
+	}
+	return 0;
+}
+
 static void exynos_dp_phy_init(struct exynos_dp_device *dp)
 {
 	u32 reg;
@@ -1028,6 +1073,11 @@ static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
 	return -EINVAL;
 }
 
+static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
+{
+	return -EINVAL;
+}
+
 static void exynos_dp_phy_init(struct exynos_dp_device *dp)
 {
 	return;
@@ -1039,6 +1089,46 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
 }
 #endif /* CONFIG_OF */
 
+void exynos_dp_poweron(struct exynos_dp_device *dp)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_platdata *pdata = dev->platform_data;
+
+	if (dev->of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_init(dp);
+	} else {
+		if (pdata->phy_init)
+			pdata->phy_init();
+	}
+
+	clk_prepare_enable(dp->clock);
+
+	exynos_dp_init_dp(dp);
+
+	enable_irq(dp->irq);
+}
+
+void exynos_dp_poweroff(struct exynos_dp_device *dp)
+{
+	struct device *dev = dp->dev;
+	struct exynos_dp_platdata *pdata = dev->platform_data;
+
+	disable_irq(dp->irq);
+
+	flush_work(&dp->hotplug_work);
+
+	if (dev->of_node) {
+		if (dp->phy_addr)
+			exynos_dp_phy_exit(dp);
+	} else {
+		if (pdata->phy_exit)
+			pdata->phy_exit();
+	}
+
+	clk_disable_unprepare(dp->clock);
+}
+
 static int exynos_dp_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1064,6 +1154,10 @@ static int exynos_dp_probe(struct platform_device *pdev)
 		ret = exynos_dp_dt_parse_phydata(dp);
 		if (ret)
 			return ret;
+
+		ret = exynos_dp_dt_parse_panel(dp);
+		if (ret)
+			return ret;
 	} else {
 		pdata = pdev->dev.platform_data;
 		if (!pdata) {
@@ -1115,6 +1209,9 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, dp);
 
+	exynos_dp_display.ctx = dp;
+	exynos_drm_display_register(&exynos_dp_display);
+
 	return 0;
 }
 
@@ -1123,6 +1220,8 @@ static int exynos_dp_remove(struct platform_device *pdev)
 	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
 	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
 
+	exynos_drm_display_unregister(&exynos_dp_display);
+
 	flush_work(&dp->hotplug_work);
 
 	if (pdev->dev.of_node) {
@@ -1142,45 +1241,17 @@ static int exynos_dp_remove(struct platform_device *pdev)
 #ifdef CONFIG_PM_SLEEP
 static int exynos_dp_suspend(struct device *dev)
 {
-	struct exynos_dp_platdata *pdata = dev->platform_data;
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-	disable_irq(dp->irq);
-
-	flush_work(&dp->hotplug_work);
-
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_exit(dp);
-	} else {
-		if (pdata->phy_exit)
-			pdata->phy_exit();
-	}
-
-	clk_disable_unprepare(dp->clock);
-
+	exynos_dp_poweroff(dp);
 	return 0;
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	struct exynos_dp_platdata *pdata = dev->platform_data;
 	struct exynos_dp_device *dp = dev_get_drvdata(dev);
 
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_init(dp);
-	} else {
-		if (pdata->phy_init)
-			pdata->phy_init();
-	}
-
-	clk_prepare_enable(dp->clock);
-
-	exynos_dp_init_dp(dp);
-
-	enable_irq(dp->irq);
-
+	exynos_dp_poweron(dp);
 	return 0;
 }
 #endif
@@ -1195,7 +1266,7 @@ static const struct of_device_id exynos_dp_match[] = {
 };
 MODULE_DEVICE_TABLE(of, exynos_dp_match);
 
-static struct platform_driver exynos_dp_driver = {
+struct platform_driver dp_driver = {
 	.probe		= exynos_dp_probe,
 	.remove		= exynos_dp_remove,
 	.driver		= {
@@ -1206,8 +1277,6 @@ static struct platform_driver exynos_dp_driver = {
 	},
 };
 
-module_platform_driver(exynos_dp_driver);
-
 MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
 MODULE_DESCRIPTION("Samsung SoC DP Driver");
 MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 6c567bbf..a5e9145 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -13,6 +13,9 @@
 #ifndef _EXYNOS_DP_CORE_H
 #define _EXYNOS_DP_CORE_H
 
+#include <drm/exynos_drm.h>
+#include <video/exynos_dp.h>
+
 enum dp_irq_type {
 	DP_IRQ_TYPE_HP_CABLE_IN,
 	DP_IRQ_TYPE_HP_CABLE_OUT,
@@ -42,6 +45,8 @@ struct exynos_dp_device {
 	struct video_info	*video_info;
 	struct link_train	link_train;
 	struct work_struct	hotplug_work;
+
+	struct exynos_drm_panel_info panel;
 };
 
 /* exynos_dp_reg.c */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 4b265bf..03caa3a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -316,6 +316,12 @@ static int __init exynos_drm_init(void)
 {
 	int ret;
 
+#ifdef CONFIG_DRM_EXYNOS_DP
+	ret = platform_driver_register(&dp_driver);
+	if (ret < 0)
+		goto out_dp;
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	ret = platform_driver_register(&fimd_driver);
 	if (ret < 0)
@@ -431,6 +437,10 @@ out_hdmi:
 	platform_driver_unregister(&fimd_driver);
 out_fimd:
 #endif
+#ifdef CONFIG_DRM_EXYNOS_DP
+	platform_driver_unregister(&dp_driver);
+out_dp:
+#endif
 	return ret;
 }
 
@@ -473,6 +483,10 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_FIMD
 	platform_driver_unregister(&fimd_driver);
 #endif
+
+#ifdef CONFIG_DRM_EXYNOS_DP
+	platform_driver_unregister(&dp_driver);
+#endif
 }
 
 module_init(exynos_drm_init);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 97bdfcc..f3e18d1 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -369,6 +369,7 @@ int exynos_platform_device_ipp_register(void);
  */
 void exynos_platform_device_ipp_unregister(void);
 
+extern struct platform_driver dp_driver;
 extern struct platform_driver fimd_driver;
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 61124ca..c6a05f6 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -158,39 +158,6 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
 	return (struct fimd_driver_data *)of_id->data;
 }
 
-static bool fimd_display_is_connected(struct exynos_drm_display *display)
-{
-	/* TODO. */
-
-	return true;
-}
-
-static void *fimd_get_panel(struct exynos_drm_display *display)
-{
-	struct fimd_context *ctx = display->ctx;
-
-	return &ctx->panel;
-}
-
-static int fimd_check_mode(struct exynos_drm_display *display,
-			struct drm_display_mode *mode)
-{
-	/* TODO. */
-
-	return 0;
-}
-
-static struct exynos_drm_display_ops fimd_display_ops = {
-	.is_connected = fimd_display_is_connected,
-	.get_panel = fimd_get_panel,
-	.check_mode = fimd_check_mode,
-};
-
-static struct exynos_drm_display fimd_display = {
-	.type = EXYNOS_DISPLAY_TYPE_LCD,
-	.ops = &fimd_display_ops,
-};
-
 static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
 			struct exynos_drm_overlay *overlay)
 {
@@ -611,6 +578,16 @@ static void fimd_mode_set(struct exynos_drm_manager *mgr,
 	mode->hfpd = hblank - mode->hsync_len - mode->hbpd;
 
 	mode->clkdiv = fimd_calc_clkdiv(ctx, in_mode);
+
+	if (in_mode->flags & DRM_MODE_FLAG_NVSYNC)
+		ctx->vidcon1 |= VIDCON1_INV_VSYNC;
+	else
+		ctx->vidcon1 &= ~VIDCON1_INV_VSYNC;
+
+	if (in_mode->flags & DRM_MODE_FLAG_NHSYNC)
+		ctx->vidcon1 |= VIDCON1_INV_HSYNC;
+	else
+		ctx->vidcon1 &= ~VIDCON1_INV_HSYNC;
 }
 
 static void fimd_commit(struct exynos_drm_manager *mgr)
@@ -888,30 +865,6 @@ static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
 	return 0;
 }
 
-static int fimd_get_platform_data(struct fimd_context *ctx, struct device *dev)
-{
-	struct videomode *vm;
-	int ret;
-
-	vm = &ctx->panel.vm;
-	ret = of_get_videomode(dev->of_node, vm, OF_USE_NATIVE_MODE);
-	if (ret) {
-		DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
-		return ret;
-	}
-
-	if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
-		ctx->vidcon1 |= VIDCON1_INV_VSYNC;
-	if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
-		ctx->vidcon1 |= VIDCON1_INV_HSYNC;
-	if (vm->flags & DISPLAY_FLAGS_DE_LOW)
-		ctx->vidcon1 |= VIDCON1_INV_VDEN;
-	if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
-		ctx->vidcon1 |= VIDCON1_INV_VCLK;
-
-	return 0;
-}
-
 static int fimd_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -929,9 +882,10 @@ static int fimd_probe(struct platform_device *pdev)
 
 	ctx->dev = dev;
 
-	ret = fimd_get_platform_data(ctx, dev);
-	if (ret)
-		return ret;
+	if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
+		ctx->vidcon1 |= VIDCON1_INV_VDEN;
+	if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
+		ctx->vidcon1 |= VIDCON1_INV_VCLK;
 
 	ctx->bus_clk = devm_clk_get(dev, "fimd");
 	if (IS_ERR(ctx->bus_clk)) {
@@ -973,9 +927,6 @@ static int fimd_probe(struct platform_device *pdev)
 	fimd_manager.ctx = ctx;
 	exynos_drm_manager_register(&fimd_manager);
 
-	fimd_display.ctx = ctx;
-	exynos_drm_display_register(&fimd_display);
-
 	pm_runtime_enable(dev);
 	pm_runtime_get_sync(dev);
 
@@ -991,7 +942,6 @@ static int fimd_remove(struct platform_device *pdev)
 	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
 	struct fimd_context *ctx = mgr->ctx;
 
-	exynos_drm_display_unregister(&fimd_display);
 	exynos_drm_manager_unregister(&fimd_manager);
 
 	if (ctx->suspended)
-- 
1.8.4

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

* [PATCH v2 23/26] ARM: dts: Move display-timings node from fimd to dp
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (21 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 22/26] drm/exynos: Move display implementation into dp Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 24/26] drm/exynos: Implement dpms display callback in DP Sean Paul
                   ` (2 subsequent siblings)
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch moves the display-timings node from fimd to dp to reflect the
device tree bindings change.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2: None

 arch/arm/boot/dts/exynos5250-arndale.dts  | 7 ++++---
 arch/arm/boot/dts/exynos5250-smdk5250.dts | 7 ++++---
 arch/arm/boot/dts/exynos5250-snow.dts     | 7 ++++---
 arch/arm/boot/dts/exynos5420-smdk5420.dts | 7 ++++---
 4 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index cee55fa..4583de4 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -517,10 +517,7 @@
 		samsung,link-rate = <0x0a>;
 		samsung,lane-count = <4>;
 		status = "okay";
-	};
 
-	fimd: fimd@14400000 {
-		status = "okay";
 		display-timings {
 			native-mode = <&timing0>;
 			timing0: timing@0 {
@@ -538,6 +535,10 @@
 		};
 	};
 
+	fimd: fimd@14400000 {
+		status = "okay";
+	};
+
 	usb_hub_bus {
 		compatible = "simple-bus";
 		#address-cells = <1>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 2538b32..df1001d 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -261,10 +261,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&dp_hpd>;
 		status = "okay";
-	};
 
-	fimd@14400000 {
-		status = "okay";
 		display-timings {
 			native-mode = <&timing0>;
 			timing0: timing@0 {
@@ -282,6 +279,10 @@
 		};
 	};
 
+	fimd@14400000 {
+		status = "okay";
+	};
+
 	fixed-rate-clocks {
 		xxti {
 			compatible = "samsung,clock-xxti";
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 8c92df8..b2783d8 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -216,10 +216,7 @@
 		pinctrl-names = "default";
 		pinctrl-0 = <&dp_hpd>;
 		status = "okay";
-	};
 
-	fimd: fimd@14400000 {
-		status = "okay";
 		display-timings {
 			native-mode = <&lcd_timing>;
 			lcd_timing: 1366x768 {
@@ -236,6 +233,10 @@
 		};
 	};
 
+	fimd: fimd@14400000 {
+		status = "okay";
+	};
+
 	fixed-rate-clocks {
 		xxti {
 			compatible = "samsung,clock-xxti";
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index bafba25..763797c 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -41,10 +41,7 @@
 		samsung,link-rate = <0x0a>;
 		samsung,lane-count = <4>;
 		status = "okay";
-	};
 
-	fimd@14400000 {
-		status = "okay";
 		display-timings {
 			native-mode = <&timing0>;
 			timing0: timing@0 {
@@ -61,4 +58,8 @@
 		};
 	};
 
+	fimd@14400000 {
+		status = "okay";
+	};
+
 };
-- 
1.8.4

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

* [PATCH v2 24/26] drm/exynos: Implement dpms display callback in DP
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (22 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 23/26] ARM: dts: Move display-timings node from fimd to dp Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 25/26] drm/exynos: Clean up FIMD power on/off routines Sean Paul
  2013-10-16 19:26 ` [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv Sean Paul
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch implements the dpms display callback for the DP driver.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Added to the patchset

 drivers/gpu/drm/exynos/exynos_dp_core.c | 173 ++++++++++++++++----------------
 drivers/gpu/drm/exynos/exynos_dp_core.h |   1 +
 2 files changed, 85 insertions(+), 89 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 13ea8b7..476d3b0 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -914,10 +914,82 @@ static int exynos_dp_check_mode(struct exynos_drm_display *display,
 	return 0;
 }
 
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+	struct exynos_dp_platdata *pdata = dp->dev->platform_data;
+	u32 reg;
+
+	if (dp->phy_addr) {
+		reg = readl(dp->phy_addr);
+		reg |= dp->enable_mask;
+		writel(reg, dp->phy_addr);
+	}
+
+	if (pdata && pdata->phy_init)
+		pdata->phy_init();
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+	struct exynos_dp_platdata *pdata = dp->dev->platform_data;
+	u32 reg;
+
+	if (dp->phy_addr) {
+		reg = readl(dp->phy_addr);
+		reg &= ~(dp->enable_mask);
+		writel(reg, dp->phy_addr);
+	}
+
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit();
+}
+
+static void exynos_dp_poweron(struct exynos_dp_device *dp)
+{
+	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
+		return;
+
+	clk_prepare_enable(dp->clock);
+	exynos_dp_phy_init(dp);
+	exynos_dp_init_dp(dp);
+	enable_irq(dp->irq);
+}
+
+static void exynos_dp_poweroff(struct exynos_dp_device *dp)
+{
+	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
+		return;
+
+	disable_irq(dp->irq);
+	flush_work(&dp->hotplug_work);
+	exynos_dp_phy_exit(dp);
+	clk_disable_unprepare(dp->clock);
+}
+
+static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
+{
+	struct exynos_dp_device *dp = display->ctx;
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		exynos_dp_poweron(dp);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		exynos_dp_poweroff(dp);
+		break;
+	default:
+		break;
+	};
+	dp->dpms_mode = mode;
+}
+
 static struct exynos_drm_display_ops exynos_dp_display_ops = {
 	.is_connected = exynos_dp_display_is_connected,
 	.get_panel = exynos_dp_get_panel,
 	.check_mode = exynos_dp_check_mode,
+	.dpms = exynos_dp_dpms,
 };
 
 static struct exynos_drm_display exynos_dp_display = {
@@ -1044,24 +1116,6 @@ static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
 	}
 	return 0;
 }
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = __raw_readl(dp->phy_addr);
-	reg |= dp->enable_mask;
-	__raw_writel(reg, dp->phy_addr);
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
-	u32 reg;
-
-	reg = __raw_readl(dp->phy_addr);
-	reg &= ~(dp->enable_mask);
-	__raw_writel(reg, dp->phy_addr);
-}
 #else
 static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev)
 {
@@ -1089,46 +1143,6 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
 }
 #endif /* CONFIG_OF */
 
-void exynos_dp_poweron(struct exynos_dp_device *dp)
-{
-	struct device *dev = dp->dev;
-	struct exynos_dp_platdata *pdata = dev->platform_data;
-
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_init(dp);
-	} else {
-		if (pdata->phy_init)
-			pdata->phy_init();
-	}
-
-	clk_prepare_enable(dp->clock);
-
-	exynos_dp_init_dp(dp);
-
-	enable_irq(dp->irq);
-}
-
-void exynos_dp_poweroff(struct exynos_dp_device *dp)
-{
-	struct device *dev = dp->dev;
-	struct exynos_dp_platdata *pdata = dev->platform_data;
-
-	disable_irq(dp->irq);
-
-	flush_work(&dp->hotplug_work);
-
-	if (dev->of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_exit(dp);
-	} else {
-		if (pdata->phy_exit)
-			pdata->phy_exit();
-	}
-
-	clk_disable_unprepare(dp->clock);
-}
-
 static int exynos_dp_probe(struct platform_device *pdev)
 {
 	struct resource *res;
@@ -1145,6 +1159,7 @@ static int exynos_dp_probe(struct platform_device *pdev)
 	}
 
 	dp->dev = &pdev->dev;
+	dp->dpms_mode = DRM_MODE_DPMS_OFF;
 
 	if (pdev->dev.of_node) {
 		pdata = exynos_dp_dt_parse_pdata(&pdev->dev);
@@ -1190,26 +1205,17 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
 	dp->video_info = pdata->video_info;
 
-	if (pdev->dev.of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_init(dp);
-	} else {
-		if (pdata->phy_init)
-			pdata->phy_init();
-	}
-
-	exynos_dp_init_dp(dp);
-
 	ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
 				"exynos-dp", dp);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request irq\n");
 		return ret;
 	}
-
-	platform_set_drvdata(pdev, dp);
+	disable_irq(dp->irq);
 
 	exynos_dp_display.ctx = dp;
+
+	platform_set_drvdata(pdev, &exynos_dp_display);
 	exynos_drm_display_register(&exynos_dp_display);
 
 	return 0;
@@ -1217,41 +1223,30 @@ static int exynos_dp_probe(struct platform_device *pdev)
 
 static int exynos_dp_remove(struct platform_device *pdev)
 {
-	struct exynos_dp_platdata *pdata = pdev->dev.platform_data;
-	struct exynos_dp_device *dp = platform_get_drvdata(pdev);
+	struct exynos_drm_display *display = platform_get_drvdata(pdev);
 
+	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
 	exynos_drm_display_unregister(&exynos_dp_display);
 
-	flush_work(&dp->hotplug_work);
-
-	if (pdev->dev.of_node) {
-		if (dp->phy_addr)
-			exynos_dp_phy_exit(dp);
-	} else {
-		if (pdata->phy_exit)
-			pdata->phy_exit();
-	}
-
-	clk_disable_unprepare(dp->clock);
-
-
 	return 0;
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int exynos_dp_suspend(struct device *dev)
 {
-	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct exynos_drm_display *display = platform_get_drvdata(pdev);
 
-	exynos_dp_poweroff(dp);
+	exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
 	return 0;
 }
 
 static int exynos_dp_resume(struct device *dev)
 {
-	struct exynos_dp_device *dp = dev_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct exynos_drm_display *display = platform_get_drvdata(pdev);
 
-	exynos_dp_poweron(dp);
+	exynos_dp_dpms(display, DRM_MODE_DPMS_ON);
 	return 0;
 }
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index a5e9145..0c67c19 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -45,6 +45,7 @@ struct exynos_dp_device {
 	struct video_info	*video_info;
 	struct link_train	link_train;
 	struct work_struct	hotplug_work;
+	int			dpms_mode;
 
 	struct exynos_drm_panel_info panel;
 };
-- 
1.8.4

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

* [PATCH v2 25/26] drm/exynos: Clean up FIMD power on/off routines
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (23 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 24/26] drm/exynos: Implement dpms display callback in DP Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 19:26 ` [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv Sean Paul
  25 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch separates the fimd_activate function into poweron/poweroff
functions to be more consistent with the other drivers in exynos drm. It
also properly cleans up after failures in poweron. The functions have
also been shuffled around such that they are all in the same
spot in the file and poweron/poweroff can be called from the dpms function.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Added to the patchset

 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 247 +++++++++++++++++--------------
 1 file changed, 135 insertions(+), 112 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index c6a05f6..ba12916 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -324,6 +324,12 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
 
 	win_data = &ctx->win_data[win];
 
+	/* If suspended, enable this on resume */
+	if (ctx->suspended) {
+		win_data->resume = true;
+		return;
+	}
+
 	/*
 	 * SHADOWCON/PRTCON register is used for enabling timing.
 	 *
@@ -505,35 +511,6 @@ static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
 		drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 }
 
-static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
-{
-	struct fimd_context *ctx = mgr->ctx;
-
-	DRM_DEBUG_KMS("%d\n", mode);
-
-	switch (mode) {
-	case DRM_MODE_DPMS_ON:
-		/*
-		 * enable fimd hardware only if suspended status.
-		 *
-		 * P.S. fimd_dpms function would be called at booting time so
-		 * clk_enable could be called double time.
-		 */
-		if (ctx->suspended)
-			pm_runtime_get_sync(ctx->dev);
-		break;
-	case DRM_MODE_DPMS_STANDBY:
-	case DRM_MODE_DPMS_SUSPEND:
-	case DRM_MODE_DPMS_OFF:
-		if (!ctx->suspended)
-			pm_runtime_put_sync(ctx->dev);
-		break;
-	default:
-		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
-		break;
-	}
-}
-
 static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
 		const struct drm_display_mode *mode)
 {
@@ -726,6 +703,130 @@ static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 		DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
+static void fimd_window_suspend(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+	struct fimd_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		win_data->resume = win_data->enabled;
+		if (win_data->enabled)
+			fimd_win_disable(mgr, i);
+	}
+	fimd_wait_for_vblank(mgr);
+}
+
+static void fimd_window_resume(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+	struct fimd_win_data *win_data;
+	int i;
+
+	for (i = 0; i < WINDOWS_NR; i++) {
+		win_data = &ctx->win_data[i];
+		win_data->enabled = win_data->resume;
+		win_data->resume = false;
+	}
+}
+
+static int fimd_poweron(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+	int ret;
+
+	if (!ctx->suspended)
+		return 0;
+
+	ctx->suspended = false;
+
+	ret = clk_prepare_enable(ctx->bus_clk);
+	if (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
+		goto bus_clk_err;
+	}
+
+	ret = clk_prepare_enable(ctx->lcd_clk);
+	if  (ret < 0) {
+		DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
+		goto lcd_clk_err;
+	}
+
+	/* if vblank was enabled status, enable it again. */
+	if (test_and_clear_bit(0, &ctx->irq_flags)) {
+		ret = fimd_enable_vblank(mgr);
+		if (ret) {
+			DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
+			goto enable_vblank_err;
+		}
+	}
+
+	fimd_window_resume(mgr);
+
+	fimd_apply(mgr);
+
+	return 0;
+
+enable_vblank_err:
+	clk_disable_unprepare(ctx->lcd_clk);
+lcd_clk_err:
+	clk_disable_unprepare(ctx->bus_clk);
+bus_clk_err:
+	ctx->suspended = true;
+	return ret;
+}
+
+static int fimd_poweroff(struct exynos_drm_manager *mgr)
+{
+	struct fimd_context *ctx = mgr->ctx;
+
+	if (ctx->suspended)
+		return 0;
+
+	/*
+	 * We need to make sure that all windows are disabled before we
+	 * suspend that connector. Otherwise we might try to scan from
+	 * a destroyed buffer later.
+	 */
+	fimd_window_suspend(mgr);
+
+	clk_disable_unprepare(ctx->lcd_clk);
+	clk_disable_unprepare(ctx->bus_clk);
+
+	ctx->suspended = true;
+	return 0;
+}
+
+static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
+{
+	struct fimd_context *ctx = mgr->ctx;
+
+	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+	switch (mode) {
+	case DRM_MODE_DPMS_ON:
+		/*
+		 * enable fimd hardware only if suspended status.
+		 *
+		 * P.S. fimd_dpms function would be called at booting time so
+		 * clk_enable could be called double time.
+		 */
+		if (ctx->suspended)
+			pm_runtime_get_sync(ctx->dev);
+		break;
+	case DRM_MODE_DPMS_STANDBY:
+	case DRM_MODE_DPMS_SUSPEND:
+	case DRM_MODE_DPMS_OFF:
+		if (!ctx->suspended)
+			pm_runtime_put_sync(ctx->dev);
+		break;
+	default:
+		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+		break;
+	}
+}
+
 static struct exynos_drm_manager_ops fimd_manager_ops = {
 	.initialize = fimd_mgr_initialize,
 	.remove = fimd_mgr_remove,
@@ -786,85 +887,6 @@ static void fimd_clear_win(struct fimd_context *ctx, int win)
 	fimd_shadow_protect_win(ctx, win, false);
 }
 
-static int fimd_clock(struct fimd_context *ctx, bool enable)
-{
-	if (enable) {
-		int ret;
-
-		ret = clk_prepare_enable(ctx->bus_clk);
-		if (ret < 0)
-			return ret;
-
-		ret = clk_prepare_enable(ctx->lcd_clk);
-		if  (ret < 0) {
-			clk_disable_unprepare(ctx->bus_clk);
-			return ret;
-		}
-	} else {
-		clk_disable_unprepare(ctx->lcd_clk);
-		clk_disable_unprepare(ctx->bus_clk);
-	}
-
-	return 0;
-}
-
-static void fimd_window_suspend(struct exynos_drm_manager *mgr)
-{
-	struct fimd_context *ctx = mgr->ctx;
-	struct fimd_win_data *win_data;
-	int i;
-
-	for (i = 0; i < WINDOWS_NR; i++) {
-		win_data = &ctx->win_data[i];
-		win_data->resume = win_data->enabled;
-		fimd_win_disable(mgr, i);
-	}
-	fimd_wait_for_vblank(mgr);
-}
-
-static void fimd_window_resume(struct exynos_drm_manager *mgr)
-{
-	struct fimd_context *ctx = mgr->ctx;
-	struct fimd_win_data *win_data;
-	int i;
-
-	for (i = 0; i < WINDOWS_NR; i++) {
-		win_data = &ctx->win_data[i];
-		win_data->enabled = win_data->resume;
-		win_data->resume = false;
-	}
-}
-
-static int fimd_activate(struct exynos_drm_manager *mgr, bool enable)
-{
-	struct fimd_context *ctx = mgr->ctx;
-
-	if (enable) {
-		int ret;
-
-		ret = fimd_clock(ctx, true);
-		if (ret < 0)
-			return ret;
-
-		ctx->suspended = false;
-
-		/* if vblank was enabled status, enable it again. */
-		if (test_and_clear_bit(0, &ctx->irq_flags))
-			fimd_enable_vblank(mgr);
-
-		fimd_window_resume(mgr);
-
-		fimd_apply(mgr);
-	} else {
-		fimd_window_suspend(mgr);
-
-		fimd_clock(ctx, false);
-		ctx->suspended = true;
-	}
-
-	return 0;
-}
-
 static int fimd_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -881,6 +903,7 @@ static int fimd_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	ctx->dev = dev;
+	ctx->suspended = true;
 
 	if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
 		ctx->vidcon1 |= VIDCON1_INV_VDEN;
@@ -967,7 +990,7 @@ static int fimd_suspend(struct device *dev)
 	 * because the usage_count of pm runtime is more than 1.
 	 */
 	if (!pm_runtime_suspended(dev))
-		return fimd_activate(mgr, false);
+		return fimd_poweroff(mgr);
 
 	return 0;
 }
@@ -984,7 +1007,7 @@ static int fimd_resume(struct device *dev)
 	if (pm_runtime_suspended(dev))
 		return 0;
 
-	return fimd_activate(mgr, true);
+	return fimd_poweron(mgr);
 }
 #endif
 
@@ -993,14 +1016,14 @@ static int fimd_runtime_suspend(struct device *dev)
 {
 	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
-	return fimd_activate(mgr, false);
+	return fimd_poweroff(mgr);
 }
 
 static int fimd_runtime_resume(struct device *dev)
 {
 	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
 
-	return fimd_activate(mgr, true);
+	return fimd_poweron(mgr);
 }
 #endif
 
-- 
1.8.4

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

* [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv
  2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
                   ` (24 preceding siblings ...)
  2013-10-16 19:26 ` [PATCH v2 25/26] drm/exynos: Clean up FIMD power on/off routines Sean Paul
@ 2013-10-16 19:26 ` Sean Paul
  2013-10-16 20:40   ` Sean Paul
  25 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-16 19:26 UTC (permalink / raw)
  To: dri-devel, inki.dae; +Cc: marcheu

This patch removes all of the suspend/resume logic from the individual
drivers and consolidates it in drm_drv. This consolidation reduces the
number of functions which enable/disable the hardware to just one -- the
dpms callback. This ensures that we always power up/down in a consistent
manner.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
---

Changes in v2:
	- Added to the patchset

 drivers/gpu/drm/exynos/exynos_drm_drv.c  | 97 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_fimd.c | 91 +++++-------------------------
 drivers/gpu/drm/exynos/exynos_hdmi.c     | 82 +--------------------------
 drivers/gpu/drm/exynos/exynos_mixer.c    | 75 +++++-------------------
 4 files changed, 127 insertions(+), 218 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 03caa3a..91d6863 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -11,6 +11,7 @@
  * option) any later version.
  */
 
+#include <linux/pm_runtime.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 
@@ -51,6 +52,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 		return -ENOMEM;
 
 	INIT_LIST_HEAD(&private->pageflip_event_list);
+	dev_set_drvdata(dev->dev, dev);
 	dev->dev_private = (void *)private;
 
 	/*
@@ -155,6 +157,41 @@ static int exynos_drm_unload(struct drm_device *dev)
 	return 0;
 }
 
+static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		int old_dpms = connector->dpms;
+
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+		/* Set the old mode back to the connector for resume */
+		connector->dpms = old_dpms;
+	}
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
+static int exynos_drm_resume(struct drm_device *dev)
+{
+	struct drm_connector *connector;
+
+	drm_modeset_lock_all(dev);
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		if (connector->funcs->dpms)
+			connector->funcs->dpms(connector, connector->dpms);
+	}
+
+	drm_helper_resume_force_mode(dev);
+	drm_modeset_unlock_all(dev);
+
+	return 0;
+}
+
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
 	struct drm_exynos_file_private *file_priv;
@@ -262,6 +299,8 @@ static struct drm_driver exynos_drm_driver = {
 					DRIVER_GEM | DRIVER_PRIME,
 	.load			= exynos_drm_load,
 	.unload			= exynos_drm_unload,
+	.suspend		= exynos_drm_suspend,
+	.resume			= exynos_drm_resume,
 	.open			= exynos_drm_open,
 	.preclose		= exynos_drm_preclose,
 	.lastclose		= exynos_drm_lastclose,
@@ -293,6 +332,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
 {
 	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+
 	return drm_platform_init(&exynos_drm_driver, pdev);
 }
 
@@ -303,12 +345,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int exynos_drm_sys_suspend(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+	pm_message_t message;
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	message.event = PM_EVENT_SUSPEND;
+	return exynos_drm_suspend(drm_dev, message);
+}
+
+static int exynos_drm_sys_resume(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	return exynos_drm_resume(drm_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int exynos_drm_runtime_suspend(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+	pm_message_t message;
+
+	if (pm_runtime_suspended(dev))
+		return 0;
+
+	message.event = PM_EVENT_SUSPEND;
+	return exynos_drm_suspend(drm_dev, message);
+}
+
+static int exynos_drm_runtime_resume(struct device *dev)
+{
+	struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+	if (!pm_runtime_suspended(dev))
+		return 0;
+
+	return exynos_drm_resume(drm_dev);
+}
+#endif
+
+static const struct dev_pm_ops exynos_drm_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
+	SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend,
+			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,
 	},
 };
 
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index ba12916..208e013 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -741,6 +741,8 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
 
 	ctx->suspended = false;
 
+	pm_runtime_get_sync(ctx->dev);
+
 	ret = clk_prepare_enable(ctx->bus_clk);
 	if (ret < 0) {
 		DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
@@ -794,32 +796,24 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
 	clk_disable_unprepare(ctx->lcd_clk);
 	clk_disable_unprepare(ctx->bus_clk);
 
+	pm_runtime_put_sync(ctx->dev);
+
 	ctx->suspended = true;
 	return 0;
 }
 
 static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct fimd_context *ctx = mgr->ctx;
-
 	DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		/*
-		 * enable fimd hardware only if suspended status.
-		 *
-		 * P.S. fimd_dpms function would be called at booting time so
-		 * clk_enable could be called double time.
-		 */
-		if (ctx->suspended)
-			pm_runtime_get_sync(ctx->dev);
+		fimd_poweron(mgr);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		if (!ctx->suspended)
-			pm_runtime_put_sync(ctx->dev);
+		fimd_poweroff(mgr);
 		break;
 	default:
 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -950,8 +944,14 @@ static int fimd_probe(struct platform_device *pdev)
 	fimd_manager.ctx = ctx;
 	exynos_drm_manager_register(&fimd_manager);
 
+	/*
+	 * We need to runtime pm to enable/disable sysmmu since it is a child of
+	 * this driver. Ideally, this would hang off the drm driver's runtime
+	 * operations, but we're not quite there yet.
+	 *
+	 * Tracked in crbug.com/264312
+	 */
 	pm_runtime_enable(dev);
-	pm_runtime_get_sync(dev);
 
 	for (win = 0; win < WINDOWS_NR; win++)
 		fimd_clear_win(ctx, win);
@@ -961,84 +961,23 @@ static int fimd_probe(struct platform_device *pdev)
 
 static int fimd_remove(struct platform_device *pdev)
 {
-	struct device *dev = &pdev->dev;
 	struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
-	struct fimd_context *ctx = mgr->ctx;
 
 	exynos_drm_manager_unregister(&fimd_manager);
 
-	if (ctx->suspended)
-		goto out;
-
-	pm_runtime_set_suspended(dev);
-	pm_runtime_put_sync(dev);
+	fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
-out:
-	pm_runtime_disable(dev);
+	pm_runtime_disable(&pdev->dev);
 
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int fimd_suspend(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-
-	/*
-	 * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
-	 * called here, an error would be returned by that interface
-	 * because the usage_count of pm runtime is more than 1.
-	 */
-	if (!pm_runtime_suspended(dev))
-		return fimd_poweroff(mgr);
-
-	return 0;
-}
-
-static int fimd_resume(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-
-	/*
-	 * if entered to sleep when lcd panel was on, the usage_count
-	 * of pm runtime would still be 1 so in this case, fimd driver
-	 * should be on directly not drawing on pm runtime interface.
-	 */
-	if (pm_runtime_suspended(dev))
-		return 0;
-
-	return fimd_poweron(mgr);
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int fimd_runtime_suspend(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-
-	return fimd_poweroff(mgr);
-}
-
-static int fimd_runtime_resume(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_fimd_manager(dev);
-
-	return fimd_poweron(mgr);
-}
-#endif
-
-static const struct dev_pm_ops fimd_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
-	SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
-};
-
 struct platform_driver fimd_driver = {
 	.probe		= fimd_probe,
 	.remove		= fimd_remove,
 	.driver		= {
 		.name	= "exynos4-fb",
 		.owner	= THIS_MODULE,
-		.pm	= &fimd_pm_ops,
 		.of_match_table = fimd_driver_dt_match,
 	},
 };
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index afc83c9..130b109 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -28,7 +28,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
-#include <linux/pm_runtime.h>
 #include <linux/clk.h>
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
@@ -1771,7 +1770,6 @@ static void hdmi_poweroff(struct exynos_drm_display *display)
 	regulator_bulk_disable(res->regul_count, res->regul_bulk);
 
 	mutex_lock(&hdata->hdmi_mutex);
-
 	hdata->powered = false;
 
 out:
@@ -1780,20 +1778,16 @@ out:
 
 static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
-	struct hdmi_context *hdata = display->ctx;
-
 	DRM_DEBUG_KMS("mode %d\n", mode);
 
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		if (pm_runtime_suspended(hdata->dev))
-			pm_runtime_get_sync(hdata->dev);
+		hdmi_poweron(display);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		if (!pm_runtime_suspended(hdata->dev))
-			pm_runtime_put_sync(hdata->dev);
+		hdmi_poweroff(display);
 		break;
 	default:
 		DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -2036,8 +2030,6 @@ static int hdmi_probe(struct platform_device *pdev)
 	hdmi_display.ctx = hdata;
 	exynos_drm_display_register(&hdmi_display);
 
-	pm_runtime_enable(dev);
-
 	return 0;
 
 err_hdmiphy:
@@ -2053,88 +2045,18 @@ static int hdmi_remove(struct platform_device *pdev)
 	struct exynos_drm_display *display = get_hdmi_display(dev);
 	struct hdmi_context *hdata = display->ctx;
 
-	pm_runtime_disable(dev);
-
 	put_device(&hdata->hdmiphy_port->dev);
 	put_device(&hdata->ddc_port->dev);
 
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int hdmi_suspend(struct device *dev)
-{
-	struct exynos_drm_display *display = get_hdmi_display(dev);
-	struct hdmi_context *hdata = display->ctx;
-
-	disable_irq(hdata->irq);
-
-	hdata->hpd = false;
-	if (hdata->drm_dev)
-		drm_helper_hpd_irq_event(hdata->drm_dev);
-
-	if (pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("Already suspended\n");
-		return 0;
-	}
-
-	hdmi_poweroff(display);
-
-	return 0;
-}
-
-static int hdmi_resume(struct device *dev)
-{
-	struct exynos_drm_display *display = get_hdmi_display(dev);
-	struct hdmi_context *hdata = display->ctx;
-
-	hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-
-	enable_irq(hdata->irq);
-
-	if (!pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("Already resumed\n");
-		return 0;
-	}
-
-	hdmi_poweron(display);
-
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int hdmi_runtime_suspend(struct device *dev)
-{
-	struct exynos_drm_display *display = get_hdmi_display(dev);
-
-	hdmi_poweroff(display);
-
-	return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
-	struct exynos_drm_display *display = get_hdmi_display(dev);
-
-	hdmi_poweron(display);
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops hdmi_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
-	SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
-};
-
 struct platform_driver hdmi_driver = {
 	.probe		= hdmi_probe,
 	.remove		= hdmi_remove,
 	.driver		= {
 		.name	= "exynos-hdmi",
 		.owner	= THIS_MODULE,
-		.pm	= &hdmi_pm_ops,
 		.of_match_table = hdmi_match_types,
 	},
 };
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 39aed3e..985391d 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -902,6 +902,8 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
 	ctx->powered = true;
 	mutex_unlock(&ctx->mixer_mutex);
 
+	pm_runtime_get_sync(ctx->dev);
+
 	clk_prepare_enable(res->mixer);
 	if (ctx->vp_enabled) {
 		clk_prepare_enable(res->vp);
@@ -934,6 +936,8 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
 		clk_disable_unprepare(res->sclk_mixer);
 	}
 
+	pm_runtime_put_sync(ctx->dev);
+
 	mutex_lock(&ctx->mixer_mutex);
 	ctx->powered = false;
 
@@ -943,18 +947,14 @@ out:
 
 static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-	struct mixer_context *mixer_ctx = mgr->ctx;
-
 	switch (mode) {
 	case DRM_MODE_DPMS_ON:
-		if (pm_runtime_suspended(mixer_ctx->dev))
-			pm_runtime_get_sync(mixer_ctx->dev);
+		mixer_poweron(mgr);
 		break;
 	case DRM_MODE_DPMS_STANDBY:
 	case DRM_MODE_DPMS_SUSPEND:
 	case DRM_MODE_DPMS_OFF:
-		if (!pm_runtime_suspended(mixer_ctx->dev))
-			pm_runtime_put_sync(mixer_ctx->dev);
+		mixer_poweroff(mgr);
 		break;
 	default:
 		DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -1239,6 +1239,13 @@ static int mixer_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, &mixer_manager);
 	exynos_drm_manager_register(&mixer_manager);
 
+	/*
+	 * We need to runtime pm to enable/disable sysmmu since it is a child of
+	 * this driver. Ideally, this would hang off the drm driver's runtime
+	 * operations, but we're not quite there yet.
+	 *
+	 * Tracked in crbug.com/264312
+	 */
 	pm_runtime_enable(dev);
 
 	return 0;
@@ -1258,66 +1265,10 @@ static int mixer_remove(struct platform_device *pdev)
 	return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int mixer_suspend(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
-
-	if (pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("Already suspended\n");
-		return 0;
-	}
-
-	mixer_poweroff(mgr);
-
-	return 0;
-}
-
-static int mixer_resume(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
-
-	if (!pm_runtime_suspended(dev)) {
-		DRM_DEBUG_KMS("Already resumed\n");
-		return 0;
-	}
-
-	mixer_poweron(mgr);
-
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int mixer_runtime_suspend(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
-
-	mixer_poweroff(mgr);
-
-	return 0;
-}
-
-static int mixer_runtime_resume(struct device *dev)
-{
-	struct exynos_drm_manager *mgr = get_mixer_manager(dev);
-
-	mixer_poweron(mgr);
-
-	return 0;
-}
-#endif
-
-static const struct dev_pm_ops mixer_pm_ops = {
-	SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
-	SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
-};
-
 struct platform_driver mixer_driver = {
 	.driver = {
 		.name = "exynos-mixer",
 		.owner = THIS_MODULE,
-		.pm = &mixer_pm_ops,
 		.of_match_table = mixer_match_types,
 	},
 	.probe = mixer_probe,
-- 
1.8.4

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

* Re: [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv
  2013-10-16 19:26 ` [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv Sean Paul
@ 2013-10-16 20:40   ` Sean Paul
  2013-10-17  5:10     ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-16 20:40 UTC (permalink / raw)
  To: dri-devel, InKi Dae; +Cc: Stéphane Marchesin

On Wed, Oct 16, 2013 at 3:26 PM, Sean Paul <seanpaul@chromium.org> wrote:
> This patch removes all of the suspend/resume logic from the individual
> drivers and consolidates it in drm_drv. This consolidation reduces the
> number of functions which enable/disable the hardware to just one -- the
> dpms callback. This ensures that we always power up/down in a consistent
> manner.
>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>
> Changes in v2:
>         - Added to the patchset
>
>  drivers/gpu/drm/exynos/exynos_drm_drv.c  | 97 ++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 91 +++++-------------------------
>  drivers/gpu/drm/exynos/exynos_hdmi.c     | 82 +--------------------------
>  drivers/gpu/drm/exynos/exynos_mixer.c    | 75 +++++-------------------
>  4 files changed, 127 insertions(+), 218 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> index 03caa3a..91d6863 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> @@ -11,6 +11,7 @@
>   * option) any later version.
>   */
>
> +#include <linux/pm_runtime.h>
>  #include <drm/drmP.h>
>  #include <drm/drm_crtc_helper.h>
>
> @@ -51,6 +52,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
>                 return -ENOMEM;
>
>         INIT_LIST_HEAD(&private->pageflip_event_list);
> +       dev_set_drvdata(dev->dev, dev);
>         dev->dev_private = (void *)private;
>
>         /*
> @@ -155,6 +157,41 @@ static int exynos_drm_unload(struct drm_device *dev)
>         return 0;
>  }
>
> +static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
> +{
> +       struct drm_connector *connector;
> +
> +       drm_modeset_lock_all(dev);
> +       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> +               int old_dpms = connector->dpms;
> +
> +               if (connector->funcs->dpms)
> +                       connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
> +
> +               /* Set the old mode back to the connector for resume */
> +               connector->dpms = old_dpms;
> +       }
> +       drm_modeset_unlock_all(dev);
> +
> +       return 0;
> +}
> +
> +static int exynos_drm_resume(struct drm_device *dev)
> +{
> +       struct drm_connector *connector;
> +
> +       drm_modeset_lock_all(dev);
> +       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
> +               if (connector->funcs->dpms)
> +                       connector->funcs->dpms(connector, connector->dpms);
> +       }
> +
> +       drm_helper_resume_force_mode(dev);
> +       drm_modeset_unlock_all(dev);
> +
> +       return 0;
> +}
> +
>  static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
>  {
>         struct drm_exynos_file_private *file_priv;
> @@ -262,6 +299,8 @@ static struct drm_driver exynos_drm_driver = {
>                                         DRIVER_GEM | DRIVER_PRIME,
>         .load                   = exynos_drm_load,
>         .unload                 = exynos_drm_unload,
> +       .suspend                = exynos_drm_suspend,
> +       .resume                 = exynos_drm_resume,
>         .open                   = exynos_drm_open,
>         .preclose               = exynos_drm_preclose,
>         .lastclose              = exynos_drm_lastclose,
> @@ -293,6 +332,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
>  {
>         pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
>
> +       pm_runtime_enable(&pdev->dev);
> +       pm_runtime_get_sync(&pdev->dev);
> +
>         return drm_platform_init(&exynos_drm_driver, pdev);
>  }
>
> @@ -303,12 +345,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
>         return 0;
>  }
>
> +#ifdef CONFIG_PM_SLEEP
> +static int exynos_drm_sys_suspend(struct device *dev)
> +{
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> +       pm_message_t message;
> +
> +       if (pm_runtime_suspended(dev))
> +               return 0;
> +
> +       message.event = PM_EVENT_SUSPEND;
> +       return exynos_drm_suspend(drm_dev, message);
> +}
> +
> +static int exynos_drm_sys_resume(struct device *dev)
> +{
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> +
> +       if (pm_runtime_suspended(dev))
> +               return 0;
> +
> +       return exynos_drm_resume(drm_dev);
> +}
> +#endif
> +
> +#ifdef CONFIG_PM_RUNTIME
> +static int exynos_drm_runtime_suspend(struct device *dev)
> +{
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> +       pm_message_t message;
> +
> +       if (pm_runtime_suspended(dev))
> +               return 0;
> +
> +       message.event = PM_EVENT_SUSPEND;
> +       return exynos_drm_suspend(drm_dev, message);
> +}
> +
> +static int exynos_drm_runtime_resume(struct device *dev)
> +{
> +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> +
> +       if (!pm_runtime_suspended(dev))
> +               return 0;
> +
> +       return exynos_drm_resume(drm_dev);
> +}
> +#endif
> +
> +static const struct dev_pm_ops exynos_drm_pm_ops = {
> +       SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
> +       SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend,
> +                       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,
>         },
>  };
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> index ba12916..208e013 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> @@ -741,6 +741,8 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
>
>         ctx->suspended = false;
>
> +       pm_runtime_get_sync(ctx->dev);
> +
>         ret = clk_prepare_enable(ctx->bus_clk);
>         if (ret < 0) {
>                 DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
> @@ -794,32 +796,24 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
>         clk_disable_unprepare(ctx->lcd_clk);
>         clk_disable_unprepare(ctx->bus_clk);
>
> +       pm_runtime_put_sync(ctx->dev);
> +
>         ctx->suspended = true;
>         return 0;
>  }
>
>  static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
>  {
> -       struct fimd_context *ctx = mgr->ctx;
> -
>         DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
>
>         switch (mode) {
>         case DRM_MODE_DPMS_ON:
> -               /*
> -                * enable fimd hardware only if suspended status.
> -                *
> -                * P.S. fimd_dpms function would be called at booting time so
> -                * clk_enable could be called double time.
> -                */
> -               if (ctx->suspended)
> -                       pm_runtime_get_sync(ctx->dev);
> +               fimd_poweron(mgr);
>                 break;
>         case DRM_MODE_DPMS_STANDBY:
>         case DRM_MODE_DPMS_SUSPEND:
>         case DRM_MODE_DPMS_OFF:
> -               if (!ctx->suspended)
> -                       pm_runtime_put_sync(ctx->dev);
> +               fimd_poweroff(mgr);
>                 break;
>         default:
>                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
> @@ -950,8 +944,14 @@ static int fimd_probe(struct platform_device *pdev)
>         fimd_manager.ctx = ctx;
>         exynos_drm_manager_register(&fimd_manager);
>
> +       /*
> +        * We need to runtime pm to enable/disable sysmmu since it is a child of
> +        * this driver. Ideally, this would hang off the drm driver's runtime
> +        * operations, but we're not quite there yet.
> +        *
> +        * Tracked in crbug.com/264312

Argh, this (and the similar comment below) slipped by me, sorry about that.

Can you remove, or would you like to to send a new version?

Sean

> +        */
>         pm_runtime_enable(dev);
> -       pm_runtime_get_sync(dev);
>
>         for (win = 0; win < WINDOWS_NR; win++)
>                 fimd_clear_win(ctx, win);
> @@ -961,84 +961,23 @@ static int fimd_probe(struct platform_device *pdev)
>
>  static int fimd_remove(struct platform_device *pdev)
>  {
> -       struct device *dev = &pdev->dev;
>         struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
> -       struct fimd_context *ctx = mgr->ctx;
>
>         exynos_drm_manager_unregister(&fimd_manager);
>
> -       if (ctx->suspended)
> -               goto out;
> -
> -       pm_runtime_set_suspended(dev);
> -       pm_runtime_put_sync(dev);
> +       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
>
> -out:
> -       pm_runtime_disable(dev);
> +       pm_runtime_disable(&pdev->dev);
>
>         return 0;
>  }
>
> -#ifdef CONFIG_PM_SLEEP
> -static int fimd_suspend(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> -
> -       /*
> -        * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
> -        * called here, an error would be returned by that interface
> -        * because the usage_count of pm runtime is more than 1.
> -        */
> -       if (!pm_runtime_suspended(dev))
> -               return fimd_poweroff(mgr);
> -
> -       return 0;
> -}
> -
> -static int fimd_resume(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> -
> -       /*
> -        * if entered to sleep when lcd panel was on, the usage_count
> -        * of pm runtime would still be 1 so in this case, fimd driver
> -        * should be on directly not drawing on pm runtime interface.
> -        */
> -       if (pm_runtime_suspended(dev))
> -               return 0;
> -
> -       return fimd_poweron(mgr);
> -}
> -#endif
> -
> -#ifdef CONFIG_PM_RUNTIME
> -static int fimd_runtime_suspend(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> -
> -       return fimd_poweroff(mgr);
> -}
> -
> -static int fimd_runtime_resume(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> -
> -       return fimd_poweron(mgr);
> -}
> -#endif
> -
> -static const struct dev_pm_ops fimd_pm_ops = {
> -       SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
> -       SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
> -};
> -
>  struct platform_driver fimd_driver = {
>         .probe          = fimd_probe,
>         .remove         = fimd_remove,
>         .driver         = {
>                 .name   = "exynos4-fb",
>                 .owner  = THIS_MODULE,
> -               .pm     = &fimd_pm_ops,
>                 .of_match_table = fimd_driver_dt_match,
>         },
>  };
> diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
> index afc83c9..130b109 100644
> --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> @@ -28,7 +28,6 @@
>  #include <linux/interrupt.h>
>  #include <linux/irq.h>
>  #include <linux/delay.h>
> -#include <linux/pm_runtime.h>
>  #include <linux/clk.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/io.h>
> @@ -1771,7 +1770,6 @@ static void hdmi_poweroff(struct exynos_drm_display *display)
>         regulator_bulk_disable(res->regul_count, res->regul_bulk);
>
>         mutex_lock(&hdata->hdmi_mutex);
> -
>         hdata->powered = false;
>
>  out:
> @@ -1780,20 +1778,16 @@ out:
>
>  static void hdmi_dpms(struct exynos_drm_display *display, int mode)
>  {
> -       struct hdmi_context *hdata = display->ctx;
> -
>         DRM_DEBUG_KMS("mode %d\n", mode);
>
>         switch (mode) {
>         case DRM_MODE_DPMS_ON:
> -               if (pm_runtime_suspended(hdata->dev))
> -                       pm_runtime_get_sync(hdata->dev);
> +               hdmi_poweron(display);
>                 break;
>         case DRM_MODE_DPMS_STANDBY:
>         case DRM_MODE_DPMS_SUSPEND:
>         case DRM_MODE_DPMS_OFF:
> -               if (!pm_runtime_suspended(hdata->dev))
> -                       pm_runtime_put_sync(hdata->dev);
> +               hdmi_poweroff(display);
>                 break;
>         default:
>                 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
> @@ -2036,8 +2030,6 @@ static int hdmi_probe(struct platform_device *pdev)
>         hdmi_display.ctx = hdata;
>         exynos_drm_display_register(&hdmi_display);
>
> -       pm_runtime_enable(dev);
> -
>         return 0;
>
>  err_hdmiphy:
> @@ -2053,88 +2045,18 @@ static int hdmi_remove(struct platform_device *pdev)
>         struct exynos_drm_display *display = get_hdmi_display(dev);
>         struct hdmi_context *hdata = display->ctx;
>
> -       pm_runtime_disable(dev);
> -
>         put_device(&hdata->hdmiphy_port->dev);
>         put_device(&hdata->ddc_port->dev);
>
>         return 0;
>  }
>
> -#ifdef CONFIG_PM_SLEEP
> -static int hdmi_suspend(struct device *dev)
> -{
> -       struct exynos_drm_display *display = get_hdmi_display(dev);
> -       struct hdmi_context *hdata = display->ctx;
> -
> -       disable_irq(hdata->irq);
> -
> -       hdata->hpd = false;
> -       if (hdata->drm_dev)
> -               drm_helper_hpd_irq_event(hdata->drm_dev);
> -
> -       if (pm_runtime_suspended(dev)) {
> -               DRM_DEBUG_KMS("Already suspended\n");
> -               return 0;
> -       }
> -
> -       hdmi_poweroff(display);
> -
> -       return 0;
> -}
> -
> -static int hdmi_resume(struct device *dev)
> -{
> -       struct exynos_drm_display *display = get_hdmi_display(dev);
> -       struct hdmi_context *hdata = display->ctx;
> -
> -       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
> -
> -       enable_irq(hdata->irq);
> -
> -       if (!pm_runtime_suspended(dev)) {
> -               DRM_DEBUG_KMS("Already resumed\n");
> -               return 0;
> -       }
> -
> -       hdmi_poweron(display);
> -
> -       return 0;
> -}
> -#endif
> -
> -#ifdef CONFIG_PM_RUNTIME
> -static int hdmi_runtime_suspend(struct device *dev)
> -{
> -       struct exynos_drm_display *display = get_hdmi_display(dev);
> -
> -       hdmi_poweroff(display);
> -
> -       return 0;
> -}
> -
> -static int hdmi_runtime_resume(struct device *dev)
> -{
> -       struct exynos_drm_display *display = get_hdmi_display(dev);
> -
> -       hdmi_poweron(display);
> -
> -       return 0;
> -}
> -#endif
> -
> -static const struct dev_pm_ops hdmi_pm_ops = {
> -       SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
> -       SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
> -};
> -
>  struct platform_driver hdmi_driver = {
>         .probe          = hdmi_probe,
>         .remove         = hdmi_remove,
>         .driver         = {
>                 .name   = "exynos-hdmi",
>                 .owner  = THIS_MODULE,
> -               .pm     = &hdmi_pm_ops,
>                 .of_match_table = hdmi_match_types,
>         },
>  };
> diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
> index 39aed3e..985391d 100644
> --- a/drivers/gpu/drm/exynos/exynos_mixer.c
> +++ b/drivers/gpu/drm/exynos/exynos_mixer.c
> @@ -902,6 +902,8 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
>         ctx->powered = true;
>         mutex_unlock(&ctx->mixer_mutex);
>
> +       pm_runtime_get_sync(ctx->dev);
> +
>         clk_prepare_enable(res->mixer);
>         if (ctx->vp_enabled) {
>                 clk_prepare_enable(res->vp);
> @@ -934,6 +936,8 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
>                 clk_disable_unprepare(res->sclk_mixer);
>         }
>
> +       pm_runtime_put_sync(ctx->dev);
> +
>         mutex_lock(&ctx->mixer_mutex);
>         ctx->powered = false;
>
> @@ -943,18 +947,14 @@ out:
>
>  static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
>  {
> -       struct mixer_context *mixer_ctx = mgr->ctx;
> -
>         switch (mode) {
>         case DRM_MODE_DPMS_ON:
> -               if (pm_runtime_suspended(mixer_ctx->dev))
> -                       pm_runtime_get_sync(mixer_ctx->dev);
> +               mixer_poweron(mgr);
>                 break;
>         case DRM_MODE_DPMS_STANDBY:
>         case DRM_MODE_DPMS_SUSPEND:
>         case DRM_MODE_DPMS_OFF:
> -               if (!pm_runtime_suspended(mixer_ctx->dev))
> -                       pm_runtime_put_sync(mixer_ctx->dev);
> +               mixer_poweroff(mgr);
>                 break;
>         default:
>                 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
> @@ -1239,6 +1239,13 @@ static int mixer_probe(struct platform_device *pdev)
>         platform_set_drvdata(pdev, &mixer_manager);
>         exynos_drm_manager_register(&mixer_manager);
>
> +       /*
> +        * We need to runtime pm to enable/disable sysmmu since it is a child of
> +        * this driver. Ideally, this would hang off the drm driver's runtime
> +        * operations, but we're not quite there yet.
> +        *
> +        * Tracked in crbug.com/264312
> +        */
>         pm_runtime_enable(dev);
>
>         return 0;
> @@ -1258,66 +1265,10 @@ static int mixer_remove(struct platform_device *pdev)
>         return 0;
>  }
>
> -#ifdef CONFIG_PM_SLEEP
> -static int mixer_suspend(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> -
> -       if (pm_runtime_suspended(dev)) {
> -               DRM_DEBUG_KMS("Already suspended\n");
> -               return 0;
> -       }
> -
> -       mixer_poweroff(mgr);
> -
> -       return 0;
> -}
> -
> -static int mixer_resume(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> -
> -       if (!pm_runtime_suspended(dev)) {
> -               DRM_DEBUG_KMS("Already resumed\n");
> -               return 0;
> -       }
> -
> -       mixer_poweron(mgr);
> -
> -       return 0;
> -}
> -#endif
> -
> -#ifdef CONFIG_PM_RUNTIME
> -static int mixer_runtime_suspend(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> -
> -       mixer_poweroff(mgr);
> -
> -       return 0;
> -}
> -
> -static int mixer_runtime_resume(struct device *dev)
> -{
> -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> -
> -       mixer_poweron(mgr);
> -
> -       return 0;
> -}
> -#endif
> -
> -static const struct dev_pm_ops mixer_pm_ops = {
> -       SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
> -       SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
> -};
> -
>  struct platform_driver mixer_driver = {
>         .driver = {
>                 .name = "exynos-mixer",
>                 .owner = THIS_MODULE,
> -               .pm = &mixer_pm_ops,
>                 .of_match_table = mixer_match_types,
>         },
>         .probe = mixer_probe,
> --
> 1.8.4
>

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

* RE: [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv
  2013-10-16 20:40   ` Sean Paul
@ 2013-10-17  5:10     ` Inki Dae
  0 siblings, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-17  5:10 UTC (permalink / raw)
  To: 'Sean Paul', 'dri-devel'
  Cc: 'Stéphane Marchesin'



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Thursday, October 17, 2013 5:40 AM
> To: dri-devel; InKi Dae
> Cc: Dave Airlie; Tomasz Figa; Stéphane Marchesin; Sean Paul
> Subject: Re: [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in
> drm_drv
> 
> On Wed, Oct 16, 2013 at 3:26 PM, Sean Paul <seanpaul@chromium.org> wrote:
> > This patch removes all of the suspend/resume logic from the individual
> > drivers and consolidates it in drm_drv. This consolidation reduces the
> > number of functions which enable/disable the hardware to just one -- the
> > dpms callback. This ensures that we always power up/down in a consistent
> > manner.
> >
> > Signed-off-by: Sean Paul <seanpaul@chromium.org>
> > ---
> >
> > Changes in v2:
> >         - Added to the patchset
> >
> >  drivers/gpu/drm/exynos/exynos_drm_drv.c  | 97
> ++++++++++++++++++++++++++++++++
> >  drivers/gpu/drm/exynos/exynos_drm_fimd.c | 91 +++++--------------------
> -----
> >  drivers/gpu/drm/exynos/exynos_hdmi.c     | 82
+-------------------------
> -
> >  drivers/gpu/drm/exynos/exynos_mixer.c    | 75 +++++-------------------
> >  4 files changed, 127 insertions(+), 218 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> > index 03caa3a..91d6863 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
> > @@ -11,6 +11,7 @@
> >   * option) any later version.
> >   */
> >
> > +#include <linux/pm_runtime.h>
> >  #include <drm/drmP.h>
> >  #include <drm/drm_crtc_helper.h>
> >
> > @@ -51,6 +52,7 @@ static int exynos_drm_load(struct drm_device *dev,
> unsigned long flags)
> >                 return -ENOMEM;
> >
> >         INIT_LIST_HEAD(&private->pageflip_event_list);
> > +       dev_set_drvdata(dev->dev, dev);
> >         dev->dev_private = (void *)private;
> >
> >         /*
> > @@ -155,6 +157,41 @@ static int exynos_drm_unload(struct drm_device
*dev)
> >         return 0;
> >  }
> >
> > +static int exynos_drm_suspend(struct drm_device *dev, pm_message_t
> state)
> > +{
> > +       struct drm_connector *connector;
> > +
> > +       drm_modeset_lock_all(dev);
> > +       list_for_each_entry(connector, &dev->mode_config.connector_list,
> head) {
> > +               int old_dpms = connector->dpms;
> > +
> > +               if (connector->funcs->dpms)
> > +                       connector->funcs->dpms(connector,
DRM_MODE_DPMS_OFF);
> > +
> > +               /* Set the old mode back to the connector for resume */
> > +               connector->dpms = old_dpms;
> > +       }
> > +       drm_modeset_unlock_all(dev);
> > +
> > +       return 0;
> > +}
> > +
> > +static int exynos_drm_resume(struct drm_device *dev)
> > +{
> > +       struct drm_connector *connector;
> > +
> > +       drm_modeset_lock_all(dev);
> > +       list_for_each_entry(connector, &dev->mode_config.connector_list,
> head) {
> > +               if (connector->funcs->dpms)
> > +                       connector->funcs->dpms(connector,
connector->dpms);
> > +       }
> > +
> > +       drm_helper_resume_force_mode(dev);
> > +       drm_modeset_unlock_all(dev);
> > +
> > +       return 0;
> > +}
> > +
> >  static int exynos_drm_open(struct drm_device *dev, struct drm_file
> *file)
> >  {
> >         struct drm_exynos_file_private *file_priv;
> > @@ -262,6 +299,8 @@ static struct drm_driver exynos_drm_driver = {
> >                                         DRIVER_GEM | DRIVER_PRIME,
> >         .load                   = exynos_drm_load,
> >         .unload                 = exynos_drm_unload,
> > +       .suspend                = exynos_drm_suspend,
> > +       .resume                 = exynos_drm_resume,
> >         .open                   = exynos_drm_open,
> >         .preclose               = exynos_drm_preclose,
> >         .lastclose              = exynos_drm_lastclose,
> > @@ -293,6 +332,9 @@ static int exynos_drm_platform_probe(struct
> platform_device *pdev)
> >  {
> >         pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
> >
> > +       pm_runtime_enable(&pdev->dev);
> > +       pm_runtime_get_sync(&pdev->dev);
> > +
> >         return drm_platform_init(&exynos_drm_driver, pdev);
> >  }
> >
> > @@ -303,12 +345,67 @@ static int exynos_drm_platform_remove(struct
> platform_device *pdev)
> >         return 0;
> >  }
> >
> > +#ifdef CONFIG_PM_SLEEP
> > +static int exynos_drm_sys_suspend(struct device *dev)
> > +{
> > +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> > +       pm_message_t message;
> > +
> > +       if (pm_runtime_suspended(dev))
> > +               return 0;
> > +
> > +       message.event = PM_EVENT_SUSPEND;
> > +       return exynos_drm_suspend(drm_dev, message);
> > +}
> > +
> > +static int exynos_drm_sys_resume(struct device *dev)
> > +{
> > +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> > +
> > +       if (pm_runtime_suspended(dev))
> > +               return 0;
> > +
> > +       return exynos_drm_resume(drm_dev);
> > +}
> > +#endif
> > +
> > +#ifdef CONFIG_PM_RUNTIME
> > +static int exynos_drm_runtime_suspend(struct device *dev)
> > +{
> > +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> > +       pm_message_t message;
> > +
> > +       if (pm_runtime_suspended(dev))
> > +               return 0;
> > +
> > +       message.event = PM_EVENT_SUSPEND;
> > +       return exynos_drm_suspend(drm_dev, message);
> > +}
> > +
> > +static int exynos_drm_runtime_resume(struct device *dev)
> > +{
> > +       struct drm_device *drm_dev = dev_get_drvdata(dev);
> > +
> > +       if (!pm_runtime_suspended(dev))
> > +               return 0;
> > +
> > +       return exynos_drm_resume(drm_dev);
> > +}
> > +#endif
> > +
> > +static const struct dev_pm_ops exynos_drm_pm_ops = {
> > +       SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend,
> exynos_drm_sys_resume)
> > +       SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend,
> > +                       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,
> >         },
> >  };
> >
> > diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> > index ba12916..208e013 100644
> > --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> > +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
> > @@ -741,6 +741,8 @@ static int fimd_poweron(struct exynos_drm_manager
> *mgr)
> >
> >         ctx->suspended = false;
> >
> > +       pm_runtime_get_sync(ctx->dev);
> > +
> >         ret = clk_prepare_enable(ctx->bus_clk);
> >         if (ret < 0) {
> >                 DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n",
> ret);
> > @@ -794,32 +796,24 @@ static int fimd_poweroff(struct exynos_drm_manager
> *mgr)
> >         clk_disable_unprepare(ctx->lcd_clk);
> >         clk_disable_unprepare(ctx->bus_clk);
> >
> > +       pm_runtime_put_sync(ctx->dev);
> > +
> >         ctx->suspended = true;
> >         return 0;
> >  }
> >
> >  static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
> >  {
> > -       struct fimd_context *ctx = mgr->ctx;
> > -
> >         DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
> >
> >         switch (mode) {
> >         case DRM_MODE_DPMS_ON:
> > -               /*
> > -                * enable fimd hardware only if suspended status.
> > -                *
> > -                * P.S. fimd_dpms function would be called at booting
time
> so
> > -                * clk_enable could be called double time.
> > -                */
> > -               if (ctx->suspended)
> > -                       pm_runtime_get_sync(ctx->dev);
> > +               fimd_poweron(mgr);
> >                 break;
> >         case DRM_MODE_DPMS_STANDBY:
> >         case DRM_MODE_DPMS_SUSPEND:
> >         case DRM_MODE_DPMS_OFF:
> > -               if (!ctx->suspended)
> > -                       pm_runtime_put_sync(ctx->dev);
> > +               fimd_poweroff(mgr);
> >                 break;
> >         default:
> >                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
> > @@ -950,8 +944,14 @@ static int fimd_probe(struct platform_device *pdev)
> >         fimd_manager.ctx = ctx;
> >         exynos_drm_manager_register(&fimd_manager);
> >
> > +       /*
> > +        * We need to runtime pm to enable/disable sysmmu since it is a
> child of
> > +        * this driver. Ideally, this would hang off the drm driver's
> runtime
> > +        * operations, but we're not quite there yet.
> > +        *
> > +        * Tracked in crbug.com/264312
> 
> Argh, this (and the similar comment below) slipped by me, sorry about
that.
> 
> Can you remove, or would you like to to send a new version?
> 


I can do it.

Thanks,
Inki Dae

P.s. we didn't really think about this way. Actually, DRM driver contains
all device drivers; fimd, hdmi, g2d, and so on. So it's good idea that core
driver handles PM, and other sub drivers should take care of their own power
domain and clock according to dpms request from core driver. And with this
way, it seems that we could resolve power ordering issue when sleep ->
wakeup


> Sean
> 
> > +        */
> >         pm_runtime_enable(dev);
> > -       pm_runtime_get_sync(dev);
> >
> >         for (win = 0; win < WINDOWS_NR; win++)
> >                 fimd_clear_win(ctx, win);
> > @@ -961,84 +961,23 @@ static int fimd_probe(struct platform_device
*pdev)
> >
> >  static int fimd_remove(struct platform_device *pdev)
> >  {
> > -       struct device *dev = &pdev->dev;
> >         struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
> > -       struct fimd_context *ctx = mgr->ctx;
> >
> >         exynos_drm_manager_unregister(&fimd_manager);
> >
> > -       if (ctx->suspended)
> > -               goto out;
> > -
> > -       pm_runtime_set_suspended(dev);
> > -       pm_runtime_put_sync(dev);
> > +       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
> >
> > -out:
> > -       pm_runtime_disable(dev);
> > +       pm_runtime_disable(&pdev->dev);
> >
> >         return 0;
> >  }
> >
> > -#ifdef CONFIG_PM_SLEEP
> > -static int fimd_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> > -
> > -       /*
> > -        * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
> > -        * called here, an error would be returned by that interface
> > -        * because the usage_count of pm runtime is more than 1.
> > -        */
> > -       if (!pm_runtime_suspended(dev))
> > -               return fimd_poweroff(mgr);
> > -
> > -       return 0;
> > -}
> > -
> > -static int fimd_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> > -
> > -       /*
> > -        * if entered to sleep when lcd panel was on, the usage_count
> > -        * of pm runtime would still be 1 so in this case, fimd driver
> > -        * should be on directly not drawing on pm runtime interface.
> > -        */
> > -       if (pm_runtime_suspended(dev))
> > -               return 0;
> > -
> > -       return fimd_poweron(mgr);
> > -}
> > -#endif
> > -
> > -#ifdef CONFIG_PM_RUNTIME
> > -static int fimd_runtime_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> > -
> > -       return fimd_poweroff(mgr);
> > -}
> > -
> > -static int fimd_runtime_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_fimd_manager(dev);
> > -
> > -       return fimd_poweron(mgr);
> > -}
> > -#endif
> > -
> > -static const struct dev_pm_ops fimd_pm_ops = {
> > -       SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
> > -       SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume,
> NULL)
> > -};
> > -
> >  struct platform_driver fimd_driver = {
> >         .probe          = fimd_probe,
> >         .remove         = fimd_remove,
> >         .driver         = {
> >                 .name   = "exynos4-fb",
> >                 .owner  = THIS_MODULE,
> > -               .pm     = &fimd_pm_ops,
> >                 .of_match_table = fimd_driver_dt_match,
> >         },
> >  };
> > diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c
> b/drivers/gpu/drm/exynos/exynos_hdmi.c
> > index afc83c9..130b109 100644
> > --- a/drivers/gpu/drm/exynos/exynos_hdmi.c
> > +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
> > @@ -28,7 +28,6 @@
> >  #include <linux/interrupt.h>
> >  #include <linux/irq.h>
> >  #include <linux/delay.h>
> > -#include <linux/pm_runtime.h>
> >  #include <linux/clk.h>
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/io.h>
> > @@ -1771,7 +1770,6 @@ static void hdmi_poweroff(struct
> exynos_drm_display *display)
> >         regulator_bulk_disable(res->regul_count, res->regul_bulk);
> >
> >         mutex_lock(&hdata->hdmi_mutex);
> > -
> >         hdata->powered = false;
> >
> >  out:
> > @@ -1780,20 +1778,16 @@ out:
> >
> >  static void hdmi_dpms(struct exynos_drm_display *display, int mode)
> >  {
> > -       struct hdmi_context *hdata = display->ctx;
> > -
> >         DRM_DEBUG_KMS("mode %d\n", mode);
> >
> >         switch (mode) {
> >         case DRM_MODE_DPMS_ON:
> > -               if (pm_runtime_suspended(hdata->dev))
> > -                       pm_runtime_get_sync(hdata->dev);
> > +               hdmi_poweron(display);
> >                 break;
> >         case DRM_MODE_DPMS_STANDBY:
> >         case DRM_MODE_DPMS_SUSPEND:
> >         case DRM_MODE_DPMS_OFF:
> > -               if (!pm_runtime_suspended(hdata->dev))
> > -                       pm_runtime_put_sync(hdata->dev);
> > +               hdmi_poweroff(display);
> >                 break;
> >         default:
> >                 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
> > @@ -2036,8 +2030,6 @@ static int hdmi_probe(struct platform_device
*pdev)
> >         hdmi_display.ctx = hdata;
> >         exynos_drm_display_register(&hdmi_display);
> >
> > -       pm_runtime_enable(dev);
> > -
> >         return 0;
> >
> >  err_hdmiphy:
> > @@ -2053,88 +2045,18 @@ static int hdmi_remove(struct platform_device
> *pdev)
> >         struct exynos_drm_display *display = get_hdmi_display(dev);
> >         struct hdmi_context *hdata = display->ctx;
> >
> > -       pm_runtime_disable(dev);
> > -
> >         put_device(&hdata->hdmiphy_port->dev);
> >         put_device(&hdata->ddc_port->dev);
> >
> >         return 0;
> >  }
> >
> > -#ifdef CONFIG_PM_SLEEP
> > -static int hdmi_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_display *display = get_hdmi_display(dev);
> > -       struct hdmi_context *hdata = display->ctx;
> > -
> > -       disable_irq(hdata->irq);
> > -
> > -       hdata->hpd = false;
> > -       if (hdata->drm_dev)
> > -               drm_helper_hpd_irq_event(hdata->drm_dev);
> > -
> > -       if (pm_runtime_suspended(dev)) {
> > -               DRM_DEBUG_KMS("Already suspended\n");
> > -               return 0;
> > -       }
> > -
> > -       hdmi_poweroff(display);
> > -
> > -       return 0;
> > -}
> > -
> > -static int hdmi_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_display *display = get_hdmi_display(dev);
> > -       struct hdmi_context *hdata = display->ctx;
> > -
> > -       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
> > -
> > -       enable_irq(hdata->irq);
> > -
> > -       if (!pm_runtime_suspended(dev)) {
> > -               DRM_DEBUG_KMS("Already resumed\n");
> > -               return 0;
> > -       }
> > -
> > -       hdmi_poweron(display);
> > -
> > -       return 0;
> > -}
> > -#endif
> > -
> > -#ifdef CONFIG_PM_RUNTIME
> > -static int hdmi_runtime_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_display *display = get_hdmi_display(dev);
> > -
> > -       hdmi_poweroff(display);
> > -
> > -       return 0;
> > -}
> > -
> > -static int hdmi_runtime_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_display *display = get_hdmi_display(dev);
> > -
> > -       hdmi_poweron(display);
> > -
> > -       return 0;
> > -}
> > -#endif
> > -
> > -static const struct dev_pm_ops hdmi_pm_ops = {
> > -       SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
> > -       SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume,
> NULL)
> > -};
> > -
> >  struct platform_driver hdmi_driver = {
> >         .probe          = hdmi_probe,
> >         .remove         = hdmi_remove,
> >         .driver         = {
> >                 .name   = "exynos-hdmi",
> >                 .owner  = THIS_MODULE,
> > -               .pm     = &hdmi_pm_ops,
> >                 .of_match_table = hdmi_match_types,
> >         },
> >  };
> > diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c
> b/drivers/gpu/drm/exynos/exynos_mixer.c
> > index 39aed3e..985391d 100644
> > --- a/drivers/gpu/drm/exynos/exynos_mixer.c
> > +++ b/drivers/gpu/drm/exynos/exynos_mixer.c
> > @@ -902,6 +902,8 @@ static void mixer_poweron(struct exynos_drm_manager
> *mgr)
> >         ctx->powered = true;
> >         mutex_unlock(&ctx->mixer_mutex);
> >
> > +       pm_runtime_get_sync(ctx->dev);
> > +
> >         clk_prepare_enable(res->mixer);
> >         if (ctx->vp_enabled) {
> >                 clk_prepare_enable(res->vp);
> > @@ -934,6 +936,8 @@ static void mixer_poweroff(struct exynos_drm_manager
> *mgr)
> >                 clk_disable_unprepare(res->sclk_mixer);
> >         }
> >
> > +       pm_runtime_put_sync(ctx->dev);
> > +
> >         mutex_lock(&ctx->mixer_mutex);
> >         ctx->powered = false;
> >
> > @@ -943,18 +947,14 @@ out:
> >
> >  static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
> >  {
> > -       struct mixer_context *mixer_ctx = mgr->ctx;
> > -
> >         switch (mode) {
> >         case DRM_MODE_DPMS_ON:
> > -               if (pm_runtime_suspended(mixer_ctx->dev))
> > -                       pm_runtime_get_sync(mixer_ctx->dev);
> > +               mixer_poweron(mgr);
> >                 break;
> >         case DRM_MODE_DPMS_STANDBY:
> >         case DRM_MODE_DPMS_SUSPEND:
> >         case DRM_MODE_DPMS_OFF:
> > -               if (!pm_runtime_suspended(mixer_ctx->dev))
> > -                       pm_runtime_put_sync(mixer_ctx->dev);
> > +               mixer_poweroff(mgr);
> >                 break;
> >         default:
> >                 DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
> > @@ -1239,6 +1239,13 @@ static int mixer_probe(struct platform_device
> *pdev)
> >         platform_set_drvdata(pdev, &mixer_manager);
> >         exynos_drm_manager_register(&mixer_manager);
> >
> > +       /*
> > +        * We need to runtime pm to enable/disable sysmmu since it is a
> child of
> > +        * this driver. Ideally, this would hang off the drm driver's
> runtime
> > +        * operations, but we're not quite there yet.
> > +        *
> > +        * Tracked in crbug.com/264312
> > +        */
> >         pm_runtime_enable(dev);
> >
> >         return 0;
> > @@ -1258,66 +1265,10 @@ static int mixer_remove(struct platform_device
> *pdev)
> >         return 0;
> >  }
> >
> > -#ifdef CONFIG_PM_SLEEP
> > -static int mixer_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> > -
> > -       if (pm_runtime_suspended(dev)) {
> > -               DRM_DEBUG_KMS("Already suspended\n");
> > -               return 0;
> > -       }
> > -
> > -       mixer_poweroff(mgr);
> > -
> > -       return 0;
> > -}
> > -
> > -static int mixer_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> > -
> > -       if (!pm_runtime_suspended(dev)) {
> > -               DRM_DEBUG_KMS("Already resumed\n");
> > -               return 0;
> > -       }
> > -
> > -       mixer_poweron(mgr);
> > -
> > -       return 0;
> > -}
> > -#endif
> > -
> > -#ifdef CONFIG_PM_RUNTIME
> > -static int mixer_runtime_suspend(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> > -
> > -       mixer_poweroff(mgr);
> > -
> > -       return 0;
> > -}
> > -
> > -static int mixer_runtime_resume(struct device *dev)
> > -{
> > -       struct exynos_drm_manager *mgr = get_mixer_manager(dev);
> > -
> > -       mixer_poweron(mgr);
> > -
> > -       return 0;
> > -}
> > -#endif
> > -
> > -static const struct dev_pm_ops mixer_pm_ops = {
> > -       SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
> > -       SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume,
> NULL)
> > -};
> > -
> >  struct platform_driver mixer_driver = {
> >         .driver = {
> >                 .name = "exynos-mixer",
> >                 .owner = THIS_MODULE,
> > -               .pm = &mixer_pm_ops,
> >                 .of_match_table = mixer_match_types,
> >         },
> >         .probe = mixer_probe,
> > --
> > 1.8.4
> >

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

* RE: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-16 19:26 ` [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv Sean Paul
@ 2013-10-17  8:21   ` Inki Dae
  2013-10-17 14:37     ` Sean Paul
  2013-10-22 10:30   ` Inki Dae
  1 sibling, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-17  8:21 UTC (permalink / raw)
  To: 'Sean Paul', dri-devel; +Cc: marcheu



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Thursday, October 17, 2013 4:27 AM
> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
> Paul
> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> 
> This patch splits display and manager from subdrv. The result is that
> crtc functions can directly call into manager callbacks and encoder
> functions can directly call into display callbacks. This will allow
> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
> with common code.
> 
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
> 
> Changes in v2:
> 	- Pass display into display_ops instead of context

Sorry but it seems like more reasonable to pass device object into
display_ops and manager_ops.

I'm not sure but display_ops could be implemented in other framework based
driver such as CDF based lcd panel driver. So if you pass display - it's
specific to exynos drm framework - into display_ops, the other framework
based driver should include specific exynos drm header.

And another one, the patch 6 passes manager object to manager_ops, and for
this, you made the manager object to be set to driver data;
platform_set_drvdata(pdev, &manager). That isn't reasonable. Generally,
driver_data would point to device driver's context object.

Thanks,
Inki Dae

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-17  8:21   ` Inki Dae
@ 2013-10-17 14:37     ` Sean Paul
  2013-10-18  2:31       ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-17 14:37 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> Sent: Thursday, October 17, 2013 4:27 AM
>> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
>> Paul
>> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>
>> This patch splits display and manager from subdrv. The result is that
>> crtc functions can directly call into manager callbacks and encoder
>> functions can directly call into display callbacks. This will allow
>> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
>> with common code.
>>
>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> ---
>>
>> Changes in v2:
>>       - Pass display into display_ops instead of context
>
> Sorry but it seems like more reasonable to pass device object into
> display_ops and manager_ops.
>


So you've changed your mind from when you said the following?

>>> manager->ops->xxx(manager, ...);
>>> display->ops->xxx(display, ...);
>>>
>>> Agree.

It would have been nice if you had changed your mind *before* I
reworked everything. At any rate, I think it's still the right thing
to do.


> I'm not sure but display_ops could be implemented in other framework based
> driver such as CDF based lcd panel driver. So if you pass display - it's
> specific to exynos drm framework - into display_ops, the other framework
> based driver should include specific exynos drm header.
>

AFAIK, CDF will not land in its current separate-from-drm form, we
don't need to worry about this. Furthermore, these ops should just go
away and become drm_crtc/drm_encoder/drm_connector funcs anyways.


> And another one, the patch 6 passes manager object to manager_ops, and for
> this, you made the manager object to be set to driver data;
> platform_set_drvdata(pdev, &manager). That isn't reasonable. Generally,
> driver_data would point to device driver's context object.
>

I'm not sure why this isn't reasonable, but it's a moot point. The
driver data is only used up until we get rid of the pm ops, it needn't
be set at all once things go through dpms.

Sean


> Thanks,
> Inki Dae
>

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

* RE: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-17 14:37     ` Sean Paul
@ 2013-10-18  2:31       ` Inki Dae
  2013-10-21 14:46         ` Sean Paul
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-18  2:31 UTC (permalink / raw)
  To: 'Sean Paul'
  Cc: 'Stéphane Marchesin', 'dri-devel'



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Thursday, October 17, 2013 11:37 PM
> To: Inki Dae
> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> 
> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> Sent: Thursday, October 17, 2013 4:27 AM
> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
> >> Paul
> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >>
> >> This patch splits display and manager from subdrv. The result is that
> >> crtc functions can directly call into manager callbacks and encoder
> >> functions can directly call into display callbacks. This will allow
> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
> >> with common code.
> >>
> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> ---
> >>
> >> Changes in v2:
> >>       - Pass display into display_ops instead of context
> >
> > Sorry but it seems like more reasonable to pass device object into
> > display_ops and manager_ops.
> >
> 
> 
> So you've changed your mind from when you said the following?
> 
> >>> manager->ops->xxx(manager, ...);
> >>> display->ops->xxx(display, ...);
> >>>
> >>> Agree.
> 


True. Before that, My comment was to pass device object into display_ops and
manager_ops, and then you said the good solution is to pass manager and
display to each driver. At that time, I thought no matter how the callback
is called if the framework doesn't call callbacks of each driver with ctx.
So I agreed.


> It would have been nice if you had changed your mind *before* I
> reworked everything. At any rate, I think it's still the right thing
> to do.

Really sorry about that. And I will add new patch for it so you don't need
to concern about that.

> 
> 
> > I'm not sure but display_ops could be implemented in other framework
> based
> > driver such as CDF based lcd panel driver. So if you pass display - it's
> > specific to exynos drm framework - into display_ops, the other framework
> > based driver should include specific exynos drm header.
> >
> 
> AFAIK, CDF will not land in its current separate-from-drm form, we
> don't need to worry about this. Furthermore, these ops should just go
> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
> 

Can you assure the display_ops never implemented in other framework based
driver, not CDF? At any rate, I think all possibilities should be opened.

> 
> > And another one, the patch 6 passes manager object to manager_ops, and
> for
> > this, you made the manager object to be set to driver data;
> > platform_set_drvdata(pdev, &manager). That isn't reasonable. Generally,
> > driver_data would point to device driver's context object.
> >
> 
> I'm not sure why this isn't reasonable, but it's a moot point. The
> driver data is only used up until we get rid of the pm ops, it needn't
> be set at all once things go through dpms.
> 

Generally, device drivers can call its own internal functions, and they will
call that functions with ctx. However, if you set manager to driver_data
then that functions should be called with manager object and also internally
that functions should get ctx from the manager object. What is the purpose
of manager? Do you think it's reasonable?

Anyway, I'd like to say really sorry about inconvenient again. So I will fix
it. 

Thanks,
Inki Dae

> Sean
> 
> 
> > Thanks,
> > Inki Dae
> >

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-18  2:31       ` Inki Dae
@ 2013-10-21 14:46         ` Sean Paul
  2013-10-21 21:17           ` Sean Paul
  2013-10-22  4:55           ` Inki Dae
  0 siblings, 2 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-21 14:46 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> Sent: Thursday, October 17, 2013 11:37 PM
>> To: Inki Dae
>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>
>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> >
>> >
>> >> -----Original Message-----
>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> Sent: Thursday, October 17, 2013 4:27 AM
>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
>> >> Paul
>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>> >>
>> >> This patch splits display and manager from subdrv. The result is that
>> >> crtc functions can directly call into manager callbacks and encoder
>> >> functions can directly call into display callbacks. This will allow
>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
>> >> with common code.
>> >>
>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> >> ---
>> >>
>> >> Changes in v2:
>> >>       - Pass display into display_ops instead of context
>> >
>> > Sorry but it seems like more reasonable to pass device object into
>> > display_ops and manager_ops.
>> >
>>
>>
>> So you've changed your mind from when you said the following?
>>
>> >>> manager->ops->xxx(manager, ...);
>> >>> display->ops->xxx(display, ...);
>> >>>
>> >>> Agree.
>>
>
>
> True. Before that, My comment was to pass device object into display_ops and
> manager_ops, and then you said the good solution is to pass manager and
> display to each driver. At that time, I thought no matter how the callback
> is called if the framework doesn't call callbacks of each driver with ctx.
> So I agreed.
>
>
>> It would have been nice if you had changed your mind *before* I
>> reworked everything. At any rate, I think it's still the right thing
>> to do.
>
> Really sorry about that. And I will add new patch for it so you don't need
> to concern about that.
>
>>
>>
>> > I'm not sure but display_ops could be implemented in other framework
>> based
>> > driver such as CDF based lcd panel driver. So if you pass display - it's
>> > specific to exynos drm framework - into display_ops, the other framework
>> > based driver should include specific exynos drm header.
>> >
>>
>> AFAIK, CDF will not land in its current separate-from-drm form, we
>> don't need to worry about this. Furthermore, these ops should just go
>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>>
>
> Can you assure the display_ops never implemented in other framework based
> driver, not CDF? At any rate, I think all possibilities should be opened.
>

I don't think we should let an RFC framework make the code more
complicated for unclear benefit. By removing manager/display entirely,
we can get rid of a *lot* of other code that is basically just
plumbing drm hooks (exynos_drm_connector is a good example).

>>
>> > And another one, the patch 6 passes manager object to manager_ops, and
>> for
>> > this, you made the manager object to be set to driver data;
>> > platform_set_drvdata(pdev, &manager). That isn't reasonable. Generally,
>> > driver_data would point to device driver's context object.
>> >
>>
>> I'm not sure why this isn't reasonable, but it's a moot point. The
>> driver data is only used up until we get rid of the pm ops, it needn't
>> be set at all once things go through dpms.
>>
>
> Generally, device drivers can call its own internal functions, and they will
> call that functions with ctx. However, if you set manager to driver_data
> then that functions should be called with manager object and also internally
> that functions should get ctx from the manager object. What is the purpose
> of manager? Do you think it's reasonable?
>

So, to avoid setting the manager as the drvdata, we could implement
something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
mgr in ctx, but that creates a circular link between the two. IMO,
both of those solutions suck :)

I'd much rather just set drvdata to the manager and call the hook
directly. Like I said earlier, this is just a temporary step since we
remove these pm ops later in the patch series.

Sean


> Anyway, I'd like to say really sorry about inconvenient again. So I will fix
> it.
>
> Thanks,
> Inki Dae
>
>> Sean
>>
>>
>> > Thanks,
>> > Inki Dae
>> >
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-21 14:46         ` Sean Paul
@ 2013-10-21 21:17           ` Sean Paul
  2013-10-22  5:30             ` Inki Dae
  2013-10-22  4:55           ` Inki Dae
  1 sibling, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-21 21:17 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>
>>
>>> -----Original Message-----
>>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> Sent: Thursday, October 17, 2013 11:37 PM
>>> To: Inki Dae
>>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>>
>>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>> >
>>> >
>>> >> -----Original Message-----
>>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org; Sean
>>> >> Paul
>>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>> >>
>>> >> This patch splits display and manager from subdrv. The result is that
>>> >> crtc functions can directly call into manager callbacks and encoder
>>> >> functions can directly call into display callbacks. This will allow
>>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
>>> >> with common code.
>>> >>
>>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>> >> ---
>>> >>
>>> >> Changes in v2:
>>> >>       - Pass display into display_ops instead of context
>>> >
>>> > Sorry but it seems like more reasonable to pass device object into
>>> > display_ops and manager_ops.
>>> >
>>>
>>>
>>> So you've changed your mind from when you said the following?
>>>
>>> >>> manager->ops->xxx(manager, ...);
>>> >>> display->ops->xxx(display, ...);
>>> >>>
>>> >>> Agree.
>>>
>>
>>
>> True. Before that, My comment was to pass device object into display_ops and
>> manager_ops, and then you said the good solution is to pass manager and
>> display to each driver. At that time, I thought no matter how the callback
>> is called if the framework doesn't call callbacks of each driver with ctx.
>> So I agreed.
>>
>>
>>> It would have been nice if you had changed your mind *before* I
>>> reworked everything. At any rate, I think it's still the right thing
>>> to do.
>>
>> Really sorry about that. And I will add new patch for it so you don't need
>> to concern about that.
>>
>>>
>>>
>>> > I'm not sure but display_ops could be implemented in other framework
>>> based
>>> > driver such as CDF based lcd panel driver. So if you pass display - it's
>>> > specific to exynos drm framework - into display_ops, the other framework
>>> > based driver should include specific exynos drm header.
>>> >
>>>
>>> AFAIK, CDF will not land in its current separate-from-drm form, we
>>> don't need to worry about this. Furthermore, these ops should just go
>>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>>>
>>
>> Can you assure the display_ops never implemented in other framework based
>> driver, not CDF? At any rate, I think all possibilities should be opened.
>>
>
> I don't think we should let an RFC framework make the code more
> complicated for unclear benefit. By removing manager/display entirely,
> we can get rid of a *lot* of other code that is basically just
> plumbing drm hooks (exynos_drm_connector is a good example).
>

I hacked this up today to prove it out. Check out the top 5 commits in
https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-staging.
It removes exynos_drm_connector in favor of just implementing
drm_connector directly. This same treatment should be done for
exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
doing this.

As you can see, it cuts out a lot of code and removes an entire
abstraction layer. Much nicer :)

Sean

>>>
>>> > And another one, the patch 6 passes manager object to manager_ops, and
>>> for
>>> > this, you made the manager object to be set to driver data;
>>> > platform_set_drvdata(pdev, &manager). That isn't reasonable. Generally,
>>> > driver_data would point to device driver's context object.
>>> >
>>>
>>> I'm not sure why this isn't reasonable, but it's a moot point. The
>>> driver data is only used up until we get rid of the pm ops, it needn't
>>> be set at all once things go through dpms.
>>>
>>
>> Generally, device drivers can call its own internal functions, and they will
>> call that functions with ctx. However, if you set manager to driver_data
>> then that functions should be called with manager object and also internally
>> that functions should get ctx from the manager object. What is the purpose
>> of manager? Do you think it's reasonable?
>>
>
> So, to avoid setting the manager as the drvdata, we could implement
> something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
> callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
> fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
> mgr in ctx, but that creates a circular link between the two. IMO,
> both of those solutions suck :)
>
> I'd much rather just set drvdata to the manager and call the hook
> directly. Like I said earlier, this is just a temporary step since we
> remove these pm ops later in the patch series.
>
> Sean
>
>
>> Anyway, I'd like to say really sorry about inconvenient again. So I will fix
>> it.
>>
>> Thanks,
>> Inki Dae
>>
>>> Sean
>>>
>>>
>>> > Thanks,
>>> > Inki Dae
>>> >
>>

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

* RE: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-21 14:46         ` Sean Paul
  2013-10-21 21:17           ` Sean Paul
@ 2013-10-22  4:55           ` Inki Dae
  1 sibling, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-22  4:55 UTC (permalink / raw)
  To: 'Sean Paul'
  Cc: 'Stéphane Marchesin', 'dri-devel'



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Monday, October 21, 2013 11:47 PM
> To: Inki Dae
> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> 
> On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >
> >
> >> -----Original Message-----
> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> Sent: Thursday, October 17, 2013 11:37 PM
> >> To: Inki Dae
> >> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >>
> >> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com> wrote:
> >> >
> >> >
> >> >> -----Original Message-----
> >> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >> Sent: Thursday, October 17, 2013 4:27 AM
> >> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org;
> Sean
> >> >> Paul
> >> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >> >>
> >> >> This patch splits display and manager from subdrv. The result is
> that
> >> >> crtc functions can directly call into manager callbacks and encoder
> >> >> functions can directly call into display callbacks. This will allow
> >> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
> fimd/dp
> >> >> with common code.
> >> >>
> >> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> >> ---
> >> >>
> >> >> Changes in v2:
> >> >>       - Pass display into display_ops instead of context
> >> >
> >> > Sorry but it seems like more reasonable to pass device object into
> >> > display_ops and manager_ops.
> >> >
> >>
> >>
> >> So you've changed your mind from when you said the following?
> >>
> >> >>> manager->ops->xxx(manager, ...);
> >> >>> display->ops->xxx(display, ...);
> >> >>>
> >> >>> Agree.
> >>
> >
> >
> > True. Before that, My comment was to pass device object into display_ops
> and
> > manager_ops, and then you said the good solution is to pass manager and
> > display to each driver. At that time, I thought no matter how the
> callback
> > is called if the framework doesn't call callbacks of each driver with
> ctx.
> > So I agreed.
> >
> >
> >> It would have been nice if you had changed your mind *before* I
> >> reworked everything. At any rate, I think it's still the right thing
> >> to do.
> >
> > Really sorry about that. And I will add new patch for it so you don't
> need
> > to concern about that.
> >
> >>
> >>
> >> > I'm not sure but display_ops could be implemented in other framework
> >> based
> >> > driver such as CDF based lcd panel driver. So if you pass display -
> it's
> >> > specific to exynos drm framework - into display_ops, the other
> framework
> >> > based driver should include specific exynos drm header.
> >> >
> >>
> >> AFAIK, CDF will not land in its current separate-from-drm form, we
> >> don't need to worry about this. Furthermore, these ops should just go
> >> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
> >>
> >
> > Can you assure the display_ops never implemented in other framework
> based
> > driver, not CDF? At any rate, I think all possibilities should be
opened.
> >
> 
> I don't think we should let an RFC framework make the code more
> complicated for unclear benefit. By removing manager/display entirely,
> we can get rid of a *lot* of other code that is basically just
> plumbing drm hooks (exynos_drm_connector is a good example).
> 
> >>
> >> > And another one, the patch 6 passes manager object to manager_ops,
> and
> >> for
> >> > this, you made the manager object to be set to driver data;
> >> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
> Generally,
> >> > driver_data would point to device driver's context object.
> >> >
> >>
> >> I'm not sure why this isn't reasonable, but it's a moot point. The
> >> driver data is only used up until we get rid of the pm ops, it needn't
> >> be set at all once things go through dpms.
> >>
> >
> > Generally, device drivers can call its own internal functions, and they
> will
> > call that functions with ctx. However, if you set manager to driver_data
> > then that functions should be called with manager object and also
> internally
> > that functions should get ctx from the manager object. What is the
> purpose
> > of manager? Do you think it's reasonable?
> >
> 
> So, to avoid setting the manager as the drvdata, we could implement
> something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
> callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;

It's still better for manager to have device objet, mgr->dev, and each
device driver gets its own context of device object. By doing so, each
device driver would have no any dependency of framework. Just leave it as
the device driver's role to get its own context object.

> fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
> mgr in ctx, but that creates a circular link between the two. IMO,

The device drivers don't really need to know the manager object. So context
doesn't need to have manager. What is the purpose of manager? The purpose
would be for that Exynos framework calls sub driver's callbacks.

> both of those solutions suck :)
> 
> I'd much rather just set drvdata to the manager and call the hook
> directly. Like I said earlier, this is just a temporary step since we
> remove these pm ops later in the patch series.
> 
> Sean
> 
> 
> > Anyway, I'd like to say really sorry about inconvenient again. So I will
> fix
> > it.
> >
> > Thanks,
> > Inki Dae
> >
> >> Sean
> >>
> >>
> >> > Thanks,
> >> > Inki Dae
> >> >
> >

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

* RE: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-21 21:17           ` Sean Paul
@ 2013-10-22  5:30             ` Inki Dae
  2013-10-22 13:45               ` Sean Paul
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-22  5:30 UTC (permalink / raw)
  To: 'Sean Paul'
  Cc: 'Stéphane Marchesin', 'dri-devel'



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Tuesday, October 22, 2013 6:18 AM
> To: Inki Dae
> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> 
> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org> wrote:
> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >>
> >>
> >>> -----Original Message-----
> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >>> Sent: Thursday, October 17, 2013 11:37 PM
> >>> To: Inki Dae
> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >>>
> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
wrote:
> >>> >
> >>> >
> >>> >> -----Original Message-----
> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org;
> Sean
> >>> >> Paul
> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >>> >>
> >>> >> This patch splits display and manager from subdrv. The result is
> that
> >>> >> crtc functions can directly call into manager callbacks and encoder
> >>> >> functions can directly call into display callbacks. This will allow
> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
> fimd/dp
> >>> >> with common code.
> >>> >>
> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >>> >> ---
> >>> >>
> >>> >> Changes in v2:
> >>> >>       - Pass display into display_ops instead of context
> >>> >
> >>> > Sorry but it seems like more reasonable to pass device object into
> >>> > display_ops and manager_ops.
> >>> >
> >>>
> >>>
> >>> So you've changed your mind from when you said the following?
> >>>
> >>> >>> manager->ops->xxx(manager, ...);
> >>> >>> display->ops->xxx(display, ...);
> >>> >>>
> >>> >>> Agree.
> >>>
> >>
> >>
> >> True. Before that, My comment was to pass device object into
> display_ops and
> >> manager_ops, and then you said the good solution is to pass manager and
> >> display to each driver. At that time, I thought no matter how the
> callback
> >> is called if the framework doesn't call callbacks of each driver with
> ctx.
> >> So I agreed.
> >>
> >>
> >>> It would have been nice if you had changed your mind *before* I
> >>> reworked everything. At any rate, I think it's still the right thing
> >>> to do.
> >>
> >> Really sorry about that. And I will add new patch for it so you don't
> need
> >> to concern about that.
> >>
> >>>
> >>>
> >>> > I'm not sure but display_ops could be implemented in other framework
> >>> based
> >>> > driver such as CDF based lcd panel driver. So if you pass display -
> it's
> >>> > specific to exynos drm framework - into display_ops, the other
> framework
> >>> > based driver should include specific exynos drm header.
> >>> >
> >>>
> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
> >>> don't need to worry about this. Furthermore, these ops should just go
> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
> >>>
> >>
> >> Can you assure the display_ops never implemented in other framework
> based
> >> driver, not CDF? At any rate, I think all possibilities should be
> opened.
> >>
> >
> > I don't think we should let an RFC framework make the code more
> > complicated for unclear benefit. By removing manager/display entirely,
> > we can get rid of a *lot* of other code that is basically just
> > plumbing drm hooks (exynos_drm_connector is a good example).
> >
> 
> I hacked this up today to prove it out. Check out the top 5 commits in
> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
> staging.
> It removes exynos_drm_connector in favor of just implementing
> drm_connector directly. This same treatment should be done for
> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
> doing this.
> 
> As you can see, it cuts out a lot of code and removes an entire
> abstraction layer. Much nicer :)
> 

It seems that you implements connector in each device driver. Can't they be
combined as common spot, exynos_connector, again to avoid codes from
duplicated? :) The abstraction layer you mentioned also means a common spot.
Another one, you patch also makes each sub driver have strongly dependency
of drm framework. So how we can support existing backlight and lcd class
based lcd panel drivers if the connector is implemented in each device
driver later?  the drm header files should be included in
drivers/video/backlight/xxx_lcd.c? 

And, I will introduce a new framework to support existing lcd panel drivers
and display bus drivers soon; as of now for Exynos drm, and the framework is
being tested internally. With this framework, encoder and connector will be
created when lcd panel or display bus driver such as eDP is probed: it
doesn’t really need to create encoder and connector in advance if lcd panel
or display bus driver isn't probed yet. Regardless of crtc, and encoder and
connector creation order, when last one is created, crtc and connector will
be connected each other. And exynos_drm_display could be implemented in
other frameworks if we have common structure for display device driver. And
also the framework will support lvds driver according to Linux device driver
model.

Thanks,
Inki Dae

> Sean
> 
> >>>
> >>> > And another one, the patch 6 passes manager object to manager_ops,
> and
> >>> for
> >>> > this, you made the manager object to be set to driver data;
> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
> Generally,
> >>> > driver_data would point to device driver's context object.
> >>> >
> >>>
> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
> >>> driver data is only used up until we get rid of the pm ops, it needn't
> >>> be set at all once things go through dpms.
> >>>
> >>
> >> Generally, device drivers can call its own internal functions, and they
> will
> >> call that functions with ctx. However, if you set manager to
> driver_data
> >> then that functions should be called with manager object and also
> internally
> >> that functions should get ctx from the manager object. What is the
> purpose
> >> of manager? Do you think it's reasonable?
> >>
> >
> > So, to avoid setting the manager as the drvdata, we could implement
> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
> > mgr in ctx, but that creates a circular link between the two. IMO,
> > both of those solutions suck :)
> >
> > I'd much rather just set drvdata to the manager and call the hook
> > directly. Like I said earlier, this is just a temporary step since we
> > remove these pm ops later in the patch series.
> >
> > Sean
> >
> >
> >> Anyway, I'd like to say really sorry about inconvenient again. So I
> will fix
> >> it.
> >>
> >> Thanks,
> >> Inki Dae
> >>
> >>> Sean
> >>>
> >>>
> >>> > Thanks,
> >>> > Inki Dae
> >>> >
> >>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-16 19:26 ` [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv Sean Paul
  2013-10-17  8:21   ` Inki Dae
@ 2013-10-22 10:30   ` Inki Dae
  2013-10-23  5:18     ` Inki Dae
  1 sibling, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-22 10:30 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list

2013/10/17 Sean Paul <seanpaul@chromium.org>:
> This patch splits display and manager from subdrv. The result is that
> crtc functions can directly call into manager callbacks and encoder
> functions can directly call into display callbacks. This will allow
> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
> with common code.
>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> ---
>
> Changes in v2:
>         - Pass display into display_ops instead of context
>
>  drivers/gpu/drm/exynos/exynos_drm_connector.c |  50 ++-
>  drivers/gpu/drm/exynos/exynos_drm_core.c      | 181 ++++++++---
>  drivers/gpu/drm/exynos/exynos_drm_crtc.c      | 115 +++++--
>  drivers/gpu/drm/exynos/exynos_drm_crtc.h      |  20 +-
>  drivers/gpu/drm/exynos/exynos_drm_drv.c       |  29 +-
>  drivers/gpu/drm/exynos/exynos_drm_drv.h       | 106 +++---
>  drivers/gpu/drm/exynos/exynos_drm_encoder.c   | 258 ++-------------
>  drivers/gpu/drm/exynos/exynos_drm_encoder.h   |  18 +-
>  drivers/gpu/drm/exynos/exynos_drm_fb.c        |   4 +-
>  drivers/gpu/drm/exynos/exynos_drm_fimd.c      | 161 +++++----
>  drivers/gpu/drm/exynos/exynos_drm_hdmi.c      | 449 --------------------------

Build error. it seems that you missed vidi module. Can you consider
vidi module also?

Thanks,
Inki Dae

>  drivers/gpu/drm/exynos/exynos_drm_hdmi.h      |   2 +
>  drivers/gpu/drm/exynos/exynos_drm_plane.c     |  15 +-
>  13 files changed, 466 insertions(+), 942 deletions(-)
>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-22  5:30             ` Inki Dae
@ 2013-10-22 13:45               ` Sean Paul
  2013-10-23  2:28                 ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-22 13:45 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
>
>
>> -----Original Message-----
>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> Sent: Tuesday, October 22, 2013 6:18 AM
>> To: Inki Dae
>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>
>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org> wrote:
>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> >>
>> >>
>> >>> -----Original Message-----
>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>> >>> To: Inki Dae
>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>> >>>
>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
> wrote:
>> >>> >
>> >>> >
>> >>> >> -----Original Message-----
>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org;
>> Sean
>> >>> >> Paul
>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>> >>> >>
>> >>> >> This patch splits display and manager from subdrv. The result is
>> that
>> >>> >> crtc functions can directly call into manager callbacks and encoder
>> >>> >> functions can directly call into display callbacks. This will allow
>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
>> fimd/dp
>> >>> >> with common code.
>> >>> >>
>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> >>> >> ---
>> >>> >>
>> >>> >> Changes in v2:
>> >>> >>       - Pass display into display_ops instead of context
>> >>> >
>> >>> > Sorry but it seems like more reasonable to pass device object into
>> >>> > display_ops and manager_ops.
>> >>> >
>> >>>
>> >>>
>> >>> So you've changed your mind from when you said the following?
>> >>>
>> >>> >>> manager->ops->xxx(manager, ...);
>> >>> >>> display->ops->xxx(display, ...);
>> >>> >>>
>> >>> >>> Agree.
>> >>>
>> >>
>> >>
>> >> True. Before that, My comment was to pass device object into
>> display_ops and
>> >> manager_ops, and then you said the good solution is to pass manager and
>> >> display to each driver. At that time, I thought no matter how the
>> callback
>> >> is called if the framework doesn't call callbacks of each driver with
>> ctx.
>> >> So I agreed.
>> >>
>> >>
>> >>> It would have been nice if you had changed your mind *before* I
>> >>> reworked everything. At any rate, I think it's still the right thing
>> >>> to do.
>> >>
>> >> Really sorry about that. And I will add new patch for it so you don't
>> need
>> >> to concern about that.
>> >>
>> >>>
>> >>>
>> >>> > I'm not sure but display_ops could be implemented in other framework
>> >>> based
>> >>> > driver such as CDF based lcd panel driver. So if you pass display -
>> it's
>> >>> > specific to exynos drm framework - into display_ops, the other
>> framework
>> >>> > based driver should include specific exynos drm header.
>> >>> >
>> >>>
>> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
>> >>> don't need to worry about this. Furthermore, these ops should just go
>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>> >>>
>> >>
>> >> Can you assure the display_ops never implemented in other framework
>> based
>> >> driver, not CDF? At any rate, I think all possibilities should be
>> opened.
>> >>
>> >
>> > I don't think we should let an RFC framework make the code more
>> > complicated for unclear benefit. By removing manager/display entirely,
>> > we can get rid of a *lot* of other code that is basically just
>> > plumbing drm hooks (exynos_drm_connector is a good example).
>> >
>>
>> I hacked this up today to prove it out. Check out the top 5 commits in
>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>> staging.
>> It removes exynos_drm_connector in favor of just implementing
>> drm_connector directly. This same treatment should be done for
>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
>> doing this.
>>
>> As you can see, it cuts out a lot of code and removes an entire
>> abstraction layer. Much nicer :)
>>
>
> It seems that you implements connector in each device driver. Can't they be
> combined as common spot, exynos_connector, again to avoid codes from
> duplicated? :)

There's nothing of substance being duplicated. In fact, by getting rid
of the exynos_drm_connector layer, we deleted 150 lines. If you really
take a look at exynos_drm_connector, it's not doing anything useful.
All it does is translate the drm callbacks into display callbacks, so
I think it's much better to just implement the drm callbacks directly.

There are a bunch of real bugs that we've found as a result of having
these abstraction layers. Take, for example, dpms. Before this
patchset, dpms for fimd was being tracked separately in fimd driver,
exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
Furthermore, during suspend, only fimd driver's dpms state was
updated, so the others were incorrect. There was also this weird
gymnastics that had to happen when dpms was changed in the encoder
since it had to walk up to the connector level to change its dpms
state. If fimd just directly implemented
drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
problem wouldn't exist. The same goes for HDMI/mixer.

Take a look at exynos_drm_encoder.c  in my tree
(https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
what does it do that's useful to abstract? All that it does is just
call display ops, it's completely useless. The same is true for
exynos_drm_connector, it's just dead weight. There is some useful
stuff in exynos_drm_crtc for page flipping, that would be better
served as a helper library, though.

> The abstraction layer you mentioned also means a common spot.
> Another one, you patch also makes each sub driver have strongly dependency
> of drm framework. So how we can support existing backlight and lcd class
> based lcd panel drivers if the connector is implemented in each device
> driver later?  the drm header files should be included in
> drivers/video/backlight/xxx_lcd.c?
>

drm_bridge or drm_panel seem like good candidates for this.


> And, I will introduce a new framework to support existing lcd panel drivers
> and display bus drivers soon; as of now for Exynos drm, and the framework is
> being tested internally. With this framework, encoder and connector will be
> created when lcd panel or display bus driver such as eDP is probed: it
> doesn’t really need to create encoder and connector in advance if lcd panel
> or display bus driver isn't probed yet. Regardless of crtc, and encoder and
> connector creation order, when last one is created, crtc and connector will
> be connected each other. And exynos_drm_display could be implemented in
> other frameworks if we have common structure for display device driver. And
> also the framework will support lvds driver according to Linux device driver
> model.
>

I don't really follow what you're trying to do here, but I think we
should be moving in the direction of fewer abstractions in the exynos
driver, not more :)

Sean



> Thanks,
> Inki Dae
>
>> Sean
>>
>> >>>
>> >>> > And another one, the patch 6 passes manager object to manager_ops,
>> and
>> >>> for
>> >>> > this, you made the manager object to be set to driver data;
>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
>> Generally,
>> >>> > driver_data would point to device driver's context object.
>> >>> >
>> >>>
>> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
>> >>> driver data is only used up until we get rid of the pm ops, it needn't
>> >>> be set at all once things go through dpms.
>> >>>
>> >>
>> >> Generally, device drivers can call its own internal functions, and they
>> will
>> >> call that functions with ctx. However, if you set manager to
>> driver_data
>> >> then that functions should be called with manager object and also
>> internally
>> >> that functions should get ctx from the manager object. What is the
>> purpose
>> >> of manager? Do you think it's reasonable?
>> >>
>> >
>> > So, to avoid setting the manager as the drvdata, we could implement
>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
>> > mgr in ctx, but that creates a circular link between the two. IMO,
>> > both of those solutions suck :)
>> >
>> > I'd much rather just set drvdata to the manager and call the hook
>> > directly. Like I said earlier, this is just a temporary step since we
>> > remove these pm ops later in the patch series.
>> >
>> > Sean
>> >
>> >
>> >> Anyway, I'd like to say really sorry about inconvenient again. So I
>> will fix
>> >> it.
>> >>
>> >> Thanks,
>> >> Inki Dae
>> >>
>> >>> Sean
>> >>>
>> >>>
>> >>> > Thanks,
>> >>> > Inki Dae
>> >>> >
>> >>
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-22 13:45               ` Sean Paul
@ 2013-10-23  2:28                 ` Inki Dae
  2013-10-23  2:40                   ` Stéphane Marchesin
  2013-10-23  3:39                   ` Sean Paul
  0 siblings, 2 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-23  2:28 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

2013/10/22 Sean Paul <seanpaul@chromium.org>:
> On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>
>>
>>> -----Original Message-----
>>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> Sent: Tuesday, October 22, 2013 6:18 AM
>>> To: Inki Dae
>>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>>
>>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org> wrote:
>>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>> >>
>>> >>
>>> >>> -----Original Message-----
>>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>> >>> To: Inki Dae
>>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>> >>>
>>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
>> wrote:
>>> >>> >
>>> >>> >
>>> >>> >> -----Original Message-----
>>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org;
>>> Sean
>>> >>> >> Paul
>>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>> >>> >>
>>> >>> >> This patch splits display and manager from subdrv. The result is
>>> that
>>> >>> >> crtc functions can directly call into manager callbacks and encoder
>>> >>> >> functions can directly call into display callbacks. This will allow
>>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
>>> fimd/dp
>>> >>> >> with common code.
>>> >>> >>
>>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>> >>> >> ---
>>> >>> >>
>>> >>> >> Changes in v2:
>>> >>> >>       - Pass display into display_ops instead of context
>>> >>> >
>>> >>> > Sorry but it seems like more reasonable to pass device object into
>>> >>> > display_ops and manager_ops.
>>> >>> >
>>> >>>
>>> >>>
>>> >>> So you've changed your mind from when you said the following?
>>> >>>
>>> >>> >>> manager->ops->xxx(manager, ...);
>>> >>> >>> display->ops->xxx(display, ...);
>>> >>> >>>
>>> >>> >>> Agree.
>>> >>>
>>> >>
>>> >>
>>> >> True. Before that, My comment was to pass device object into
>>> display_ops and
>>> >> manager_ops, and then you said the good solution is to pass manager and
>>> >> display to each driver. At that time, I thought no matter how the
>>> callback
>>> >> is called if the framework doesn't call callbacks of each driver with
>>> ctx.
>>> >> So I agreed.
>>> >>
>>> >>
>>> >>> It would have been nice if you had changed your mind *before* I
>>> >>> reworked everything. At any rate, I think it's still the right thing
>>> >>> to do.
>>> >>
>>> >> Really sorry about that. And I will add new patch for it so you don't
>>> need
>>> >> to concern about that.
>>> >>
>>> >>>
>>> >>>
>>> >>> > I'm not sure but display_ops could be implemented in other framework
>>> >>> based
>>> >>> > driver such as CDF based lcd panel driver. So if you pass display -
>>> it's
>>> >>> > specific to exynos drm framework - into display_ops, the other
>>> framework
>>> >>> > based driver should include specific exynos drm header.
>>> >>> >
>>> >>>
>>> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
>>> >>> don't need to worry about this. Furthermore, these ops should just go
>>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>>> >>>
>>> >>
>>> >> Can you assure the display_ops never implemented in other framework
>>> based
>>> >> driver, not CDF? At any rate, I think all possibilities should be
>>> opened.
>>> >>
>>> >
>>> > I don't think we should let an RFC framework make the code more
>>> > complicated for unclear benefit. By removing manager/display entirely,
>>> > we can get rid of a *lot* of other code that is basically just
>>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>> >
>>>
>>> I hacked this up today to prove it out. Check out the top 5 commits in
>>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>> staging.
>>> It removes exynos_drm_connector in favor of just implementing
>>> drm_connector directly. This same treatment should be done for
>>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
>>> doing this.
>>>
>>> As you can see, it cuts out a lot of code and removes an entire
>>> abstraction layer. Much nicer :)
>>>
>>
>> It seems that you implements connector in each device driver. Can't they be
>> combined as common spot, exynos_connector, again to avoid codes from
>> duplicated? :)
>
> There's nothing of substance being duplicated.

Not true. xxx_create_connector is duplicated.

> In fact, by getting rid
> of the exynos_drm_connector layer, we deleted 150 lines. If you really
> take a look at exynos_drm_connector, it's not doing anything useful.

No, That is for each driver has no any dependency of drm framework.

> All it does is translate the drm callbacks into display callbacks, so
> I think it's much better to just implement the drm callbacks directly.
>

No, It has strongly dependency of drm framework. Assume that we
implemented the drm callbacks directly, and then some features are
added to drm framework, drm_connector side. At this time, we will have
to take care of each device driver according to the change. That is
really not good. Why device drivers should have dependency of drm
framework? Just to reduce line counts?

> There are a bunch of real bugs that we've found as a result of having
> these abstraction layers. Take, for example, dpms. Before this
> patchset, dpms for fimd was being tracked separately in fimd driver,
> exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
> Furthermore, during suspend, only fimd driver's dpms state was
> updated, so the others were incorrect. There was also this weird
> gymnastics that had to happen when dpms was changed in the encoder
> since it had to walk up to the connector level to change its dpms
> state. If fimd just directly implemented
> drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
> problem wouldn't exist. The same goes for HDMI/mixer.
>

That is a issue we should take care of by using the independent layer.
Then, aren't you take care of that well with the re-factoring patch
set? :)  It seems that you are outside real point.

> Take a look at exynos_drm_encoder.c  in my tree
> (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
> what does it do that's useful to abstract? All that it does is just
> call display ops, it's completely useless. The same is true for
> exynos_drm_connector, it's just dead weight. There is some useful
> stuff in exynos_drm_crtc for page flipping, that would be better
> served as a helper library, though.
>
>> The abstraction layer you mentioned also means a common spot.
>> Another one, you patch also makes each sub driver have strongly dependency
>> of drm framework. So how we can support existing backlight and lcd class
>> based lcd panel drivers if the connector is implemented in each device
>> driver later?  the drm header files should be included in
>> drivers/video/backlight/xxx_lcd.c?
>>
>
> drm_bridge or drm_panel seem like good candidates for this.
>

Yes, exynos_drm_display could be replaced with drm_panel later if the
drm_panel can be merged to mainline.

>
>> And, I will introduce a new framework to support existing lcd panel drivers
>> and display bus drivers soon; as of now for Exynos drm, and the framework is
>> being tested internally. With this framework, encoder and connector will be
>> created when lcd panel or display bus driver such as eDP is probed: it
>> doesn’t really need to create encoder and connector in advance if lcd panel
>> or display bus driver isn't probed yet. Regardless of crtc, and encoder and
>> connector creation order, when last one is created, crtc and connector will
>> be connected each other. And exynos_drm_display could be implemented in
>> other frameworks if we have common structure for display device driver. And
>> also the framework will support lvds driver according to Linux device driver
>> model.
>>
>
> I don't really follow what you're trying to do here, but I think we
> should be moving in the direction of fewer abstractions in the exynos
> driver, not more :)
>

Not abstraction layer, just a bridge for connecting crtc and its
corresponding encoder/connector, and lvds regardless of creation
order, and for connecting drm connector and other framework based
display ops such as drm_panel later.

> Sean
>
>
>
>> Thanks,
>> Inki Dae
>>
>>> Sean
>>>
>>> >>>
>>> >>> > And another one, the patch 6 passes manager object to manager_ops,
>>> and
>>> >>> for
>>> >>> > this, you made the manager object to be set to driver data;
>>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
>>> Generally,
>>> >>> > driver_data would point to device driver's context object.
>>> >>> >
>>> >>>
>>> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
>>> >>> driver data is only used up until we get rid of the pm ops, it needn't
>>> >>> be set at all once things go through dpms.
>>> >>>
>>> >>
>>> >> Generally, device drivers can call its own internal functions, and they
>>> will
>>> >> call that functions with ctx. However, if you set manager to
>>> driver_data
>>> >> then that functions should be called with manager object and also
>>> internally
>>> >> that functions should get ctx from the manager object. What is the
>>> purpose
>>> >> of manager? Do you think it's reasonable?
>>> >>
>>> >
>>> > So, to avoid setting the manager as the drvdata, we could implement
>>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
>>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
>>> > mgr in ctx, but that creates a circular link between the two. IMO,
>>> > both of those solutions suck :)
>>> >
>>> > I'd much rather just set drvdata to the manager and call the hook
>>> > directly. Like I said earlier, this is just a temporary step since we
>>> > remove these pm ops later in the patch series.
>>> >
>>> > Sean
>>> >
>>> >
>>> >> Anyway, I'd like to say really sorry about inconvenient again. So I
>>> will fix
>>> >> it.
>>> >>
>>> >> Thanks,
>>> >> Inki Dae
>>> >>
>>> >>> Sean
>>> >>>
>>> >>>
>>> >>> > Thanks,
>>> >>> > Inki Dae
>>> >>> >
>>> >>
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  2:28                 ` Inki Dae
@ 2013-10-23  2:40                   ` Stéphane Marchesin
  2013-10-23  3:38                     ` Inki Dae
  2013-10-23  3:39                   ` Sean Paul
  1 sibling, 1 reply; 93+ messages in thread
From: Stéphane Marchesin @ 2013-10-23  2:40 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 12432 bytes --]

On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com> wrote:

> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
> >>
> >>
> >>> -----Original Message-----
> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >>> Sent: Tuesday, October 22, 2013 6:18 AM
> >>> To: Inki Dae
> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> >>>
> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org>
> wrote:
> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com>
> wrote:
> >>> >>
> >>> >>
> >>> >>> -----Original Message-----
> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
> >>> >>> To: Inki Dae
> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
> manager/display/subdrv
> >>> >>>
> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
> >> wrote:
> >>> >>> >
> >>> >>> >
> >>> >>> >> -----Original Message-----
> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
> marcheu@chromium.org;
> >>> Sean
> >>> >>> >> Paul
> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
> manager/display/subdrv
> >>> >>> >>
> >>> >>> >> This patch splits display and manager from subdrv. The result is
> >>> that
> >>> >>> >> crtc functions can directly call into manager callbacks and
> encoder
> >>> >>> >> functions can directly call into display callbacks. This will
> allow
> >>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
> >>> fimd/dp
> >>> >>> >> with common code.
> >>> >>> >>
> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >>> >>> >> ---
> >>> >>> >>
> >>> >>> >> Changes in v2:
> >>> >>> >>       - Pass display into display_ops instead of context
> >>> >>> >
> >>> >>> > Sorry but it seems like more reasonable to pass device object
> into
> >>> >>> > display_ops and manager_ops.
> >>> >>> >
> >>> >>>
> >>> >>>
> >>> >>> So you've changed your mind from when you said the following?
> >>> >>>
> >>> >>> >>> manager->ops->xxx(manager, ...);
> >>> >>> >>> display->ops->xxx(display, ...);
> >>> >>> >>>
> >>> >>> >>> Agree.
> >>> >>>
> >>> >>
> >>> >>
> >>> >> True. Before that, My comment was to pass device object into
> >>> display_ops and
> >>> >> manager_ops, and then you said the good solution is to pass manager
> and
> >>> >> display to each driver. At that time, I thought no matter how the
> >>> callback
> >>> >> is called if the framework doesn't call callbacks of each driver
> with
> >>> ctx.
> >>> >> So I agreed.
> >>> >>
> >>> >>
> >>> >>> It would have been nice if you had changed your mind *before* I
> >>> >>> reworked everything. At any rate, I think it's still the right
> thing
> >>> >>> to do.
> >>> >>
> >>> >> Really sorry about that. And I will add new patch for it so you
> don't
> >>> need
> >>> >> to concern about that.
> >>> >>
> >>> >>>
> >>> >>>
> >>> >>> > I'm not sure but display_ops could be implemented in other
> framework
> >>> >>> based
> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
> display -
> >>> it's
> >>> >>> > specific to exynos drm framework - into display_ops, the other
> >>> framework
> >>> >>> > based driver should include specific exynos drm header.
> >>> >>> >
> >>> >>>
> >>> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
> >>> >>> don't need to worry about this. Furthermore, these ops should just
> go
> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
> >>> >>>
> >>> >>
> >>> >> Can you assure the display_ops never implemented in other framework
> >>> based
> >>> >> driver, not CDF? At any rate, I think all possibilities should be
> >>> opened.
> >>> >>
> >>> >
> >>> > I don't think we should let an RFC framework make the code more
> >>> > complicated for unclear benefit. By removing manager/display
> entirely,
> >>> > we can get rid of a *lot* of other code that is basically just
> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
> >>> >
> >>>
> >>> I hacked this up today to prove it out. Check out the top 5 commits in
> >>>
> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
> >>> staging.
> >>> It removes exynos_drm_connector in favor of just implementing
> >>> drm_connector directly. This same treatment should be done for
> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
> >>> doing this.
> >>>
> >>> As you can see, it cuts out a lot of code and removes an entire
> >>> abstraction layer. Much nicer :)
> >>>
> >>
> >> It seems that you implements connector in each device driver. Can't
> they be
> >> combined as common spot, exynos_connector, again to avoid codes from
> >> duplicated? :)
> >
> > There's nothing of substance being duplicated.
>
> Not true. xxx_create_connector is duplicated.
>
> > In fact, by getting rid
> > of the exynos_drm_connector layer, we deleted 150 lines. If you really
> > take a look at exynos_drm_connector, it's not doing anything useful.
>
> No, That is for each driver has no any dependency of drm framework.
>
> > All it does is translate the drm callbacks into display callbacks, so
> > I think it's much better to just implement the drm callbacks directly.
> >
>
> No, It has strongly dependency of drm framework. Assume that we
> implemented the drm callbacks directly, and then some features are
> added to drm framework, drm_connector side. At this time, we will have
> to take care of each device driver according to the change. That is
> really not good. Why device drivers should have dependency of drm
> framework? Just to reduce line counts?
>


You seem to miss the point here and elsewhere in the discussion.
drm/exynos is a drm driver, and as such it should use the drm
framework, especially if this reduces the line count and the code
complexity (as is the case for this patch series). If you don't want
to maintain a drm driver, it simply should be moved away from drm/,
and it should be replaced by a real drm driver in my opinion.

Stéphane


>
> > There are a bunch of real bugs that we've found as a result of having
> > these abstraction layers. Take, for example, dpms. Before this
> > patchset, dpms for fimd was being tracked separately in fimd driver,
> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
> > Furthermore, during suspend, only fimd driver's dpms state was
> > updated, so the others were incorrect. There was also this weird
> > gymnastics that had to happen when dpms was changed in the encoder
> > since it had to walk up to the connector level to change its dpms
> > state. If fimd just directly implemented
> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
> > problem wouldn't exist. The same goes for HDMI/mixer.
> >
>
> That is a issue we should take care of by using the independent layer.
> Then, aren't you take care of that well with the re-factoring patch
> set? :)  It seems that you are outside real point.
>
> > Take a look at exynos_drm_encoder.c  in my tree
> > (
> https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> ),
> > what does it do that's useful to abstract? All that it does is just
> > call display ops, it's completely useless. The same is true for
> > exynos_drm_connector, it's just dead weight. There is some useful
> > stuff in exynos_drm_crtc for page flipping, that would be better
> > served as a helper library, though.
> >
> >> The abstraction layer you mentioned also means a common spot.
> >> Another one, you patch also makes each sub driver have strongly
> dependency
> >> of drm framework. So how we can support existing backlight and lcd class
> >> based lcd panel drivers if the connector is implemented in each device
> >> driver later?  the drm header files should be included in
> >> drivers/video/backlight/xxx_lcd.c?
> >>
> >
> > drm_bridge or drm_panel seem like good candidates for this.
> >
>
> Yes, exynos_drm_display could be replaced with drm_panel later if the
> drm_panel can be merged to mainline.
>
> >
> >> And, I will introduce a new framework to support existing lcd panel
> drivers
> >> and display bus drivers soon; as of now for Exynos drm, and the
> framework is
> >> being tested internally. With this framework, encoder and connector
> will be
> >> created when lcd panel or display bus driver such as eDP is probed: it
> >> doesn’t really need to create encoder and connector in advance if lcd
> panel
> >> or display bus driver isn't probed yet. Regardless of crtc, and encoder
> and
> >> connector creation order, when last one is created, crtc and connector
> will
> >> be connected each other. And exynos_drm_display could be implemented in
> >> other frameworks if we have common structure for display device driver.
> And
> >> also the framework will support lvds driver according to Linux device
> driver
> >> model.
> >>
> >
> > I don't really follow what you're trying to do here, but I think we
> > should be moving in the direction of fewer abstractions in the exynos
> > driver, not more :)
> >
>
> Not abstraction layer, just a bridge for connecting crtc and its
> corresponding encoder/connector, and lvds regardless of creation
> order, and for connecting drm connector and other framework based
> display ops such as drm_panel later.
>
> > Sean
> >
> >
> >
> >> Thanks,
> >> Inki Dae
> >>
> >>> Sean
> >>>
> >>> >>>
> >>> >>> > And another one, the patch 6 passes manager object to
> manager_ops,
> >>> and
> >>> >>> for
> >>> >>> > this, you made the manager object to be set to driver data;
> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
> >>> Generally,
> >>> >>> > driver_data would point to device driver's context object.
> >>> >>> >
> >>> >>>
> >>> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
> >>> >>> driver data is only used up until we get rid of the pm ops, it
> needn't
> >>> >>> be set at all once things go through dpms.
> >>> >>>
> >>> >>
> >>> >> Generally, device drivers can call its own internal functions, and
> they
> >>> will
> >>> >> call that functions with ctx. However, if you set manager to
> >>> driver_data
> >>> >> then that functions should be called with manager object and also
> >>> internally
> >>> >> that functions should get ctx from the manager object. What is the
> >>> purpose
> >>> >> of manager? Do you think it's reasonable?
> >>> >>
> >>> >
> >>> > So, to avoid setting the manager as the drvdata, we could implement
> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
> manager
> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
> >>> > mgr in ctx, but that creates a circular link between the two. IMO,
> >>> > both of those solutions suck :)
> >>> >
> >>> > I'd much rather just set drvdata to the manager and call the hook
> >>> > directly. Like I said earlier, this is just a temporary step since we
> >>> > remove these pm ops later in the patch series.
> >>> >
> >>> > Sean
> >>> >
> >>> >
> >>> >> Anyway, I'd like to say really sorry about inconvenient again. So I
> >>> will fix
> >>> >> it.
> >>> >>
> >>> >> Thanks,
> >>> >> Inki Dae
> >>> >>
> >>> >>> Sean
> >>> >>>
> >>> >>>
> >>> >>> > Thanks,
> >>> >>> > Inki Dae
> >>> >>> >
> >>> >>
> >>
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

[-- Attachment #1.2: Type: text/html, Size: 18031 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  2:40                   ` Stéphane Marchesin
@ 2013-10-23  3:38                     ` Inki Dae
  2013-10-23  4:03                       ` Stéphane Marchesin
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-23  3:38 UTC (permalink / raw)
  To: Stéphane Marchesin; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>
>
>
> On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>
>> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> >>
>> >>
>> >>> -----Original Message-----
>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>> >>> To: Inki Dae
>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>> >>>
>> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org>
>> >>> wrote:
>> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com>
>> >>> > wrote:
>> >>> >>
>> >>> >>
>> >>> >>> -----Original Message-----
>> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>> >>> >>> To: Inki Dae
>> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>> >>> >>> manager/display/subdrv
>> >>> >>>
>> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
>> >> wrote:
>> >>> >>> >
>> >>> >>> >
>> >>> >>> >> -----Original Message-----
>> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>> >>> >>> >> marcheu@chromium.org;
>> >>> Sean
>> >>> >>> >> Paul
>> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>> >>> >>> >> manager/display/subdrv
>> >>> >>> >>
>> >>> >>> >> This patch splits display and manager from subdrv. The result
>> >>> >>> >> is
>> >>> that
>> >>> >>> >> crtc functions can directly call into manager callbacks and
>> >>> >>> >> encoder
>> >>> >>> >> functions can directly call into display callbacks. This will
>> >>> >>> >> allow
>> >>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
>> >>> fimd/dp
>> >>> >>> >> with common code.
>> >>> >>> >>
>> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> >>> >>> >> ---
>> >>> >>> >>
>> >>> >>> >> Changes in v2:
>> >>> >>> >>       - Pass display into display_ops instead of context
>> >>> >>> >
>> >>> >>> > Sorry but it seems like more reasonable to pass device object
>> >>> >>> > into
>> >>> >>> > display_ops and manager_ops.
>> >>> >>> >
>> >>> >>>
>> >>> >>>
>> >>> >>> So you've changed your mind from when you said the following?
>> >>> >>>
>> >>> >>> >>> manager->ops->xxx(manager, ...);
>> >>> >>> >>> display->ops->xxx(display, ...);
>> >>> >>> >>>
>> >>> >>> >>> Agree.
>> >>> >>>
>> >>> >>
>> >>> >>
>> >>> >> True. Before that, My comment was to pass device object into
>> >>> display_ops and
>> >>> >> manager_ops, and then you said the good solution is to pass manager
>> >>> >> and
>> >>> >> display to each driver. At that time, I thought no matter how the
>> >>> callback
>> >>> >> is called if the framework doesn't call callbacks of each driver
>> >>> >> with
>> >>> ctx.
>> >>> >> So I agreed.
>> >>> >>
>> >>> >>
>> >>> >>> It would have been nice if you had changed your mind *before* I
>> >>> >>> reworked everything. At any rate, I think it's still the right
>> >>> >>> thing
>> >>> >>> to do.
>> >>> >>
>> >>> >> Really sorry about that. And I will add new patch for it so you
>> >>> >> don't
>> >>> need
>> >>> >> to concern about that.
>> >>> >>
>> >>> >>>
>> >>> >>>
>> >>> >>> > I'm not sure but display_ops could be implemented in other
>> >>> >>> > framework
>> >>> >>> based
>> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>> >>> >>> > display -
>> >>> it's
>> >>> >>> > specific to exynos drm framework - into display_ops, the other
>> >>> framework
>> >>> >>> > based driver should include specific exynos drm header.
>> >>> >>> >
>> >>> >>>
>> >>> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
>> >>> >>> don't need to worry about this. Furthermore, these ops should just
>> >>> >>> go
>> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>> >>> >>>
>> >>> >>
>> >>> >> Can you assure the display_ops never implemented in other framework
>> >>> based
>> >>> >> driver, not CDF? At any rate, I think all possibilities should be
>> >>> opened.
>> >>> >>
>> >>> >
>> >>> > I don't think we should let an RFC framework make the code more
>> >>> > complicated for unclear benefit. By removing manager/display
>> >>> > entirely,
>> >>> > we can get rid of a *lot* of other code that is basically just
>> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>> >>> >
>> >>>
>> >>> I hacked this up today to prove it out. Check out the top 5 commits in
>> >>>
>> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>> >>> staging.
>> >>> It removes exynos_drm_connector in favor of just implementing
>> >>> drm_connector directly. This same treatment should be done for
>> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
>> >>> doing this.
>> >>>
>> >>> As you can see, it cuts out a lot of code and removes an entire
>> >>> abstraction layer. Much nicer :)
>> >>>
>> >>
>> >> It seems that you implements connector in each device driver. Can't
>> >> they be
>> >> combined as common spot, exynos_connector, again to avoid codes from
>> >> duplicated? :)
>> >
>> > There's nothing of substance being duplicated.
>>
>> Not true. xxx_create_connector is duplicated.
>>
>> > In fact, by getting rid
>> > of the exynos_drm_connector layer, we deleted 150 lines. If you really
>> > take a look at exynos_drm_connector, it's not doing anything useful.
>>
>> No, That is for each driver has no any dependency of drm framework.
>>
>> > All it does is translate the drm callbacks into display callbacks, so
>> > I think it's much better to just implement the drm callbacks directly.
>> >
>>
>> No, It has strongly dependency of drm framework. Assume that we
>> implemented the drm callbacks directly, and then some features are
>> added to drm framework, drm_connector side. At this time, we will have
>> to take care of each device driver according to the change. That is
>> really not good. Why device drivers should have dependency of drm
>> framework? Just to reduce line counts?
>
>
>
> You seem to miss the point here and elsewhere in the discussion.
> drm/exynos is a drm driver, and as such it should use the drm
> framework,

Hm.. you seem to miss something. Exynos drm based drivers are based on
exynos drm framework, not drm framework directly. So I mean that
Exynos drm framework based drivers should include only Exynos drm
headers, _not drm header_ directly.

> especially if this reduces the line count and the code
> complexity (as is the case for this patch series). If you don't want
> to maintain a drm driver, it simply should be moved away from drm/,
> and it should be replaced by a real drm driver in my opinion.

So those drivers should be in drm/exynos. Isn't that you really mean
those drivers should be driver/gpu/drm? If so, That would really be
horrible. :(

Please, know that only Exynos drm framework, _not device drivers_, has
all dependencies of drm framework, and also I know that other ARM
based drm drivers are using same way.

Thanks,
Inki Dae

>
> Stéphane
>
>>
>>
>> > There are a bunch of real bugs that we've found as a result of having
>> > these abstraction layers. Take, for example, dpms. Before this
>> > patchset, dpms for fimd was being tracked separately in fimd driver,
>> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>> > Furthermore, during suspend, only fimd driver's dpms state was
>> > updated, so the others were incorrect. There was also this weird
>> > gymnastics that had to happen when dpms was changed in the encoder
>> > since it had to walk up to the connector level to change its dpms
>> > state. If fimd just directly implemented
>> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>> > problem wouldn't exist. The same goes for HDMI/mixer.
>> >
>>
>> That is a issue we should take care of by using the independent layer.
>> Then, aren't you take care of that well with the re-factoring patch
>> set? :)  It seems that you are outside real point.
>>
>> > Take a look at exynos_drm_encoder.c  in my tree
>> >
>> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>> > what does it do that's useful to abstract? All that it does is just
>> > call display ops, it's completely useless. The same is true for
>> > exynos_drm_connector, it's just dead weight. There is some useful
>> > stuff in exynos_drm_crtc for page flipping, that would be better
>> > served as a helper library, though.
>> >
>> >> The abstraction layer you mentioned also means a common spot.
>> >> Another one, you patch also makes each sub driver have strongly
>> >> dependency
>> >> of drm framework. So how we can support existing backlight and lcd
>> >> class
>> >> based lcd panel drivers if the connector is implemented in each device
>> >> driver later?  the drm header files should be included in
>> >> drivers/video/backlight/xxx_lcd.c?
>> >>
>> >
>> > drm_bridge or drm_panel seem like good candidates for this.
>> >
>>
>> Yes, exynos_drm_display could be replaced with drm_panel later if the
>> drm_panel can be merged to mainline.
>>
>> >
>> >> And, I will introduce a new framework to support existing lcd panel
>> >> drivers
>> >> and display bus drivers soon; as of now for Exynos drm, and the
>> >> framework is
>> >> being tested internally. With this framework, encoder and connector
>> >> will be
>> >> created when lcd panel or display bus driver such as eDP is probed: it
>> >> doesn’t really need to create encoder and connector in advance if lcd
>> >> panel
>> >> or display bus driver isn't probed yet. Regardless of crtc, and encoder
>> >> and
>> >> connector creation order, when last one is created, crtc and connector
>> >> will
>> >> be connected each other. And exynos_drm_display could be implemented in
>> >> other frameworks if we have common structure for display device driver.
>> >> And
>> >> also the framework will support lvds driver according to Linux device
>> >> driver
>> >> model.
>> >>
>> >
>> > I don't really follow what you're trying to do here, but I think we
>> > should be moving in the direction of fewer abstractions in the exynos
>> > driver, not more :)
>> >
>>
>> Not abstraction layer, just a bridge for connecting crtc and its
>> corresponding encoder/connector, and lvds regardless of creation
>> order, and for connecting drm connector and other framework based
>> display ops such as drm_panel later.
>>
>> > Sean
>> >
>> >
>> >
>> >> Thanks,
>> >> Inki Dae
>> >>
>> >>> Sean
>> >>>
>> >>> >>>
>> >>> >>> > And another one, the patch 6 passes manager object to
>> >>> >>> > manager_ops,
>> >>> and
>> >>> >>> for
>> >>> >>> > this, you made the manager object to be set to driver data;
>> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
>> >>> Generally,
>> >>> >>> > driver_data would point to device driver's context object.
>> >>> >>> >
>> >>> >>>
>> >>> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
>> >>> >>> driver data is only used up until we get rid of the pm ops, it
>> >>> >>> needn't
>> >>> >>> be set at all once things go through dpms.
>> >>> >>>
>> >>> >>
>> >>> >> Generally, device drivers can call its own internal functions, and
>> >>> >> they
>> >>> will
>> >>> >> call that functions with ctx. However, if you set manager to
>> >>> driver_data
>> >>> >> then that functions should be called with manager object and also
>> >>> internally
>> >>> >> that functions should get ctx from the manager object. What is the
>> >>> purpose
>> >>> >> of manager? Do you think it's reasonable?
>> >>> >>
>> >>> >
>> >>> > So, to avoid setting the manager as the drvdata, we could implement
>> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>> >>> > manager
>> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer
>> >>> > to
>> >>> > mgr in ctx, but that creates a circular link between the two. IMO,
>> >>> > both of those solutions suck :)
>> >>> >
>> >>> > I'd much rather just set drvdata to the manager and call the hook
>> >>> > directly. Like I said earlier, this is just a temporary step since
>> >>> > we
>> >>> > remove these pm ops later in the patch series.
>> >>> >
>> >>> > Sean
>> >>> >
>> >>> >
>> >>> >> Anyway, I'd like to say really sorry about inconvenient again. So I
>> >>> will fix
>> >>> >> it.
>> >>> >>
>> >>> >> Thanks,
>> >>> >> Inki Dae
>> >>> >>
>> >>> >>> Sean
>> >>> >>>
>> >>> >>>
>> >>> >>> > Thanks,
>> >>> >>> > Inki Dae
>> >>> >>> >
>> >>> >>
>> >>
>> > _______________________________________________
>> > dri-devel mailing list
>> > dri-devel@lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  2:28                 ` Inki Dae
  2013-10-23  2:40                   ` Stéphane Marchesin
@ 2013-10-23  3:39                   ` Sean Paul
  1 sibling, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-23  3:39 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Tue, Oct 22, 2013 at 10:28 PM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>> On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>>
>>>
>>>> -----Original Message-----
>>>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> Sent: Tuesday, October 22, 2013 6:18 AM
>>>> To: Inki Dae
>>>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>>>
>>>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org> wrote:
>>>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>> >>
>>>> >>
>>>> >>> -----Original Message-----
>>>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>>> >>> To: Inki Dae
>>>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>>> >>>
>>>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com>
>>> wrote:
>>>> >>> >
>>>> >>> >
>>>> >>> >> -----Original Message-----
>>>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com; marcheu@chromium.org;
>>>> Sean
>>>> >>> >> Paul
>>>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
>>>> >>> >>
>>>> >>> >> This patch splits display and manager from subdrv. The result is
>>>> that
>>>> >>> >> crtc functions can directly call into manager callbacks and encoder
>>>> >>> >> functions can directly call into display callbacks. This will allow
>>>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi &
>>>> fimd/dp
>>>> >>> >> with common code.
>>>> >>> >>
>>>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>>> >>> >> ---
>>>> >>> >>
>>>> >>> >> Changes in v2:
>>>> >>> >>       - Pass display into display_ops instead of context
>>>> >>> >
>>>> >>> > Sorry but it seems like more reasonable to pass device object into
>>>> >>> > display_ops and manager_ops.
>>>> >>> >
>>>> >>>
>>>> >>>
>>>> >>> So you've changed your mind from when you said the following?
>>>> >>>
>>>> >>> >>> manager->ops->xxx(manager, ...);
>>>> >>> >>> display->ops->xxx(display, ...);
>>>> >>> >>>
>>>> >>> >>> Agree.
>>>> >>>
>>>> >>
>>>> >>
>>>> >> True. Before that, My comment was to pass device object into
>>>> display_ops and
>>>> >> manager_ops, and then you said the good solution is to pass manager and
>>>> >> display to each driver. At that time, I thought no matter how the
>>>> callback
>>>> >> is called if the framework doesn't call callbacks of each driver with
>>>> ctx.
>>>> >> So I agreed.
>>>> >>
>>>> >>
>>>> >>> It would have been nice if you had changed your mind *before* I
>>>> >>> reworked everything. At any rate, I think it's still the right thing
>>>> >>> to do.
>>>> >>
>>>> >> Really sorry about that. And I will add new patch for it so you don't
>>>> need
>>>> >> to concern about that.
>>>> >>
>>>> >>>
>>>> >>>
>>>> >>> > I'm not sure but display_ops could be implemented in other framework
>>>> >>> based
>>>> >>> > driver such as CDF based lcd panel driver. So if you pass display -
>>>> it's
>>>> >>> > specific to exynos drm framework - into display_ops, the other
>>>> framework
>>>> >>> > based driver should include specific exynos drm header.
>>>> >>> >
>>>> >>>
>>>> >>> AFAIK, CDF will not land in its current separate-from-drm form, we
>>>> >>> don't need to worry about this. Furthermore, these ops should just go
>>>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs anyways.
>>>> >>>
>>>> >>
>>>> >> Can you assure the display_ops never implemented in other framework
>>>> based
>>>> >> driver, not CDF? At any rate, I think all possibilities should be
>>>> opened.
>>>> >>
>>>> >
>>>> > I don't think we should let an RFC framework make the code more
>>>> > complicated for unclear benefit. By removing manager/display entirely,
>>>> > we can get rid of a *lot* of other code that is basically just
>>>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>>> >
>>>>
>>>> I hacked this up today to prove it out. Check out the top 5 commits in
>>>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>>> staging.
>>>> It removes exynos_drm_connector in favor of just implementing
>>>> drm_connector directly. This same treatment should be done for
>>>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
>>>> doing this.
>>>>
>>>> As you can see, it cuts out a lot of code and removes an entire
>>>> abstraction layer. Much nicer :)
>>>>
>>>
>>> It seems that you implements connector in each device driver. Can't they be
>>> combined as common spot, exynos_connector, again to avoid codes from
>>> duplicated? :)
>>
>> There's nothing of substance being duplicated.
>
> Not true. xxx_create_connector is duplicated.
>

I said nothing *of substance*, all of the other drm drivers call
drm_connector_init for each display type.

>> In fact, by getting rid
>> of the exynos_drm_connector layer, we deleted 150 lines. If you really
>> take a look at exynos_drm_connector, it's not doing anything useful.
>
> No, That is for each driver has no any dependency of drm framework.
>

I didn't think this was desirable :)

>> All it does is translate the drm callbacks into display callbacks, so
>> I think it's much better to just implement the drm callbacks directly.
>>
>
> No, It has strongly dependency of drm framework. Assume that we
> implemented the drm callbacks directly, and then some features are
> added to drm framework, drm_connector side. At this time, we will have
> to take care of each device driver according to the change. That is
> really not good. Why device drivers should have dependency of drm
> framework? Just to reduce line counts?
>

Assuming someone adds something to drm_connector, it's their
responsibility to bring all other drivers forward with that change.
Device drivers should have a dependency on drm framework because
that's the API that everyone on this list has agreed to use. Why
invent something else? What's the point of having independent hooks
that almost identically mirror the drm framework?


>> There are a bunch of real bugs that we've found as a result of having
>> these abstraction layers. Take, for example, dpms. Before this
>> patchset, dpms for fimd was being tracked separately in fimd driver,
>> exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>> Furthermore, during suspend, only fimd driver's dpms state was
>> updated, so the others were incorrect. There was also this weird
>> gymnastics that had to happen when dpms was changed in the encoder
>> since it had to walk up to the connector level to change its dpms
>> state. If fimd just directly implemented
>> drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>> problem wouldn't exist. The same goes for HDMI/mixer.
>>
>
> That is a issue we should take care of by using the independent layer.
> Then, aren't you take care of that well with the re-factoring patch
> set? :)  It seems that you are outside real point.
>

Right, I took out the connector and encoder dpms state, but it still
exists in crtc. I was trying to point out the class of issues that
comes from this type of shim.

>> Take a look at exynos_drm_encoder.c  in my tree
>> (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>> what does it do that's useful to abstract? All that it does is just
>> call display ops, it's completely useless. The same is true for
>> exynos_drm_connector, it's just dead weight. There is some useful
>> stuff in exynos_drm_crtc for page flipping, that would be better
>> served as a helper library, though.
>>
>>> The abstraction layer you mentioned also means a common spot.
>>> Another one, you patch also makes each sub driver have strongly dependency
>>> of drm framework. So how we can support existing backlight and lcd class
>>> based lcd panel drivers if the connector is implemented in each device
>>> driver later?  the drm header files should be included in
>>> drivers/video/backlight/xxx_lcd.c?
>>>
>>
>> drm_bridge or drm_panel seem like good candidates for this.
>>
>
> Yes, exynos_drm_display could be replaced with drm_panel later if the
> drm_panel can be merged to mainline.
>

Well, exynos_drm_display can be replaced today by drm_encoder/drm_connector.

>>
>>> And, I will introduce a new framework to support existing lcd panel drivers
>>> and display bus drivers soon; as of now for Exynos drm, and the framework is
>>> being tested internally. With this framework, encoder and connector will be
>>> created when lcd panel or display bus driver such as eDP is probed: it
>>> doesn’t really need to create encoder and connector in advance if lcd panel
>>> or display bus driver isn't probed yet. Regardless of crtc, and encoder and
>>> connector creation order, when last one is created, crtc and connector will
>>> be connected each other. And exynos_drm_display could be implemented in
>>> other frameworks if we have common structure for display device driver. And
>>> also the framework will support lvds driver according to Linux device driver
>>> model.
>>>
>>
>> I don't really follow what you're trying to do here, but I think we
>> should be moving in the direction of fewer abstractions in the exynos
>> driver, not more :)
>>
>
> Not abstraction layer, just a bridge for connecting crtc and its
> corresponding encoder/connector, and lvds regardless of creation
> order, and for connecting drm connector and other framework based
> display ops such as drm_panel later.
>

I guess we see things differently. It seems like you want to do a
bunch of stuff that is outside of the drm framework, I assumed that
you wanted this to be a proper drm driver. Not surprisingly, I'm with
Stephane on this, I'd like for exynos to be a first-class drm driver,
and that can't happen with these homebrew interfaces.

Sean

>> Sean
>>
>>
>>
>>> Thanks,
>>> Inki Dae
>>>
>>>> Sean
>>>>
>>>> >>>
>>>> >>> > And another one, the patch 6 passes manager object to manager_ops,
>>>> and
>>>> >>> for
>>>> >>> > this, you made the manager object to be set to driver data;
>>>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
>>>> Generally,
>>>> >>> > driver_data would point to device driver's context object.
>>>> >>> >
>>>> >>>
>>>> >>> I'm not sure why this isn't reasonable, but it's a moot point. The
>>>> >>> driver data is only used up until we get rid of the pm ops, it needn't
>>>> >>> be set at all once things go through dpms.
>>>> >>>
>>>> >>
>>>> >> Generally, device drivers can call its own internal functions, and they
>>>> will
>>>> >> call that functions with ctx. However, if you set manager to
>>>> driver_data
>>>> >> then that functions should be called with manager object and also
>>>> internally
>>>> >> that functions should get ctx from the manager object. What is the
>>>> purpose
>>>> >> of manager? Do you think it's reasonable?
>>>> >>
>>>> >
>>>> > So, to avoid setting the manager as the drvdata, we could implement
>>>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the manager
>>>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer to
>>>> > mgr in ctx, but that creates a circular link between the two. IMO,
>>>> > both of those solutions suck :)
>>>> >
>>>> > I'd much rather just set drvdata to the manager and call the hook
>>>> > directly. Like I said earlier, this is just a temporary step since we
>>>> > remove these pm ops later in the patch series.
>>>> >
>>>> > Sean
>>>> >
>>>> >
>>>> >> Anyway, I'd like to say really sorry about inconvenient again. So I
>>>> will fix
>>>> >> it.
>>>> >>
>>>> >> Thanks,
>>>> >> Inki Dae
>>>> >>
>>>> >>> Sean
>>>> >>>
>>>> >>>
>>>> >>> > Thanks,
>>>> >>> > Inki Dae
>>>> >>> >
>>>> >>
>>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  3:38                     ` Inki Dae
@ 2013-10-23  4:03                       ` Stéphane Marchesin
  2013-10-23  4:15                         ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Stéphane Marchesin @ 2013-10-23  4:03 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 15041 bytes --]

On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:

> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
> >
> >
> >
> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >>
> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
> wrote:
> >> >>
> >> >>
> >> >>> -----Original Message-----
> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
> >> >>> To: Inki Dae
> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
> manager/display/subdrv
> >> >>>
> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org>
> >> >>> wrote:
> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com>
> >> >>> > wrote:
> >> >>> >>
> >> >>> >>
> >> >>> >>> -----Original Message-----
> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
> >> >>> >>> To: Inki Dae
> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
> >> >>> >>> manager/display/subdrv
> >> >>> >>>
> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae <inki.dae@samsung.com
> >
> >> >> wrote:
> >> >>> >>> >
> >> >>> >>> >
> >> >>> >>> >> -----Original Message-----
> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
> >> >>> >>> >> marcheu@chromium.org;
> >> >>> Sean
> >> >>> >>> >> Paul
> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
> >> >>> >>> >> manager/display/subdrv
> >> >>> >>> >>
> >> >>> >>> >> This patch splits display and manager from subdrv. The result
> >> >>> >>> >> is
> >> >>> that
> >> >>> >>> >> crtc functions can directly call into manager callbacks and
> >> >>> >>> >> encoder
> >> >>> >>> >> functions can directly call into display callbacks. This will
> >> >>> >>> >> allow
> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi
> &
> >> >>> fimd/dp
> >> >>> >>> >> with common code.
> >> >>> >>> >>
> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> >>> >>> >> ---
> >> >>> >>> >>
> >> >>> >>> >> Changes in v2:
> >> >>> >>> >>       - Pass display into display_ops instead of context
> >> >>> >>> >
> >> >>> >>> > Sorry but it seems like more reasonable to pass device object
> >> >>> >>> > into
> >> >>> >>> > display_ops and manager_ops.
> >> >>> >>> >
> >> >>> >>>
> >> >>> >>>
> >> >>> >>> So you've changed your mind from when you said the following?
> >> >>> >>>
> >> >>> >>> >>> manager->ops->xxx(manager, ...);
> >> >>> >>> >>> display->ops->xxx(display, ...);
> >> >>> >>> >>>
> >> >>> >>> >>> Agree.
> >> >>> >>>
> >> >>> >>
> >> >>> >>
> >> >>> >> True. Before that, My comment was to pass device object into
> >> >>> display_ops and
> >> >>> >> manager_ops, and then you said the good solution is to pass
> manager
> >> >>> >> and
> >> >>> >> display to each driver. At that time, I thought no matter how the
> >> >>> callback
> >> >>> >> is called if the framework doesn't call callbacks of each driver
> >> >>> >> with
> >> >>> ctx.
> >> >>> >> So I agreed.
> >> >>> >>
> >> >>> >>
> >> >>> >>> It would have been nice if you had changed your mind *before* I
> >> >>> >>> reworked everything. At any rate, I think it's still the right
> >> >>> >>> thing
> >> >>> >>> to do.
> >> >>> >>
> >> >>> >> Really sorry about that. And I will add new patch for it so you
> >> >>> >> don't
> >> >>> need
> >> >>> >> to concern about that.
> >> >>> >>
> >> >>> >>>
> >> >>> >>>
> >> >>> >>> > I'm not sure but display_ops could be implemented in other
> >> >>> >>> > framework
> >> >>> >>> based
> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
> >> >>> >>> > display -
> >> >>> it's
> >> >>> >>> > specific to exynos drm framework - into display_ops, the other
> >> >>> framework
> >> >>> >>> > based driver should include specific exynos drm header.
> >> >>> >>> >
> >> >>> >>>
> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm form,
> we
> >> >>> >>> don't need to worry about this. Furthermore, these ops should
> just
> >> >>> >>> go
> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
> anyways.
> >> >>> >>>
> >> >>> >>
> >> >>> >> Can you assure the display_ops never implemented in other
> framework
> >> >>> based
> >> >>> >> driver, not CDF? At any rate, I think all possibilities should be
> >> >>> opened.
> >> >>> >>
> >> >>> >
> >> >>> > I don't think we should let an RFC framework make the code more
> >> >>> > complicated for unclear benefit. By removing manager/display
> >> >>> > entirely,
> >> >>> > we can get rid of a *lot* of other code that is basically just
> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
> >> >>> >
> >> >>>
> >> >>> I hacked this up today to prove it out. Check out the top 5 commits
> in
> >> >>>
> >> >>>
> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
> >> >>> staging.
> >> >>> It removes exynos_drm_connector in favor of just implementing
> >> >>> drm_connector directly. This same treatment should be done for
> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
> >> >>> doing this.
> >> >>>
> >> >>> As you can see, it cuts out a lot of code and removes an entire
> >> >>> abstraction layer. Much nicer :)
> >> >>>
> >> >>
> >> >> It seems that you implements connector in each device driver. Can't
> >> >> they be
> >> >> combined as common spot, exynos_connector, again to avoid codes from
> >> >> duplicated? :)
> >> >
> >> > There's nothing of substance being duplicated.
> >>
> >> Not true. xxx_create_connector is duplicated.
> >>
> >> > In fact, by getting rid
> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you really
> >> > take a look at exynos_drm_connector, it's not doing anything useful.
> >>
> >> No, That is for each driver has no any dependency of drm framework.
> >>
> >> > All it does is translate the drm callbacks into display callbacks, so
> >> > I think it's much better to just implement the drm callbacks directly.
> >> >
> >>
> >> No, It has strongly dependency of drm framework. Assume that we
> >> implemented the drm callbacks directly, and then some features are
> >> added to drm framework, drm_connector side. At this time, we will have
> >> to take care of each device driver according to the change. That is
> >> really not good. Why device drivers should have dependency of drm
> >> framework? Just to reduce line counts?
> >
> >
> >
> > You seem to miss the point here and elsewhere in the discussion.
> > drm/exynos is a drm driver, and as such it should use the drm
> > framework,
>
> Hm.. you seem to miss something. Exynos drm based drivers are based on
> exynos drm framework, not drm framework directly. So I mean that
> Exynos drm framework based drivers should include only Exynos drm
> headers, _not drm header_ directly.
>

Well, I think everyone sees that exynos is different. But my point still
remains: why is the exynos driver in drm/ if it wants to use a different
framework? Right now it is blocking work on a proper drm driver...



>
> > especially if this reduces the line count and the code
> > complexity (as is the case for this patch series). If you don't want
> > to maintain a drm driver, it simply should be moved away from drm/,
> > and it should be replaced by a real drm driver in my opinion.
>
> So those drivers should be in drm/exynos. Isn't that you really mean
> those drivers should be driver/gpu/drm?


I don't understand this sentence, sorry.

Stéphane



> If so, That would really be
> horrible. :(
>
>


> Please, know that only Exynos drm framework, _not device drivers_, has
> all dependencies of drm framework, and also I know that other ARM
> based drm drivers are using same way.
>
> Thanks,
> Inki Dae
>
> >
> > Stéphane
> >
> >>
> >>
> >> > There are a bunch of real bugs that we've found as a result of having
> >> > these abstraction layers. Take, for example, dpms. Before this
> >> > patchset, dpms for fimd was being tracked separately in fimd driver,
> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
> >> > Furthermore, during suspend, only fimd driver's dpms state was
> >> > updated, so the others were incorrect. There was also this weird
> >> > gymnastics that had to happen when dpms was changed in the encoder
> >> > since it had to walk up to the connector level to change its dpms
> >> > state. If fimd just directly implemented
> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
> >> > problem wouldn't exist. The same goes for HDMI/mixer.
> >> >
> >>
> >> That is a issue we should take care of by using the independent layer.
> >> Then, aren't you take care of that well with the re-factoring patch
> >> set? :)  It seems that you are outside real point.
> >>
> >> > Take a look at exynos_drm_encoder.c  in my tree
> >> >
> >> > (
> https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> ),
> >> > what does it do that's useful to abstract? All that it does is just
> >> > call display ops, it's completely useless. The same is true for
> >> > exynos_drm_connector, it's just dead weight. There is some useful
> >> > stuff in exynos_drm_crtc for page flipping, that would be better
> >> > served as a helper library, though.
> >> >
> >> >> The abstraction layer you mentioned also means a common spot.
> >> >> Another one, you patch also makes each sub driver have strongly
> >> >> dependency
> >> >> of drm framework. So how we can support existing backlight and lcd
> >> >> class
> >> >> based lcd panel drivers if the connector is implemented in each
> device
> >> >> driver later?  the drm header files should be included in
> >> >> drivers/video/backlight/xxx_lcd.c?
> >> >>
> >> >
> >> > drm_bridge or drm_panel seem like good candidates for this.
> >> >
> >>
> >> Yes, exynos_drm_display could be replaced with drm_panel later if the
> >> drm_panel can be merged to mainline.
> >>
> >> >
> >> >> And, I will introduce a new framework to support existing lcd panel
> >> >> drivers
> >> >> and display bus drivers soon; as of now for Exynos drm, and the
> >> >> framework is
> >> >> being tested internally. With this framework, encoder and connector
> >> >> will be
> >> >> created when lcd panel or display bus driver such as eDP is probed:
> it
> >> >> doesn’t really need to create encoder and connector in advance if lcd
> >> >> panel
> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
> encoder
> >> >> and
> >> >> connector creation order, when last one is created, crtc and
> connector
> >> >> will
> >> >> be connected each other. And exynos_drm_display could be implemented
> in
> >> >> other frameworks if we have common structure for display device
> driver.
> >> >> And
> >> >> also the framework will support lvds driver according to Linux device
> >> >> driver
> >> >> model.
> >> >>
> >> >
> >> > I don't really follow what you're trying to do here, but I think we
> >> > should be moving in the direction of fewer abstractions in the exynos
> >> > driver, not more :)
> >> >
> >>
> >> Not abstraction layer, just a bridge for connecting crtc and its
> >> corresponding encoder/connector, and lvds regardless of creation
> >> order, and for connecting drm connector and other framework based
> >> display ops such as drm_panel later.
> >>
> >> > Sean
> >> >
> >> >
> >> >
> >> >> Thanks,
> >> >> Inki Dae
> >> >>
> >> >>> Sean
> >> >>>
> >> >>> >>>
> >> >>> >>> > And another one, the patch 6 passes manager object to
> >> >>> >>> > manager_ops,
> >> >>> and
> >> >>> >>> for
> >> >>> >>> > this, you made the manager object to be set to driver data;
> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
> >> >>> Generally,
> >> >>> >>> > driver_data would point to device driver's context object.
> >> >>> >>> >
> >> >>> >>>
> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot point.
> The
> >> >>> >>> driver data is only used up until we get rid of the pm ops, it
> >> >>> >>> needn't
> >> >>> >>> be set at all once things go through dpms.
> >> >>> >>>
> >> >>> >>
> >> >>> >> Generally, device drivers can call its own internal functions,
> and
> >> >>> >> they
> >> >>> will
> >> >>> >> call that functions with ctx. However, if you set manager to
> >> >>> driver_data
> >> >>> >> then that functions should be called with manager object and also
> >> >>> internally
> >> >>> >> that functions should get ctx from the manager object. What is
> the
> >> >>> purpose
> >> >>> >> of manager? Do you think it's reasonable?
> >> >>> >>
> >> >>> >
> >> >>> > So, to avoid setting the manager as the drvdata, we could
> implement
> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
> >> >>> > manager
> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a pointer
> >> >>> > to
> >> >>> > mgr in ctx, but that creates a circular link between the two. IMO,
> >> >>> > both of those solutions suck :)
> >> >>> >
> >> >>> > I'd much rather just set drvdata to the manager and call the hook
> >> >>> > directly. Like I said earlier, this is just a temporary step since
> >> >>> > we
> >> >>> > remove these pm ops later in the patch series.
> >> >>> >
> >> >>> > Sean
> >> >>> >
> >> >>> >
> >> >>> >> Anyway, I'd like to say really sorry about inconvenient again.
> So I
> >> >>> will fix
> >> >>> >> it.
> >> >>> >>
> >> >>> >> Thanks,
> >> >>> >> Inki Dae
> >> >>> >>
> >> >>> >>> Sean
> >> >>> >>>
> >> >>> >>>
> >> >>> >>> > Thanks,
> >> >>> >>> > Inki Dae
> >> >>> >>> >
> >> >>> >>
> >> >>
> >> > _______________________________________________
> >> > dri-devel mailing list
> >> > dri-devel@lists.freedesktop.org
> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
> >
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
>

[-- Attachment #1.2: Type: text/html, Size: 23901 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  4:03                       ` Stéphane Marchesin
@ 2013-10-23  4:15                         ` Inki Dae
  2013-10-23  4:28                           ` Stéphane Marchesin
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-23  4:15 UTC (permalink / raw)
  To: Stéphane Marchesin; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>
>
>
> On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>
>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>> >
>> >
>> >
>> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> >>
>> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>> >> > wrote:
>> >> >>
>> >> >>
>> >> >>> -----Original Message-----
>> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>> >> >>> To: Inki Dae
>> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>> >> >>> manager/display/subdrv
>> >> >>>
>> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <seanpaul@chromium.org>
>> >> >>> wrote:
>> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <inki.dae@samsung.com>
>> >> >>> > wrote:
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>> -----Original Message-----
>> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>> >> >>> >>> To: Inki Dae
>> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>> >> >>> >>> manager/display/subdrv
>> >> >>> >>>
>> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>> >> >>> >>> <inki.dae@samsung.com>
>> >> >> wrote:
>> >> >>> >>> >
>> >> >>> >>> >
>> >> >>> >>> >> -----Original Message-----
>> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>> >> >>> >>> >> marcheu@chromium.org;
>> >> >>> Sean
>> >> >>> >>> >> Paul
>> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>> >> >>> >>> >> manager/display/subdrv
>> >> >>> >>> >>
>> >> >>> >>> >> This patch splits display and manager from subdrv. The
>> >> >>> >>> >> result
>> >> >>> >>> >> is
>> >> >>> that
>> >> >>> >>> >> crtc functions can directly call into manager callbacks and
>> >> >>> >>> >> encoder
>> >> >>> >>> >> functions can directly call into display callbacks. This
>> >> >>> >>> >> will
>> >> >>> >>> >> allow
>> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support mixer/hdmi
>> >> >>> >>> >> &
>> >> >>> fimd/dp
>> >> >>> >>> >> with common code.
>> >> >>> >>> >>
>> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> >> >>> >>> >> ---
>> >> >>> >>> >>
>> >> >>> >>> >> Changes in v2:
>> >> >>> >>> >>       - Pass display into display_ops instead of context
>> >> >>> >>> >
>> >> >>> >>> > Sorry but it seems like more reasonable to pass device object
>> >> >>> >>> > into
>> >> >>> >>> > display_ops and manager_ops.
>> >> >>> >>> >
>> >> >>> >>>
>> >> >>> >>>
>> >> >>> >>> So you've changed your mind from when you said the following?
>> >> >>> >>>
>> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>> >> >>> >>> >>> display->ops->xxx(display, ...);
>> >> >>> >>> >>>
>> >> >>> >>> >>> Agree.
>> >> >>> >>>
>> >> >>> >>
>> >> >>> >>
>> >> >>> >> True. Before that, My comment was to pass device object into
>> >> >>> display_ops and
>> >> >>> >> manager_ops, and then you said the good solution is to pass
>> >> >>> >> manager
>> >> >>> >> and
>> >> >>> >> display to each driver. At that time, I thought no matter how
>> >> >>> >> the
>> >> >>> callback
>> >> >>> >> is called if the framework doesn't call callbacks of each driver
>> >> >>> >> with
>> >> >>> ctx.
>> >> >>> >> So I agreed.
>> >> >>> >>
>> >> >>> >>
>> >> >>> >>> It would have been nice if you had changed your mind *before* I
>> >> >>> >>> reworked everything. At any rate, I think it's still the right
>> >> >>> >>> thing
>> >> >>> >>> to do.
>> >> >>> >>
>> >> >>> >> Really sorry about that. And I will add new patch for it so you
>> >> >>> >> don't
>> >> >>> need
>> >> >>> >> to concern about that.
>> >> >>> >>
>> >> >>> >>>
>> >> >>> >>>
>> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>> >> >>> >>> > framework
>> >> >>> >>> based
>> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>> >> >>> >>> > display -
>> >> >>> it's
>> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>> >> >>> >>> > other
>> >> >>> framework
>> >> >>> >>> > based driver should include specific exynos drm header.
>> >> >>> >>> >
>> >> >>> >>>
>> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm form,
>> >> >>> >>> we
>> >> >>> >>> don't need to worry about this. Furthermore, these ops should
>> >> >>> >>> just
>> >> >>> >>> go
>> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>> >> >>> >>> anyways.
>> >> >>> >>>
>> >> >>> >>
>> >> >>> >> Can you assure the display_ops never implemented in other
>> >> >>> >> framework
>> >> >>> based
>> >> >>> >> driver, not CDF? At any rate, I think all possibilities should
>> >> >>> >> be
>> >> >>> opened.
>> >> >>> >>
>> >> >>> >
>> >> >>> > I don't think we should let an RFC framework make the code more
>> >> >>> > complicated for unclear benefit. By removing manager/display
>> >> >>> > entirely,
>> >> >>> > we can get rid of a *lot* of other code that is basically just
>> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>> >> >>> >
>> >> >>>
>> >> >>> I hacked this up today to prove it out. Check out the top 5 commits
>> >> >>> in
>> >> >>>
>> >> >>>
>> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>> >> >>> staging.
>> >> >>> It removes exynos_drm_connector in favor of just implementing
>> >> >>> drm_connector directly. This same treatment should be done for
>> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around to
>> >> >>> doing this.
>> >> >>>
>> >> >>> As you can see, it cuts out a lot of code and removes an entire
>> >> >>> abstraction layer. Much nicer :)
>> >> >>>
>> >> >>
>> >> >> It seems that you implements connector in each device driver. Can't
>> >> >> they be
>> >> >> combined as common spot, exynos_connector, again to avoid codes from
>> >> >> duplicated? :)
>> >> >
>> >> > There's nothing of substance being duplicated.
>> >>
>> >> Not true. xxx_create_connector is duplicated.
>> >>
>> >> > In fact, by getting rid
>> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>> >> > really
>> >> > take a look at exynos_drm_connector, it's not doing anything useful.
>> >>
>> >> No, That is for each driver has no any dependency of drm framework.
>> >>
>> >> > All it does is translate the drm callbacks into display callbacks, so
>> >> > I think it's much better to just implement the drm callbacks
>> >> > directly.
>> >> >
>> >>
>> >> No, It has strongly dependency of drm framework. Assume that we
>> >> implemented the drm callbacks directly, and then some features are
>> >> added to drm framework, drm_connector side. At this time, we will have
>> >> to take care of each device driver according to the change. That is
>> >> really not good. Why device drivers should have dependency of drm
>> >> framework? Just to reduce line counts?
>> >
>> >
>> >
>> > You seem to miss the point here and elsewhere in the discussion.
>> > drm/exynos is a drm driver, and as such it should use the drm
>> > framework,
>>
>> Hm.. you seem to miss something. Exynos drm based drivers are based on
>> exynos drm framework, not drm framework directly. So I mean that
>> Exynos drm framework based drivers should include only Exynos drm
>> headers, _not drm header_ directly.
>
>
> Well, I think everyone sees that exynos is different. But my point still
> remains: why is the exynos driver in drm/ if it wants to use a different
> framework? Right now it is blocking work on a proper drm driver...
>

Noooooo. It's not to use a different framework. It's to use a wrapper instead.

>
>>
>>
>> > especially if this reduces the line count and the code
>> > complexity (as is the case for this patch series). If you don't want
>> > to maintain a drm driver, it simply should be moved away from drm/,
>> > and it should be replaced by a real drm driver in my opinion.
>>
>> So those drivers should be in drm/exynos. Isn't that you really mean
>> those drivers should be driver/gpu/drm?
>
>
> I don't understand this sentence, sorry.

Sorry, again, you mean Exynos drm based drivers should be in
drivers/gpu/drm, not drivers/gpu/drm/exynos?

Thanks,
Inki Dae

>
> Stéphane
>
>
>>
>> If so, That would really be
>> horrible. :(
>>
>
>
>>
>> Please, know that only Exynos drm framework, _not device drivers_, has
>> all dependencies of drm framework, and also I know that other ARM
>> based drm drivers are using same way.
>>
>> Thanks,
>> Inki Dae
>>
>> >
>> > Stéphane
>> >
>> >>
>> >>
>> >> > There are a bunch of real bugs that we've found as a result of having
>> >> > these abstraction layers. Take, for example, dpms. Before this
>> >> > patchset, dpms for fimd was being tracked separately in fimd driver,
>> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>> >> > Furthermore, during suspend, only fimd driver's dpms state was
>> >> > updated, so the others were incorrect. There was also this weird
>> >> > gymnastics that had to happen when dpms was changed in the encoder
>> >> > since it had to walk up to the connector level to change its dpms
>> >> > state. If fimd just directly implemented
>> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>> >> >
>> >>
>> >> That is a issue we should take care of by using the independent layer.
>> >> Then, aren't you take care of that well with the re-factoring patch
>> >> set? :)  It seems that you are outside real point.
>> >>
>> >> > Take a look at exynos_drm_encoder.c  in my tree
>> >> >
>> >> >
>> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>> >> > what does it do that's useful to abstract? All that it does is just
>> >> > call display ops, it's completely useless. The same is true for
>> >> > exynos_drm_connector, it's just dead weight. There is some useful
>> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>> >> > served as a helper library, though.
>> >> >
>> >> >> The abstraction layer you mentioned also means a common spot.
>> >> >> Another one, you patch also makes each sub driver have strongly
>> >> >> dependency
>> >> >> of drm framework. So how we can support existing backlight and lcd
>> >> >> class
>> >> >> based lcd panel drivers if the connector is implemented in each
>> >> >> device
>> >> >> driver later?  the drm header files should be included in
>> >> >> drivers/video/backlight/xxx_lcd.c?
>> >> >>
>> >> >
>> >> > drm_bridge or drm_panel seem like good candidates for this.
>> >> >
>> >>
>> >> Yes, exynos_drm_display could be replaced with drm_panel later if the
>> >> drm_panel can be merged to mainline.
>> >>
>> >> >
>> >> >> And, I will introduce a new framework to support existing lcd panel
>> >> >> drivers
>> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>> >> >> framework is
>> >> >> being tested internally. With this framework, encoder and connector
>> >> >> will be
>> >> >> created when lcd panel or display bus driver such as eDP is probed:
>> >> >> it
>> >> >> doesn’t really need to create encoder and connector in advance if
>> >> >> lcd
>> >> >> panel
>> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>> >> >> encoder
>> >> >> and
>> >> >> connector creation order, when last one is created, crtc and
>> >> >> connector
>> >> >> will
>> >> >> be connected each other. And exynos_drm_display could be implemented
>> >> >> in
>> >> >> other frameworks if we have common structure for display device
>> >> >> driver.
>> >> >> And
>> >> >> also the framework will support lvds driver according to Linux
>> >> >> device
>> >> >> driver
>> >> >> model.
>> >> >>
>> >> >
>> >> > I don't really follow what you're trying to do here, but I think we
>> >> > should be moving in the direction of fewer abstractions in the exynos
>> >> > driver, not more :)
>> >> >
>> >>
>> >> Not abstraction layer, just a bridge for connecting crtc and its
>> >> corresponding encoder/connector, and lvds regardless of creation
>> >> order, and for connecting drm connector and other framework based
>> >> display ops such as drm_panel later.
>> >>
>> >> > Sean
>> >> >
>> >> >
>> >> >
>> >> >> Thanks,
>> >> >> Inki Dae
>> >> >>
>> >> >>> Sean
>> >> >>>
>> >> >>> >>>
>> >> >>> >>> > And another one, the patch 6 passes manager object to
>> >> >>> >>> > manager_ops,
>> >> >>> and
>> >> >>> >>> for
>> >> >>> >>> > this, you made the manager object to be set to driver data;
>> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't reasonable.
>> >> >>> Generally,
>> >> >>> >>> > driver_data would point to device driver's context object.
>> >> >>> >>> >
>> >> >>> >>>
>> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot point.
>> >> >>> >>> The
>> >> >>> >>> driver data is only used up until we get rid of the pm ops, it
>> >> >>> >>> needn't
>> >> >>> >>> be set at all once things go through dpms.
>> >> >>> >>>
>> >> >>> >>
>> >> >>> >> Generally, device drivers can call its own internal functions,
>> >> >>> >> and
>> >> >>> >> they
>> >> >>> will
>> >> >>> >> call that functions with ctx. However, if you set manager to
>> >> >>> driver_data
>> >> >>> >> then that functions should be called with manager object and
>> >> >>> >> also
>> >> >>> internally
>> >> >>> >> that functions should get ctx from the manager object. What is
>> >> >>> >> the
>> >> >>> purpose
>> >> >>> >> of manager? Do you think it's reasonable?
>> >> >>> >>
>> >> >>> >
>> >> >>> > So, to avoid setting the manager as the drvdata, we could
>> >> >>> > implement
>> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>> >> >>> > manager
>> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>> >> >>> > pointer
>> >> >>> > to
>> >> >>> > mgr in ctx, but that creates a circular link between the two.
>> >> >>> > IMO,
>> >> >>> > both of those solutions suck :)
>> >> >>> >
>> >> >>> > I'd much rather just set drvdata to the manager and call the hook
>> >> >>> > directly. Like I said earlier, this is just a temporary step
>> >> >>> > since
>> >> >>> > we
>> >> >>> > remove these pm ops later in the patch series.
>> >> >>> >
>> >> >>> > Sean
>> >> >>> >
>> >> >>> >
>> >> >>> >> Anyway, I'd like to say really sorry about inconvenient again.
>> >> >>> >> So I
>> >> >>> will fix
>> >> >>> >> it.
>> >> >>> >>
>> >> >>> >> Thanks,
>> >> >>> >> Inki Dae
>> >> >>> >>
>> >> >>> >>> Sean
>> >> >>> >>>
>> >> >>> >>>
>> >> >>> >>> > Thanks,
>> >> >>> >>> > Inki Dae
>> >> >>> >>> >
>> >> >>> >>
>> >> >>
>> >> > _______________________________________________
>> >> > dri-devel mailing list
>> >> > dri-devel@lists.freedesktop.org
>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >> _______________________________________________
>> >> dri-devel mailing list
>> >> dri-devel@lists.freedesktop.org
>> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >
>> >
>> >
>> > _______________________________________________
>> > dri-devel mailing list
>> > dri-devel@lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >
>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  4:15                         ` Inki Dae
@ 2013-10-23  4:28                           ` Stéphane Marchesin
  2013-10-23  4:48                             ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Stéphane Marchesin @ 2013-10-23  4:28 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 17689 bytes --]

On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:

> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
> >
> >
> >
> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
> >>
> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
> >> >
> >> >
> >> >
> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
> wrote:
> >> >>
> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
> >> >> > wrote:
> >> >> >>
> >> >> >>
> >> >> >>> -----Original Message-----
> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
> >> >> >>> To: Inki Dae
> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
> >> >> >>> manager/display/subdrv
> >> >> >>>
> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul <
> seanpaul@chromium.org>
> >> >> >>> wrote:
> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae <
> inki.dae@samsung.com>
> >> >> >>> > wrote:
> >> >> >>> >>
> >> >> >>> >>
> >> >> >>> >>> -----Original Message-----
> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
> >> >> >>> >>> To: Inki Dae
> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
> >> >> >>> >>> manager/display/subdrv
> >> >> >>> >>>
> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
> >> >> >>> >>> <inki.dae@samsung.com>
> >> >> >> wrote:
> >> >> >>> >>> >
> >> >> >>> >>> >
> >> >> >>> >>> >> -----Original Message-----
> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
> >> >> >>> >>> >> marcheu@chromium.org;
> >> >> >>> Sean
> >> >> >>> >>> >> Paul
> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
> >> >> >>> >>> >> manager/display/subdrv
> >> >> >>> >>> >>
> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
> >> >> >>> >>> >> result
> >> >> >>> >>> >> is
> >> >> >>> that
> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
> and
> >> >> >>> >>> >> encoder
> >> >> >>> >>> >> functions can directly call into display callbacks. This
> >> >> >>> >>> >> will
> >> >> >>> >>> >> allow
> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
> mixer/hdmi
> >> >> >>> >>> >> &
> >> >> >>> fimd/dp
> >> >> >>> >>> >> with common code.
> >> >> >>> >>> >>
> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> >> >> >>> >>> >> ---
> >> >> >>> >>> >>
> >> >> >>> >>> >> Changes in v2:
> >> >> >>> >>> >>       - Pass display into display_ops instead of context
> >> >> >>> >>> >
> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
> object
> >> >> >>> >>> > into
> >> >> >>> >>> > display_ops and manager_ops.
> >> >> >>> >>> >
> >> >> >>> >>>
> >> >> >>> >>>
> >> >> >>> >>> So you've changed your mind from when you said the following?
> >> >> >>> >>>
> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
> >> >> >>> >>> >>> display->ops->xxx(display, ...);
> >> >> >>> >>> >>>
> >> >> >>> >>> >>> Agree.
> >> >> >>> >>>
> >> >> >>> >>
> >> >> >>> >>
> >> >> >>> >> True. Before that, My comment was to pass device object into
> >> >> >>> display_ops and
> >> >> >>> >> manager_ops, and then you said the good solution is to pass
> >> >> >>> >> manager
> >> >> >>> >> and
> >> >> >>> >> display to each driver. At that time, I thought no matter how
> >> >> >>> >> the
> >> >> >>> callback
> >> >> >>> >> is called if the framework doesn't call callbacks of each
> driver
> >> >> >>> >> with
> >> >> >>> ctx.
> >> >> >>> >> So I agreed.
> >> >> >>> >>
> >> >> >>> >>
> >> >> >>> >>> It would have been nice if you had changed your mind
> *before* I
> >> >> >>> >>> reworked everything. At any rate, I think it's still the
> right
> >> >> >>> >>> thing
> >> >> >>> >>> to do.
> >> >> >>> >>
> >> >> >>> >> Really sorry about that. And I will add new patch for it so
> you
> >> >> >>> >> don't
> >> >> >>> need
> >> >> >>> >> to concern about that.
> >> >> >>> >>
> >> >> >>> >>>
> >> >> >>> >>>
> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
> >> >> >>> >>> > framework
> >> >> >>> >>> based
> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
> >> >> >>> >>> > display -
> >> >> >>> it's
> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
> >> >> >>> >>> > other
> >> >> >>> framework
> >> >> >>> >>> > based driver should include specific exynos drm header.
> >> >> >>> >>> >
> >> >> >>> >>>
> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
> form,
> >> >> >>> >>> we
> >> >> >>> >>> don't need to worry about this. Furthermore, these ops should
> >> >> >>> >>> just
> >> >> >>> >>> go
> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
> >> >> >>> >>> anyways.
> >> >> >>> >>>
> >> >> >>> >>
> >> >> >>> >> Can you assure the display_ops never implemented in other
> >> >> >>> >> framework
> >> >> >>> based
> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities should
> >> >> >>> >> be
> >> >> >>> opened.
> >> >> >>> >>
> >> >> >>> >
> >> >> >>> > I don't think we should let an RFC framework make the code more
> >> >> >>> > complicated for unclear benefit. By removing manager/display
> >> >> >>> > entirely,
> >> >> >>> > we can get rid of a *lot* of other code that is basically just
> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
> >> >> >>> >
> >> >> >>>
> >> >> >>> I hacked this up today to prove it out. Check out the top 5
> commits
> >> >> >>> in
> >> >> >>>
> >> >> >>>
> >> >> >>>
> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
> >> >> >>> staging.
> >> >> >>> It removes exynos_drm_connector in favor of just implementing
> >> >> >>> drm_connector directly. This same treatment should be done for
> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
> to
> >> >> >>> doing this.
> >> >> >>>
> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
> >> >> >>> abstraction layer. Much nicer :)
> >> >> >>>
> >> >> >>
> >> >> >> It seems that you implements connector in each device driver.
> Can't
> >> >> >> they be
> >> >> >> combined as common spot, exynos_connector, again to avoid codes
> from
> >> >> >> duplicated? :)
> >> >> >
> >> >> > There's nothing of substance being duplicated.
> >> >>
> >> >> Not true. xxx_create_connector is duplicated.
> >> >>
> >> >> > In fact, by getting rid
> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
> >> >> > really
> >> >> > take a look at exynos_drm_connector, it's not doing anything
> useful.
> >> >>
> >> >> No, That is for each driver has no any dependency of drm framework.
> >> >>
> >> >> > All it does is translate the drm callbacks into display callbacks,
> so
> >> >> > I think it's much better to just implement the drm callbacks
> >> >> > directly.
> >> >> >
> >> >>
> >> >> No, It has strongly dependency of drm framework. Assume that we
> >> >> implemented the drm callbacks directly, and then some features are
> >> >> added to drm framework, drm_connector side. At this time, we will
> have
> >> >> to take care of each device driver according to the change. That is
> >> >> really not good. Why device drivers should have dependency of drm
> >> >> framework? Just to reduce line counts?
> >> >
> >> >
> >> >
> >> > You seem to miss the point here and elsewhere in the discussion.
> >> > drm/exynos is a drm driver, and as such it should use the drm
> >> > framework,
> >>
> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
> >> exynos drm framework, not drm framework directly. So I mean that
> >> Exynos drm framework based drivers should include only Exynos drm
> >> headers, _not drm header_ directly.
> >
> >
> > Well, I think everyone sees that exynos is different. But my point still
> > remains: why is the exynos driver in drm/ if it wants to use a different
> > framework? Right now it is blocking work on a proper drm driver...
> >
>
> Noooooo. It's not to use a different framework. It's to use a wrapper
> instead.
>

Ok, if you want to call it a wrapper, then what is the point of doing this
wrapping given that it prevents a proper drm-style implementation?



> >
> >>
> >>
> >> > especially if this reduces the line count and the code
> >> > complexity (as is the case for this patch series). If you don't want
> >> > to maintain a drm driver, it simply should be moved away from drm/,
> >> > and it should be replaced by a real drm driver in my opinion.
> >>
> >> So those drivers should be in drm/exynos. Isn't that you really mean
> >> those drivers should be driver/gpu/drm?
> >
> >
> > I don't understand this sentence, sorry.
>
> Sorry, again, you mean Exynos drm based drivers should be in
> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>
> Is the exynos drm useful in its current shape at all? My recommendation
would be to fork off a real drm driver in gpu/drm/exynos with the current
code as a base.

Stéphane



> Thanks,
> Inki Dae
>
> >
> > Stéphane
> >
> >
> >>
> >> If so, That would really be
> >> horrible. :(
> >>
> >
> >
> >>
> >> Please, know that only Exynos drm framework, _not device drivers_, has
> >> all dependencies of drm framework, and also I know that other ARM
> >> based drm drivers are using same way.
> >>
> >> Thanks,
> >> Inki Dae
> >>
> >> >
> >> > Stéphane
> >> >
> >> >>
> >> >>
> >> >> > There are a bunch of real bugs that we've found as a result of
> having
> >> >> > these abstraction layers. Take, for example, dpms. Before this
> >> >> > patchset, dpms for fimd was being tracked separately in fimd
> driver,
> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
> >> >> > updated, so the others were incorrect. There was also this weird
> >> >> > gymnastics that had to happen when dpms was changed in the encoder
> >> >> > since it had to walk up to the connector level to change its dpms
> >> >> > state. If fimd just directly implemented
> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
> >> >> >
> >> >>
> >> >> That is a issue we should take care of by using the independent
> layer.
> >> >> Then, aren't you take care of that well with the re-factoring patch
> >> >> set? :)  It seems that you are outside real point.
> >> >>
> >> >> > Take a look at exynos_drm_encoder.c  in my tree
> >> >> >
> >> >> >
> >> >> > (
> https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c
> ),
> >> >> > what does it do that's useful to abstract? All that it does is just
> >> >> > call display ops, it's completely useless. The same is true for
> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
> >> >> > served as a helper library, though.
> >> >> >
> >> >> >> The abstraction layer you mentioned also means a common spot.
> >> >> >> Another one, you patch also makes each sub driver have strongly
> >> >> >> dependency
> >> >> >> of drm framework. So how we can support existing backlight and lcd
> >> >> >> class
> >> >> >> based lcd panel drivers if the connector is implemented in each
> >> >> >> device
> >> >> >> driver later?  the drm header files should be included in
> >> >> >> drivers/video/backlight/xxx_lcd.c?
> >> >> >>
> >> >> >
> >> >> > drm_bridge or drm_panel seem like good candidates for this.
> >> >> >
> >> >>
> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if the
> >> >> drm_panel can be merged to mainline.
> >> >>
> >> >> >
> >> >> >> And, I will introduce a new framework to support existing lcd
> panel
> >> >> >> drivers
> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
> >> >> >> framework is
> >> >> >> being tested internally. With this framework, encoder and
> connector
> >> >> >> will be
> >> >> >> created when lcd panel or display bus driver such as eDP is
> probed:
> >> >> >> it
> >> >> >> doesn’t really need to create encoder and connector in advance if
> >> >> >> lcd
> >> >> >> panel
> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
> >> >> >> encoder
> >> >> >> and
> >> >> >> connector creation order, when last one is created, crtc and
> >> >> >> connector
> >> >> >> will
> >> >> >> be connected each other. And exynos_drm_display could be
> implemented
> >> >> >> in
> >> >> >> other frameworks if we have common structure for display device
> >> >> >> driver.
> >> >> >> And
> >> >> >> also the framework will support lvds driver according to Linux
> >> >> >> device
> >> >> >> driver
> >> >> >> model.
> >> >> >>
> >> >> >
> >> >> > I don't really follow what you're trying to do here, but I think we
> >> >> > should be moving in the direction of fewer abstractions in the
> exynos
> >> >> > driver, not more :)
> >> >> >
> >> >>
> >> >> Not abstraction layer, just a bridge for connecting crtc and its
> >> >> corresponding encoder/connector, and lvds regardless of creation
> >> >> order, and for connecting drm connector and other framework based
> >> >> display ops such as drm_panel later.
> >> >>
> >> >> > Sean
> >> >> >
> >> >> >
> >> >> >
> >> >> >> Thanks,
> >> >> >> Inki Dae
> >> >> >>
> >> >> >>> Sean
> >> >> >>>
> >> >> >>> >>>
> >> >> >>> >>> > And another one, the patch 6 passes manager object to
> >> >> >>> >>> > manager_ops,
> >> >> >>> and
> >> >> >>> >>> for
> >> >> >>> >>> > this, you made the manager object to be set to driver data;
> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
> reasonable.
> >> >> >>> Generally,
> >> >> >>> >>> > driver_data would point to device driver's context object.
> >> >> >>> >>> >
> >> >> >>> >>>
> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
> point.
> >> >> >>> >>> The
> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
> it
> >> >> >>> >>> needn't
> >> >> >>> >>> be set at all once things go through dpms.
> >> >> >>> >>>
> >> >> >>> >>
> >> >> >>> >> Generally, device drivers can call its own internal functions,
> >> >> >>> >> and
> >> >> >>> >> they
> >> >> >>> will
> >> >> >>> >> call that functions with ctx. However, if you set manager to
> >> >> >>> driver_data
> >> >> >>> >> then that functions should be called with manager object and
> >> >> >>> >> also
> >> >> >>> internally
> >> >> >>> >> that functions should get ctx from the manager object. What is
> >> >> >>> >> the
> >> >> >>> purpose
> >> >> >>> >> of manager? Do you think it's reasonable?
> >> >> >>> >>
> >> >> >>> >
> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
> >> >> >>> > implement
> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
> >> >> >>> > manager
> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
> >> >> >>> > pointer
> >> >> >>> > to
> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
> >> >> >>> > IMO,
> >> >> >>> > both of those solutions suck :)
> >> >> >>> >
> >> >> >>> > I'd much rather just set drvdata to the manager and call the
> hook
> >> >> >>> > directly. Like I said earlier, this is just a temporary step
> >> >> >>> > since
> >> >> >>> > we
> >> >> >>> > remove these pm ops later in the patch series.
> >> >> >>> >
> >> >> >>> > Sean
> >> >> >>> >
> >> >> >>> >
> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient again.
> >> >> >>> >> So I
> >> >> >>> will fix
> >> >> >>> >> it.
> >> >> >>> >>
> >> >> >>> >> Thanks,
> >> >> >>> >> Inki Dae
> >> >> >>> >>
> >> >> >>> >>> Sean
> >> >> >>> >>>
> >> >> >>> >>>
> >> >> >>> >>> > Thanks,
> >> >> >>> >>> > Inki Dae
> >> >> >>> >>> >
> >> >> >>> >>
> >> >> >>
> >> >> > _______________________________________________
> >> >> > dri-devel mailing list
> >> >> > dri-devel@lists.freedesktop.org
> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> >> _______________________________________________
> >> >> dri-devel mailing list
> >> >> dri-devel@lists.freedesktop.org
> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> >
> >> >
> >> >
> >> > _______________________________________________
> >> > dri-devel mailing list
> >> > dri-devel@lists.freedesktop.org
> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >> >
> >
> >
> >
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >
>

[-- Attachment #1.2: Type: text/html, Size: 29708 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  4:28                           ` Stéphane Marchesin
@ 2013-10-23  4:48                             ` Inki Dae
  2013-10-23  5:19                               ` Sean Paul
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-23  4:48 UTC (permalink / raw)
  To: Stéphane Marchesin; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>
>
>
> On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>
>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>> >
>> >
>> >
>> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>> >>
>> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>> >> >
>> >> >
>> >> >
>> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
>> >> > wrote:
>> >> >>
>> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >>
>> >> >> >>> -----Original Message-----
>> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>> >> >> >>> To: Inki Dae
>> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>> >> >> >>> manager/display/subdrv
>> >> >> >>>
>> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul
>> >> >> >>> <seanpaul@chromium.org>
>> >> >> >>> wrote:
>> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae
>> >> >> >>> > <inki.dae@samsung.com>
>> >> >> >>> > wrote:
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >>> -----Original Message-----
>> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>> >> >> >>> >>> To: Inki Dae
>> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>> >> >> >>> >>> manager/display/subdrv
>> >> >> >>> >>>
>> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>> >> >> >>> >>> <inki.dae@samsung.com>
>> >> >> >> wrote:
>> >> >> >>> >>> >
>> >> >> >>> >>> >
>> >> >> >>> >>> >> -----Original Message-----
>> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>> >> >> >>> >>> >> marcheu@chromium.org;
>> >> >> >>> Sean
>> >> >> >>> >>> >> Paul
>> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>> >> >> >>> >>> >> manager/display/subdrv
>> >> >> >>> >>> >>
>> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
>> >> >> >>> >>> >> result
>> >> >> >>> >>> >> is
>> >> >> >>> that
>> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
>> >> >> >>> >>> >> and
>> >> >> >>> >>> >> encoder
>> >> >> >>> >>> >> functions can directly call into display callbacks. This
>> >> >> >>> >>> >> will
>> >> >> >>> >>> >> allow
>> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
>> >> >> >>> >>> >> mixer/hdmi
>> >> >> >>> >>> >> &
>> >> >> >>> fimd/dp
>> >> >> >>> >>> >> with common code.
>> >> >> >>> >>> >>
>> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> >> >> >>> >>> >> ---
>> >> >> >>> >>> >>
>> >> >> >>> >>> >> Changes in v2:
>> >> >> >>> >>> >>       - Pass display into display_ops instead of context
>> >> >> >>> >>> >
>> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
>> >> >> >>> >>> > object
>> >> >> >>> >>> > into
>> >> >> >>> >>> > display_ops and manager_ops.
>> >> >> >>> >>> >
>> >> >> >>> >>>
>> >> >> >>> >>>
>> >> >> >>> >>> So you've changed your mind from when you said the
>> >> >> >>> >>> following?
>> >> >> >>> >>>
>> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>> >> >> >>> >>> >>> display->ops->xxx(display, ...);
>> >> >> >>> >>> >>>
>> >> >> >>> >>> >>> Agree.
>> >> >> >>> >>>
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >> True. Before that, My comment was to pass device object into
>> >> >> >>> display_ops and
>> >> >> >>> >> manager_ops, and then you said the good solution is to pass
>> >> >> >>> >> manager
>> >> >> >>> >> and
>> >> >> >>> >> display to each driver. At that time, I thought no matter how
>> >> >> >>> >> the
>> >> >> >>> callback
>> >> >> >>> >> is called if the framework doesn't call callbacks of each
>> >> >> >>> >> driver
>> >> >> >>> >> with
>> >> >> >>> ctx.
>> >> >> >>> >> So I agreed.
>> >> >> >>> >>
>> >> >> >>> >>
>> >> >> >>> >>> It would have been nice if you had changed your mind
>> >> >> >>> >>> *before* I
>> >> >> >>> >>> reworked everything. At any rate, I think it's still the
>> >> >> >>> >>> right
>> >> >> >>> >>> thing
>> >> >> >>> >>> to do.
>> >> >> >>> >>
>> >> >> >>> >> Really sorry about that. And I will add new patch for it so
>> >> >> >>> >> you
>> >> >> >>> >> don't
>> >> >> >>> need
>> >> >> >>> >> to concern about that.
>> >> >> >>> >>
>> >> >> >>> >>>
>> >> >> >>> >>>
>> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>> >> >> >>> >>> > framework
>> >> >> >>> >>> based
>> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>> >> >> >>> >>> > display -
>> >> >> >>> it's
>> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>> >> >> >>> >>> > other
>> >> >> >>> framework
>> >> >> >>> >>> > based driver should include specific exynos drm header.
>> >> >> >>> >>> >
>> >> >> >>> >>>
>> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
>> >> >> >>> >>> form,
>> >> >> >>> >>> we
>> >> >> >>> >>> don't need to worry about this. Furthermore, these ops
>> >> >> >>> >>> should
>> >> >> >>> >>> just
>> >> >> >>> >>> go
>> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>> >> >> >>> >>> anyways.
>> >> >> >>> >>>
>> >> >> >>> >>
>> >> >> >>> >> Can you assure the display_ops never implemented in other
>> >> >> >>> >> framework
>> >> >> >>> based
>> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities
>> >> >> >>> >> should
>> >> >> >>> >> be
>> >> >> >>> opened.
>> >> >> >>> >>
>> >> >> >>> >
>> >> >> >>> > I don't think we should let an RFC framework make the code
>> >> >> >>> > more
>> >> >> >>> > complicated for unclear benefit. By removing manager/display
>> >> >> >>> > entirely,
>> >> >> >>> > we can get rid of a *lot* of other code that is basically just
>> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>> >> >> >>> >
>> >> >> >>>
>> >> >> >>> I hacked this up today to prove it out. Check out the top 5
>> >> >> >>> commits
>> >> >> >>> in
>> >> >> >>>
>> >> >> >>>
>> >> >> >>>
>> >> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>> >> >> >>> staging.
>> >> >> >>> It removes exynos_drm_connector in favor of just implementing
>> >> >> >>> drm_connector directly. This same treatment should be done for
>> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
>> >> >> >>> to
>> >> >> >>> doing this.
>> >> >> >>>
>> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
>> >> >> >>> abstraction layer. Much nicer :)
>> >> >> >>>
>> >> >> >>
>> >> >> >> It seems that you implements connector in each device driver.
>> >> >> >> Can't
>> >> >> >> they be
>> >> >> >> combined as common spot, exynos_connector, again to avoid codes
>> >> >> >> from
>> >> >> >> duplicated? :)
>> >> >> >
>> >> >> > There's nothing of substance being duplicated.
>> >> >>
>> >> >> Not true. xxx_create_connector is duplicated.
>> >> >>
>> >> >> > In fact, by getting rid
>> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>> >> >> > really
>> >> >> > take a look at exynos_drm_connector, it's not doing anything
>> >> >> > useful.
>> >> >>
>> >> >> No, That is for each driver has no any dependency of drm framework.
>> >> >>
>> >> >> > All it does is translate the drm callbacks into display callbacks,
>> >> >> > so
>> >> >> > I think it's much better to just implement the drm callbacks
>> >> >> > directly.
>> >> >> >
>> >> >>
>> >> >> No, It has strongly dependency of drm framework. Assume that we
>> >> >> implemented the drm callbacks directly, and then some features are
>> >> >> added to drm framework, drm_connector side. At this time, we will
>> >> >> have
>> >> >> to take care of each device driver according to the change. That is
>> >> >> really not good. Why device drivers should have dependency of drm
>> >> >> framework? Just to reduce line counts?
>> >> >
>> >> >
>> >> >
>> >> > You seem to miss the point here and elsewhere in the discussion.
>> >> > drm/exynos is a drm driver, and as such it should use the drm
>> >> > framework,
>> >>
>> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
>> >> exynos drm framework, not drm framework directly. So I mean that
>> >> Exynos drm framework based drivers should include only Exynos drm
>> >> headers, _not drm header_ directly.
>> >
>> >
>> > Well, I think everyone sees that exynos is different. But my point still
>> > remains: why is the exynos driver in drm/ if it wants to use a different
>> > framework? Right now it is blocking work on a proper drm driver...
>> >
>>
>> Noooooo. It's not to use a different framework. It's to use a wrapper
>> instead.
>
>
> Ok, if you want to call it a wrapper, then what is the point of doing this
> wrapping given that it prevents a proper drm-style implementation?
>

I already commented. That is for only Exynos drm framework has
dependency of drm framework directly, and Exynos drm based drivers
include only Exynos drm headers.

>
>>
>> >
>> >>
>> >>
>> >> > especially if this reduces the line count and the code
>> >> > complexity (as is the case for this patch series). If you don't want
>> >> > to maintain a drm driver, it simply should be moved away from drm/,
>> >> > and it should be replaced by a real drm driver in my opinion.
>> >>
>> >> So those drivers should be in drm/exynos. Isn't that you really mean
>> >> those drivers should be driver/gpu/drm?
>> >
>> >
>> > I don't understand this sentence, sorry.
>>
>> Sorry, again, you mean Exynos drm based drivers should be in
>> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>>
> Is the exynos drm useful in its current shape at all? My recommendation
> would be to fork off a real drm driver in gpu/drm/exynos with the current
> code as a base.
>

Yes as of now. of course, There could be a better way. However, I
don't want for Exynos drm based drivers have dependency of drm
framework directly.

Thanks for your opinions.
Inki Dae

> Stéphane
>
>
>>
>> Thanks,
>> Inki Dae
>>
>> >
>> > Stéphane
>> >
>> >
>> >>
>> >> If so, That would really be
>> >> horrible. :(
>> >>
>> >
>> >
>> >>
>> >> Please, know that only Exynos drm framework, _not device drivers_, has
>> >> all dependencies of drm framework, and also I know that other ARM
>> >> based drm drivers are using same way.
>> >>
>> >> Thanks,
>> >> Inki Dae
>> >>
>> >> >
>> >> > Stéphane
>> >> >
>> >> >>
>> >> >>
>> >> >> > There are a bunch of real bugs that we've found as a result of
>> >> >> > having
>> >> >> > these abstraction layers. Take, for example, dpms. Before this
>> >> >> > patchset, dpms for fimd was being tracked separately in fimd
>> >> >> > driver,
>> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
>> >> >> > updated, so the others were incorrect. There was also this weird
>> >> >> > gymnastics that had to happen when dpms was changed in the encoder
>> >> >> > since it had to walk up to the connector level to change its dpms
>> >> >> > state. If fimd just directly implemented
>> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>> >> >> >
>> >> >>
>> >> >> That is a issue we should take care of by using the independent
>> >> >> layer.
>> >> >> Then, aren't you take care of that well with the re-factoring patch
>> >> >> set? :)  It seems that you are outside real point.
>> >> >>
>> >> >> > Take a look at exynos_drm_encoder.c  in my tree
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>> >> >> > what does it do that's useful to abstract? All that it does is
>> >> >> > just
>> >> >> > call display ops, it's completely useless. The same is true for
>> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
>> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>> >> >> > served as a helper library, though.
>> >> >> >
>> >> >> >> The abstraction layer you mentioned also means a common spot.
>> >> >> >> Another one, you patch also makes each sub driver have strongly
>> >> >> >> dependency
>> >> >> >> of drm framework. So how we can support existing backlight and
>> >> >> >> lcd
>> >> >> >> class
>> >> >> >> based lcd panel drivers if the connector is implemented in each
>> >> >> >> device
>> >> >> >> driver later?  the drm header files should be included in
>> >> >> >> drivers/video/backlight/xxx_lcd.c?
>> >> >> >>
>> >> >> >
>> >> >> > drm_bridge or drm_panel seem like good candidates for this.
>> >> >> >
>> >> >>
>> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if
>> >> >> the
>> >> >> drm_panel can be merged to mainline.
>> >> >>
>> >> >> >
>> >> >> >> And, I will introduce a new framework to support existing lcd
>> >> >> >> panel
>> >> >> >> drivers
>> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>> >> >> >> framework is
>> >> >> >> being tested internally. With this framework, encoder and
>> >> >> >> connector
>> >> >> >> will be
>> >> >> >> created when lcd panel or display bus driver such as eDP is
>> >> >> >> probed:
>> >> >> >> it
>> >> >> >> doesn’t really need to create encoder and connector in advance if
>> >> >> >> lcd
>> >> >> >> panel
>> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>> >> >> >> encoder
>> >> >> >> and
>> >> >> >> connector creation order, when last one is created, crtc and
>> >> >> >> connector
>> >> >> >> will
>> >> >> >> be connected each other. And exynos_drm_display could be
>> >> >> >> implemented
>> >> >> >> in
>> >> >> >> other frameworks if we have common structure for display device
>> >> >> >> driver.
>> >> >> >> And
>> >> >> >> also the framework will support lvds driver according to Linux
>> >> >> >> device
>> >> >> >> driver
>> >> >> >> model.
>> >> >> >>
>> >> >> >
>> >> >> > I don't really follow what you're trying to do here, but I think
>> >> >> > we
>> >> >> > should be moving in the direction of fewer abstractions in the
>> >> >> > exynos
>> >> >> > driver, not more :)
>> >> >> >
>> >> >>
>> >> >> Not abstraction layer, just a bridge for connecting crtc and its
>> >> >> corresponding encoder/connector, and lvds regardless of creation
>> >> >> order, and for connecting drm connector and other framework based
>> >> >> display ops such as drm_panel later.
>> >> >>
>> >> >> > Sean
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> >> Thanks,
>> >> >> >> Inki Dae
>> >> >> >>
>> >> >> >>> Sean
>> >> >> >>>
>> >> >> >>> >>>
>> >> >> >>> >>> > And another one, the patch 6 passes manager object to
>> >> >> >>> >>> > manager_ops,
>> >> >> >>> and
>> >> >> >>> >>> for
>> >> >> >>> >>> > this, you made the manager object to be set to driver
>> >> >> >>> >>> > data;
>> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
>> >> >> >>> >>> > reasonable.
>> >> >> >>> Generally,
>> >> >> >>> >>> > driver_data would point to device driver's context object.
>> >> >> >>> >>> >
>> >> >> >>> >>>
>> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
>> >> >> >>> >>> point.
>> >> >> >>> >>> The
>> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
>> >> >> >>> >>> it
>> >> >> >>> >>> needn't
>> >> >> >>> >>> be set at all once things go through dpms.
>> >> >> >>> >>>
>> >> >> >>> >>
>> >> >> >>> >> Generally, device drivers can call its own internal
>> >> >> >>> >> functions,
>> >> >> >>> >> and
>> >> >> >>> >> they
>> >> >> >>> will
>> >> >> >>> >> call that functions with ctx. However, if you set manager to
>> >> >> >>> driver_data
>> >> >> >>> >> then that functions should be called with manager object and
>> >> >> >>> >> also
>> >> >> >>> internally
>> >> >> >>> >> that functions should get ctx from the manager object. What
>> >> >> >>> >> is
>> >> >> >>> >> the
>> >> >> >>> purpose
>> >> >> >>> >> of manager? Do you think it's reasonable?
>> >> >> >>> >>
>> >> >> >>> >
>> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
>> >> >> >>> > implement
>> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>> >> >> >>> > manager
>> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>> >> >> >>> > pointer
>> >> >> >>> > to
>> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
>> >> >> >>> > IMO,
>> >> >> >>> > both of those solutions suck :)
>> >> >> >>> >
>> >> >> >>> > I'd much rather just set drvdata to the manager and call the
>> >> >> >>> > hook
>> >> >> >>> > directly. Like I said earlier, this is just a temporary step
>> >> >> >>> > since
>> >> >> >>> > we
>> >> >> >>> > remove these pm ops later in the patch series.
>> >> >> >>> >
>> >> >> >>> > Sean
>> >> >> >>> >
>> >> >> >>> >
>> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient
>> >> >> >>> >> again.
>> >> >> >>> >> So I
>> >> >> >>> will fix
>> >> >> >>> >> it.
>> >> >> >>> >>
>> >> >> >>> >> Thanks,
>> >> >> >>> >> Inki Dae
>> >> >> >>> >>
>> >> >> >>> >>> Sean
>> >> >> >>> >>>
>> >> >> >>> >>>
>> >> >> >>> >>> > Thanks,
>> >> >> >>> >>> > Inki Dae
>> >> >> >>> >>> >
>> >> >> >>> >>
>> >> >> >>
>> >> >> > _______________________________________________
>> >> >> > dri-devel mailing list
>> >> >> > dri-devel@lists.freedesktop.org
>> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >> >> _______________________________________________
>> >> >> dri-devel mailing list
>> >> >> dri-devel@lists.freedesktop.org
>> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >> >
>> >> >
>> >> >
>> >> > _______________________________________________
>> >> > dri-devel mailing list
>> >> > dri-devel@lists.freedesktop.org
>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >> >
>> >
>> >
>> >
>> > _______________________________________________
>> > dri-devel mailing list
>> > dri-devel@lists.freedesktop.org
>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> >
>
>
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-22 10:30   ` Inki Dae
@ 2013-10-23  5:18     ` Inki Dae
  0 siblings, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-23  5:18 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, DRI mailing list

2013/10/22 Inki Dae <inki.dae@samsung.com>:
> 2013/10/17 Sean Paul <seanpaul@chromium.org>:
>> This patch splits display and manager from subdrv. The result is that
>> crtc functions can directly call into manager callbacks and encoder
>> functions can directly call into display callbacks. This will allow
>> us to remove the exynos_drm_hdmi shim and support mixer/hdmi & fimd/dp
>> with common code.
>>
>> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>> ---
>>
>> Changes in v2:
>>         - Pass display into display_ops instead of context
>>
>>  drivers/gpu/drm/exynos/exynos_drm_connector.c |  50 ++-
>>  drivers/gpu/drm/exynos/exynos_drm_core.c      | 181 ++++++++---
>>  drivers/gpu/drm/exynos/exynos_drm_crtc.c      | 115 +++++--
>>  drivers/gpu/drm/exynos/exynos_drm_crtc.h      |  20 +-
>>  drivers/gpu/drm/exynos/exynos_drm_drv.c       |  29 +-
>>  drivers/gpu/drm/exynos/exynos_drm_drv.h       | 106 +++---
>>  drivers/gpu/drm/exynos/exynos_drm_encoder.c   | 258 ++-------------
>>  drivers/gpu/drm/exynos/exynos_drm_encoder.h   |  18 +-
>>  drivers/gpu/drm/exynos/exynos_drm_fb.c        |   4 +-
>>  drivers/gpu/drm/exynos/exynos_drm_fimd.c      | 161 +++++----
>>  drivers/gpu/drm/exynos/exynos_drm_hdmi.c      | 449 --------------------------
>
> Build error. it seems that you missed vidi module. Can you consider
> vidi module also?
>

Sean, ping~~~

> Thanks,
> Inki Dae
>
>>  drivers/gpu/drm/exynos/exynos_drm_hdmi.h      |   2 +
>>  drivers/gpu/drm/exynos/exynos_drm_plane.c     |  15 +-
>>  13 files changed, 466 insertions(+), 942 deletions(-)
>>  delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_hdmi.c
>>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  4:48                             ` Inki Dae
@ 2013-10-23  5:19                               ` Sean Paul
  2013-10-23  5:42                                 ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-23  5:19 UTC (permalink / raw)
  To: Inki Dae; +Cc: dri-devel, Stéphane Marchesin

On Wed, Oct 23, 2013 at 12:48 AM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>
>>
>>
>> On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>
>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>> >
>>> >
>>> >
>>> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>> >>
>>> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>> >> >
>>> >> >
>>> >> >
>>> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
>>> >> > wrote:
>>> >> >>
>>> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>>> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>>> >> >> > wrote:
>>> >> >> >>
>>> >> >> >>
>>> >> >> >>> -----Original Message-----
>>> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>>> >> >> >>> To: Inki Dae
>>> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>> >> >> >>> manager/display/subdrv
>>> >> >> >>>
>>> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul
>>> >> >> >>> <seanpaul@chromium.org>
>>> >> >> >>> wrote:
>>> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae
>>> >> >> >>> > <inki.dae@samsung.com>
>>> >> >> >>> > wrote:
>>> >> >> >>> >>
>>> >> >> >>> >>
>>> >> >> >>> >>> -----Original Message-----
>>> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>> >> >> >>> >>> To: Inki Dae
>>> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>> >> >> >>> >>> manager/display/subdrv
>>> >> >> >>> >>>
>>> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>>> >> >> >>> >>> <inki.dae@samsung.com>
>>> >> >> >> wrote:
>>> >> >> >>> >>> >
>>> >> >> >>> >>> >
>>> >> >> >>> >>> >> -----Original Message-----
>>> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>>> >> >> >>> >>> >> marcheu@chromium.org;
>>> >> >> >>> Sean
>>> >> >> >>> >>> >> Paul
>>> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>>> >> >> >>> >>> >> manager/display/subdrv
>>> >> >> >>> >>> >>
>>> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
>>> >> >> >>> >>> >> result
>>> >> >> >>> >>> >> is
>>> >> >> >>> that
>>> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
>>> >> >> >>> >>> >> and
>>> >> >> >>> >>> >> encoder
>>> >> >> >>> >>> >> functions can directly call into display callbacks. This
>>> >> >> >>> >>> >> will
>>> >> >> >>> >>> >> allow
>>> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
>>> >> >> >>> >>> >> mixer/hdmi
>>> >> >> >>> >>> >> &
>>> >> >> >>> fimd/dp
>>> >> >> >>> >>> >> with common code.
>>> >> >> >>> >>> >>
>>> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>> >> >> >>> >>> >> ---
>>> >> >> >>> >>> >>
>>> >> >> >>> >>> >> Changes in v2:
>>> >> >> >>> >>> >>       - Pass display into display_ops instead of context
>>> >> >> >>> >>> >
>>> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
>>> >> >> >>> >>> > object
>>> >> >> >>> >>> > into
>>> >> >> >>> >>> > display_ops and manager_ops.
>>> >> >> >>> >>> >
>>> >> >> >>> >>>
>>> >> >> >>> >>>
>>> >> >> >>> >>> So you've changed your mind from when you said the
>>> >> >> >>> >>> following?
>>> >> >> >>> >>>
>>> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>>> >> >> >>> >>> >>> display->ops->xxx(display, ...);
>>> >> >> >>> >>> >>>
>>> >> >> >>> >>> >>> Agree.
>>> >> >> >>> >>>
>>> >> >> >>> >>
>>> >> >> >>> >>
>>> >> >> >>> >> True. Before that, My comment was to pass device object into
>>> >> >> >>> display_ops and
>>> >> >> >>> >> manager_ops, and then you said the good solution is to pass
>>> >> >> >>> >> manager
>>> >> >> >>> >> and
>>> >> >> >>> >> display to each driver. At that time, I thought no matter how
>>> >> >> >>> >> the
>>> >> >> >>> callback
>>> >> >> >>> >> is called if the framework doesn't call callbacks of each
>>> >> >> >>> >> driver
>>> >> >> >>> >> with
>>> >> >> >>> ctx.
>>> >> >> >>> >> So I agreed.
>>> >> >> >>> >>
>>> >> >> >>> >>
>>> >> >> >>> >>> It would have been nice if you had changed your mind
>>> >> >> >>> >>> *before* I
>>> >> >> >>> >>> reworked everything. At any rate, I think it's still the
>>> >> >> >>> >>> right
>>> >> >> >>> >>> thing
>>> >> >> >>> >>> to do.
>>> >> >> >>> >>
>>> >> >> >>> >> Really sorry about that. And I will add new patch for it so
>>> >> >> >>> >> you
>>> >> >> >>> >> don't
>>> >> >> >>> need
>>> >> >> >>> >> to concern about that.
>>> >> >> >>> >>
>>> >> >> >>> >>>
>>> >> >> >>> >>>
>>> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>>> >> >> >>> >>> > framework
>>> >> >> >>> >>> based
>>> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>>> >> >> >>> >>> > display -
>>> >> >> >>> it's
>>> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>>> >> >> >>> >>> > other
>>> >> >> >>> framework
>>> >> >> >>> >>> > based driver should include specific exynos drm header.
>>> >> >> >>> >>> >
>>> >> >> >>> >>>
>>> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
>>> >> >> >>> >>> form,
>>> >> >> >>> >>> we
>>> >> >> >>> >>> don't need to worry about this. Furthermore, these ops
>>> >> >> >>> >>> should
>>> >> >> >>> >>> just
>>> >> >> >>> >>> go
>>> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>>> >> >> >>> >>> anyways.
>>> >> >> >>> >>>
>>> >> >> >>> >>
>>> >> >> >>> >> Can you assure the display_ops never implemented in other
>>> >> >> >>> >> framework
>>> >> >> >>> based
>>> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities
>>> >> >> >>> >> should
>>> >> >> >>> >> be
>>> >> >> >>> opened.
>>> >> >> >>> >>
>>> >> >> >>> >
>>> >> >> >>> > I don't think we should let an RFC framework make the code
>>> >> >> >>> > more
>>> >> >> >>> > complicated for unclear benefit. By removing manager/display
>>> >> >> >>> > entirely,
>>> >> >> >>> > we can get rid of a *lot* of other code that is basically just
>>> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>> >> >> >>> >
>>> >> >> >>>
>>> >> >> >>> I hacked this up today to prove it out. Check out the top 5
>>> >> >> >>> commits
>>> >> >> >>> in
>>> >> >> >>>
>>> >> >> >>>
>>> >> >> >>>
>>> >> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>> >> >> >>> staging.
>>> >> >> >>> It removes exynos_drm_connector in favor of just implementing
>>> >> >> >>> drm_connector directly. This same treatment should be done for
>>> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
>>> >> >> >>> to
>>> >> >> >>> doing this.
>>> >> >> >>>
>>> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
>>> >> >> >>> abstraction layer. Much nicer :)
>>> >> >> >>>
>>> >> >> >>
>>> >> >> >> It seems that you implements connector in each device driver.
>>> >> >> >> Can't
>>> >> >> >> they be
>>> >> >> >> combined as common spot, exynos_connector, again to avoid codes
>>> >> >> >> from
>>> >> >> >> duplicated? :)
>>> >> >> >
>>> >> >> > There's nothing of substance being duplicated.
>>> >> >>
>>> >> >> Not true. xxx_create_connector is duplicated.
>>> >> >>
>>> >> >> > In fact, by getting rid
>>> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>>> >> >> > really
>>> >> >> > take a look at exynos_drm_connector, it's not doing anything
>>> >> >> > useful.
>>> >> >>
>>> >> >> No, That is for each driver has no any dependency of drm framework.
>>> >> >>
>>> >> >> > All it does is translate the drm callbacks into display callbacks,
>>> >> >> > so
>>> >> >> > I think it's much better to just implement the drm callbacks
>>> >> >> > directly.
>>> >> >> >
>>> >> >>
>>> >> >> No, It has strongly dependency of drm framework. Assume that we
>>> >> >> implemented the drm callbacks directly, and then some features are
>>> >> >> added to drm framework, drm_connector side. At this time, we will
>>> >> >> have
>>> >> >> to take care of each device driver according to the change. That is
>>> >> >> really not good. Why device drivers should have dependency of drm
>>> >> >> framework? Just to reduce line counts?
>>> >> >
>>> >> >
>>> >> >
>>> >> > You seem to miss the point here and elsewhere in the discussion.
>>> >> > drm/exynos is a drm driver, and as such it should use the drm
>>> >> > framework,
>>> >>
>>> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
>>> >> exynos drm framework, not drm framework directly. So I mean that
>>> >> Exynos drm framework based drivers should include only Exynos drm
>>> >> headers, _not drm header_ directly.
>>> >
>>> >
>>> > Well, I think everyone sees that exynos is different. But my point still
>>> > remains: why is the exynos driver in drm/ if it wants to use a different
>>> > framework? Right now it is blocking work on a proper drm driver...
>>> >
>>>
>>> Noooooo. It's not to use a different framework. It's to use a wrapper
>>> instead.
>>
>>
>> Ok, if you want to call it a wrapper, then what is the point of doing this
>> wrapping given that it prevents a proper drm-style implementation?
>>
>
> I already commented. That is for only Exynos drm framework has
> dependency of drm framework directly, and Exynos drm based drivers
> include only Exynos drm headers.
>
>>
>>>
>>> >
>>> >>
>>> >>
>>> >> > especially if this reduces the line count and the code
>>> >> > complexity (as is the case for this patch series). If you don't want
>>> >> > to maintain a drm driver, it simply should be moved away from drm/,
>>> >> > and it should be replaced by a real drm driver in my opinion.
>>> >>
>>> >> So those drivers should be in drm/exynos. Isn't that you really mean
>>> >> those drivers should be driver/gpu/drm?
>>> >
>>> >
>>> > I don't understand this sentence, sorry.
>>>
>>> Sorry, again, you mean Exynos drm based drivers should be in
>>> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>>>
>> Is the exynos drm useful in its current shape at all? My recommendation
>> would be to fork off a real drm driver in gpu/drm/exynos with the current
>> code as a base.
>>
>
> Yes as of now. of course, There could be a better way. However, I
> don't want for Exynos drm based drivers have dependency of drm
> framework directly.
>

Just to satisfy my curiosity, do you actually have something that uses
these drivers outside of drm?

So I think we've reached somewhat of an impasse. I'd like to move the
driver towards a proper drm driver (ie: no exynos
framework/wrapper/whatever), you'd like to keep things separate. So
should we create a new exynos driver drivers/drm/gpu/exynos5 to house
the drm driver?

Sean


> Thanks for your opinions.
> Inki Dae
>
>> Stéphane
>>
>>
>>>
>>> Thanks,
>>> Inki Dae
>>>
>>> >
>>> > Stéphane
>>> >
>>> >
>>> >>
>>> >> If so, That would really be
>>> >> horrible. :(
>>> >>
>>> >
>>> >
>>> >>
>>> >> Please, know that only Exynos drm framework, _not device drivers_, has
>>> >> all dependencies of drm framework, and also I know that other ARM
>>> >> based drm drivers are using same way.
>>> >>
>>> >> Thanks,
>>> >> Inki Dae
>>> >>
>>> >> >
>>> >> > Stéphane
>>> >> >
>>> >> >>
>>> >> >>
>>> >> >> > There are a bunch of real bugs that we've found as a result of
>>> >> >> > having
>>> >> >> > these abstraction layers. Take, for example, dpms. Before this
>>> >> >> > patchset, dpms for fimd was being tracked separately in fimd
>>> >> >> > driver,
>>> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>>> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
>>> >> >> > updated, so the others were incorrect. There was also this weird
>>> >> >> > gymnastics that had to happen when dpms was changed in the encoder
>>> >> >> > since it had to walk up to the connector level to change its dpms
>>> >> >> > state. If fimd just directly implemented
>>> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>>> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>>> >> >> >
>>> >> >>
>>> >> >> That is a issue we should take care of by using the independent
>>> >> >> layer.
>>> >> >> Then, aren't you take care of that well with the re-factoring patch
>>> >> >> set? :)  It seems that you are outside real point.
>>> >> >>
>>> >> >> > Take a look at exynos_drm_encoder.c  in my tree
>>> >> >> >
>>> >> >> >
>>> >> >> >
>>> >> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>>> >> >> > what does it do that's useful to abstract? All that it does is
>>> >> >> > just
>>> >> >> > call display ops, it's completely useless. The same is true for
>>> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
>>> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>>> >> >> > served as a helper library, though.
>>> >> >> >
>>> >> >> >> The abstraction layer you mentioned also means a common spot.
>>> >> >> >> Another one, you patch also makes each sub driver have strongly
>>> >> >> >> dependency
>>> >> >> >> of drm framework. So how we can support existing backlight and
>>> >> >> >> lcd
>>> >> >> >> class
>>> >> >> >> based lcd panel drivers if the connector is implemented in each
>>> >> >> >> device
>>> >> >> >> driver later?  the drm header files should be included in
>>> >> >> >> drivers/video/backlight/xxx_lcd.c?
>>> >> >> >>
>>> >> >> >
>>> >> >> > drm_bridge or drm_panel seem like good candidates for this.
>>> >> >> >
>>> >> >>
>>> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if
>>> >> >> the
>>> >> >> drm_panel can be merged to mainline.
>>> >> >>
>>> >> >> >
>>> >> >> >> And, I will introduce a new framework to support existing lcd
>>> >> >> >> panel
>>> >> >> >> drivers
>>> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>>> >> >> >> framework is
>>> >> >> >> being tested internally. With this framework, encoder and
>>> >> >> >> connector
>>> >> >> >> will be
>>> >> >> >> created when lcd panel or display bus driver such as eDP is
>>> >> >> >> probed:
>>> >> >> >> it
>>> >> >> >> doesn’t really need to create encoder and connector in advance if
>>> >> >> >> lcd
>>> >> >> >> panel
>>> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>>> >> >> >> encoder
>>> >> >> >> and
>>> >> >> >> connector creation order, when last one is created, crtc and
>>> >> >> >> connector
>>> >> >> >> will
>>> >> >> >> be connected each other. And exynos_drm_display could be
>>> >> >> >> implemented
>>> >> >> >> in
>>> >> >> >> other frameworks if we have common structure for display device
>>> >> >> >> driver.
>>> >> >> >> And
>>> >> >> >> also the framework will support lvds driver according to Linux
>>> >> >> >> device
>>> >> >> >> driver
>>> >> >> >> model.
>>> >> >> >>
>>> >> >> >
>>> >> >> > I don't really follow what you're trying to do here, but I think
>>> >> >> > we
>>> >> >> > should be moving in the direction of fewer abstractions in the
>>> >> >> > exynos
>>> >> >> > driver, not more :)
>>> >> >> >
>>> >> >>
>>> >> >> Not abstraction layer, just a bridge for connecting crtc and its
>>> >> >> corresponding encoder/connector, and lvds regardless of creation
>>> >> >> order, and for connecting drm connector and other framework based
>>> >> >> display ops such as drm_panel later.
>>> >> >>
>>> >> >> > Sean
>>> >> >> >
>>> >> >> >
>>> >> >> >
>>> >> >> >> Thanks,
>>> >> >> >> Inki Dae
>>> >> >> >>
>>> >> >> >>> Sean
>>> >> >> >>>
>>> >> >> >>> >>>
>>> >> >> >>> >>> > And another one, the patch 6 passes manager object to
>>> >> >> >>> >>> > manager_ops,
>>> >> >> >>> and
>>> >> >> >>> >>> for
>>> >> >> >>> >>> > this, you made the manager object to be set to driver
>>> >> >> >>> >>> > data;
>>> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
>>> >> >> >>> >>> > reasonable.
>>> >> >> >>> Generally,
>>> >> >> >>> >>> > driver_data would point to device driver's context object.
>>> >> >> >>> >>> >
>>> >> >> >>> >>>
>>> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
>>> >> >> >>> >>> point.
>>> >> >> >>> >>> The
>>> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
>>> >> >> >>> >>> it
>>> >> >> >>> >>> needn't
>>> >> >> >>> >>> be set at all once things go through dpms.
>>> >> >> >>> >>>
>>> >> >> >>> >>
>>> >> >> >>> >> Generally, device drivers can call its own internal
>>> >> >> >>> >> functions,
>>> >> >> >>> >> and
>>> >> >> >>> >> they
>>> >> >> >>> will
>>> >> >> >>> >> call that functions with ctx. However, if you set manager to
>>> >> >> >>> driver_data
>>> >> >> >>> >> then that functions should be called with manager object and
>>> >> >> >>> >> also
>>> >> >> >>> internally
>>> >> >> >>> >> that functions should get ctx from the manager object. What
>>> >> >> >>> >> is
>>> >> >> >>> >> the
>>> >> >> >>> purpose
>>> >> >> >>> >> of manager? Do you think it's reasonable?
>>> >> >> >>> >>
>>> >> >> >>> >
>>> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
>>> >> >> >>> > implement
>>> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>>> >> >> >>> > manager
>>> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>>> >> >> >>> > pointer
>>> >> >> >>> > to
>>> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
>>> >> >> >>> > IMO,
>>> >> >> >>> > both of those solutions suck :)
>>> >> >> >>> >
>>> >> >> >>> > I'd much rather just set drvdata to the manager and call the
>>> >> >> >>> > hook
>>> >> >> >>> > directly. Like I said earlier, this is just a temporary step
>>> >> >> >>> > since
>>> >> >> >>> > we
>>> >> >> >>> > remove these pm ops later in the patch series.
>>> >> >> >>> >
>>> >> >> >>> > Sean
>>> >> >> >>> >
>>> >> >> >>> >
>>> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient
>>> >> >> >>> >> again.
>>> >> >> >>> >> So I
>>> >> >> >>> will fix
>>> >> >> >>> >> it.
>>> >> >> >>> >>
>>> >> >> >>> >> Thanks,
>>> >> >> >>> >> Inki Dae
>>> >> >> >>> >>
>>> >> >> >>> >>> Sean
>>> >> >> >>> >>>
>>> >> >> >>> >>>
>>> >> >> >>> >>> > Thanks,
>>> >> >> >>> >>> > Inki Dae
>>> >> >> >>> >>> >
>>> >> >> >>> >>
>>> >> >> >>
>>> >> >> > _______________________________________________
>>> >> >> > dri-devel mailing list
>>> >> >> > dri-devel@lists.freedesktop.org
>>> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> >> >> _______________________________________________
>>> >> >> dri-devel mailing list
>>> >> >> dri-devel@lists.freedesktop.org
>>> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> >> >
>>> >> >
>>> >> >
>>> >> > _______________________________________________
>>> >> > dri-devel mailing list
>>> >> > dri-devel@lists.freedesktop.org
>>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> >> >
>>> >
>>> >
>>> >
>>> > _______________________________________________
>>> > dri-devel mailing list
>>> > dri-devel@lists.freedesktop.org
>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> >
>>
>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  5:19                               ` Sean Paul
@ 2013-10-23  5:42                                 ` Inki Dae
  2013-10-23 12:20                                   ` Sean Paul
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-10-23  5:42 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Sean Paul <seanpaul@chromium.org>:
> On Wed, Oct 23, 2013 at 12:48 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>
>>>
>>>
>>> On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>>
>>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>> >
>>>> >
>>>> >
>>>> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>> >>
>>>> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>> >> >
>>>> >> >
>>>> >> >
>>>> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
>>>> >> > wrote:
>>>> >> >>
>>>> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>>>> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>>>> >> >> > wrote:
>>>> >> >> >>
>>>> >> >> >>
>>>> >> >> >>> -----Original Message-----
>>>> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>>>> >> >> >>> To: Inki Dae
>>>> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>> >> >> >>> manager/display/subdrv
>>>> >> >> >>>
>>>> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul
>>>> >> >> >>> <seanpaul@chromium.org>
>>>> >> >> >>> wrote:
>>>> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae
>>>> >> >> >>> > <inki.dae@samsung.com>
>>>> >> >> >>> > wrote:
>>>> >> >> >>> >>
>>>> >> >> >>> >>
>>>> >> >> >>> >>> -----Original Message-----
>>>> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>>> >> >> >>> >>> To: Inki Dae
>>>> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>> >> >> >>> >>> manager/display/subdrv
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>>>> >> >> >>> >>> <inki.dae@samsung.com>
>>>> >> >> >> wrote:
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>> >> -----Original Message-----
>>>> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>>> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>>> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>>>> >> >> >>> >>> >> marcheu@chromium.org;
>>>> >> >> >>> Sean
>>>> >> >> >>> >>> >> Paul
>>>> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>>>> >> >> >>> >>> >> manager/display/subdrv
>>>> >> >> >>> >>> >>
>>>> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
>>>> >> >> >>> >>> >> result
>>>> >> >> >>> >>> >> is
>>>> >> >> >>> that
>>>> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
>>>> >> >> >>> >>> >> and
>>>> >> >> >>> >>> >> encoder
>>>> >> >> >>> >>> >> functions can directly call into display callbacks. This
>>>> >> >> >>> >>> >> will
>>>> >> >> >>> >>> >> allow
>>>> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
>>>> >> >> >>> >>> >> mixer/hdmi
>>>> >> >> >>> >>> >> &
>>>> >> >> >>> fimd/dp
>>>> >> >> >>> >>> >> with common code.
>>>> >> >> >>> >>> >>
>>>> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>>> >> >> >>> >>> >> ---
>>>> >> >> >>> >>> >>
>>>> >> >> >>> >>> >> Changes in v2:
>>>> >> >> >>> >>> >>       - Pass display into display_ops instead of context
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
>>>> >> >> >>> >>> > object
>>>> >> >> >>> >>> > into
>>>> >> >> >>> >>> > display_ops and manager_ops.
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>>
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> So you've changed your mind from when you said the
>>>> >> >> >>> >>> following?
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>>>> >> >> >>> >>> >>> display->ops->xxx(display, ...);
>>>> >> >> >>> >>> >>>
>>>> >> >> >>> >>> >>> Agree.
>>>> >> >> >>> >>>
>>>> >> >> >>> >>
>>>> >> >> >>> >>
>>>> >> >> >>> >> True. Before that, My comment was to pass device object into
>>>> >> >> >>> display_ops and
>>>> >> >> >>> >> manager_ops, and then you said the good solution is to pass
>>>> >> >> >>> >> manager
>>>> >> >> >>> >> and
>>>> >> >> >>> >> display to each driver. At that time, I thought no matter how
>>>> >> >> >>> >> the
>>>> >> >> >>> callback
>>>> >> >> >>> >> is called if the framework doesn't call callbacks of each
>>>> >> >> >>> >> driver
>>>> >> >> >>> >> with
>>>> >> >> >>> ctx.
>>>> >> >> >>> >> So I agreed.
>>>> >> >> >>> >>
>>>> >> >> >>> >>
>>>> >> >> >>> >>> It would have been nice if you had changed your mind
>>>> >> >> >>> >>> *before* I
>>>> >> >> >>> >>> reworked everything. At any rate, I think it's still the
>>>> >> >> >>> >>> right
>>>> >> >> >>> >>> thing
>>>> >> >> >>> >>> to do.
>>>> >> >> >>> >>
>>>> >> >> >>> >> Really sorry about that. And I will add new patch for it so
>>>> >> >> >>> >> you
>>>> >> >> >>> >> don't
>>>> >> >> >>> need
>>>> >> >> >>> >> to concern about that.
>>>> >> >> >>> >>
>>>> >> >> >>> >>>
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>>>> >> >> >>> >>> > framework
>>>> >> >> >>> >>> based
>>>> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>>>> >> >> >>> >>> > display -
>>>> >> >> >>> it's
>>>> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>>>> >> >> >>> >>> > other
>>>> >> >> >>> framework
>>>> >> >> >>> >>> > based driver should include specific exynos drm header.
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
>>>> >> >> >>> >>> form,
>>>> >> >> >>> >>> we
>>>> >> >> >>> >>> don't need to worry about this. Furthermore, these ops
>>>> >> >> >>> >>> should
>>>> >> >> >>> >>> just
>>>> >> >> >>> >>> go
>>>> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>>>> >> >> >>> >>> anyways.
>>>> >> >> >>> >>>
>>>> >> >> >>> >>
>>>> >> >> >>> >> Can you assure the display_ops never implemented in other
>>>> >> >> >>> >> framework
>>>> >> >> >>> based
>>>> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities
>>>> >> >> >>> >> should
>>>> >> >> >>> >> be
>>>> >> >> >>> opened.
>>>> >> >> >>> >>
>>>> >> >> >>> >
>>>> >> >> >>> > I don't think we should let an RFC framework make the code
>>>> >> >> >>> > more
>>>> >> >> >>> > complicated for unclear benefit. By removing manager/display
>>>> >> >> >>> > entirely,
>>>> >> >> >>> > we can get rid of a *lot* of other code that is basically just
>>>> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>>> >> >> >>> >
>>>> >> >> >>>
>>>> >> >> >>> I hacked this up today to prove it out. Check out the top 5
>>>> >> >> >>> commits
>>>> >> >> >>> in
>>>> >> >> >>>
>>>> >> >> >>>
>>>> >> >> >>>
>>>> >> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>>> >> >> >>> staging.
>>>> >> >> >>> It removes exynos_drm_connector in favor of just implementing
>>>> >> >> >>> drm_connector directly. This same treatment should be done for
>>>> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
>>>> >> >> >>> to
>>>> >> >> >>> doing this.
>>>> >> >> >>>
>>>> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
>>>> >> >> >>> abstraction layer. Much nicer :)
>>>> >> >> >>>
>>>> >> >> >>
>>>> >> >> >> It seems that you implements connector in each device driver.
>>>> >> >> >> Can't
>>>> >> >> >> they be
>>>> >> >> >> combined as common spot, exynos_connector, again to avoid codes
>>>> >> >> >> from
>>>> >> >> >> duplicated? :)
>>>> >> >> >
>>>> >> >> > There's nothing of substance being duplicated.
>>>> >> >>
>>>> >> >> Not true. xxx_create_connector is duplicated.
>>>> >> >>
>>>> >> >> > In fact, by getting rid
>>>> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>>>> >> >> > really
>>>> >> >> > take a look at exynos_drm_connector, it's not doing anything
>>>> >> >> > useful.
>>>> >> >>
>>>> >> >> No, That is for each driver has no any dependency of drm framework.
>>>> >> >>
>>>> >> >> > All it does is translate the drm callbacks into display callbacks,
>>>> >> >> > so
>>>> >> >> > I think it's much better to just implement the drm callbacks
>>>> >> >> > directly.
>>>> >> >> >
>>>> >> >>
>>>> >> >> No, It has strongly dependency of drm framework. Assume that we
>>>> >> >> implemented the drm callbacks directly, and then some features are
>>>> >> >> added to drm framework, drm_connector side. At this time, we will
>>>> >> >> have
>>>> >> >> to take care of each device driver according to the change. That is
>>>> >> >> really not good. Why device drivers should have dependency of drm
>>>> >> >> framework? Just to reduce line counts?
>>>> >> >
>>>> >> >
>>>> >> >
>>>> >> > You seem to miss the point here and elsewhere in the discussion.
>>>> >> > drm/exynos is a drm driver, and as such it should use the drm
>>>> >> > framework,
>>>> >>
>>>> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
>>>> >> exynos drm framework, not drm framework directly. So I mean that
>>>> >> Exynos drm framework based drivers should include only Exynos drm
>>>> >> headers, _not drm header_ directly.
>>>> >
>>>> >
>>>> > Well, I think everyone sees that exynos is different. But my point still
>>>> > remains: why is the exynos driver in drm/ if it wants to use a different
>>>> > framework? Right now it is blocking work on a proper drm driver...
>>>> >
>>>>
>>>> Noooooo. It's not to use a different framework. It's to use a wrapper
>>>> instead.
>>>
>>>
>>> Ok, if you want to call it a wrapper, then what is the point of doing this
>>> wrapping given that it prevents a proper drm-style implementation?
>>>
>>
>> I already commented. That is for only Exynos drm framework has
>> dependency of drm framework directly, and Exynos drm based drivers
>> include only Exynos drm headers.
>>
>>>
>>>>
>>>> >
>>>> >>
>>>> >>
>>>> >> > especially if this reduces the line count and the code
>>>> >> > complexity (as is the case for this patch series). If you don't want
>>>> >> > to maintain a drm driver, it simply should be moved away from drm/,
>>>> >> > and it should be replaced by a real drm driver in my opinion.
>>>> >>
>>>> >> So those drivers should be in drm/exynos. Isn't that you really mean
>>>> >> those drivers should be driver/gpu/drm?
>>>> >
>>>> >
>>>> > I don't understand this sentence, sorry.
>>>>
>>>> Sorry, again, you mean Exynos drm based drivers should be in
>>>> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>>>>
>>> Is the exynos drm useful in its current shape at all? My recommendation
>>> would be to fork off a real drm driver in gpu/drm/exynos with the current
>>> code as a base.
>>>
>>
>> Yes as of now. of course, There could be a better way. However, I
>> don't want for Exynos drm based drivers have dependency of drm
>> framework directly.
>>
>
> Just to satisfy my curiosity, do you actually have something that uses
> these drivers outside of drm?
>

Never no.


> So I think we've reached somewhat of an impasse. I'd like to move the
> driver towards a proper drm driver (ie: no exynos
> framework/wrapper/whatever), you'd like to keep things separate. So
> should we create a new exynos driver drivers/drm/gpu/exynos5 to house
> the drm driver?

Did you check out other drm drivers using similar way? And If so, the
other drm framework based drivers should be moved? What is the problem
that Exynos drm based drivers include only Exynos drm headers, not drm
framework header directly? Is that really a big issue? I _cannot_
understand your behavior. Anyway, if there are any reasons that Exynos
drm based drivers should necessary include drm framework header
directly, I will agree it.

Thanks,
Inki Dae

>
> Sean
>
>
>> Thanks for your opinions.
>> Inki Dae
>>
>>> Stéphane
>>>
>>>
>>>>
>>>> Thanks,
>>>> Inki Dae
>>>>
>>>> >
>>>> > Stéphane
>>>> >
>>>> >
>>>> >>
>>>> >> If so, That would really be
>>>> >> horrible. :(
>>>> >>
>>>> >
>>>> >
>>>> >>
>>>> >> Please, know that only Exynos drm framework, _not device drivers_, has
>>>> >> all dependencies of drm framework, and also I know that other ARM
>>>> >> based drm drivers are using same way.
>>>> >>
>>>> >> Thanks,
>>>> >> Inki Dae
>>>> >>
>>>> >> >
>>>> >> > Stéphane
>>>> >> >
>>>> >> >>
>>>> >> >>
>>>> >> >> > There are a bunch of real bugs that we've found as a result of
>>>> >> >> > having
>>>> >> >> > these abstraction layers. Take, for example, dpms. Before this
>>>> >> >> > patchset, dpms for fimd was being tracked separately in fimd
>>>> >> >> > driver,
>>>> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>>>> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
>>>> >> >> > updated, so the others were incorrect. There was also this weird
>>>> >> >> > gymnastics that had to happen when dpms was changed in the encoder
>>>> >> >> > since it had to walk up to the connector level to change its dpms
>>>> >> >> > state. If fimd just directly implemented
>>>> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>>>> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>>>> >> >> >
>>>> >> >>
>>>> >> >> That is a issue we should take care of by using the independent
>>>> >> >> layer.
>>>> >> >> Then, aren't you take care of that well with the re-factoring patch
>>>> >> >> set? :)  It seems that you are outside real point.
>>>> >> >>
>>>> >> >> > Take a look at exynos_drm_encoder.c  in my tree
>>>> >> >> >
>>>> >> >> >
>>>> >> >> >
>>>> >> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>>>> >> >> > what does it do that's useful to abstract? All that it does is
>>>> >> >> > just
>>>> >> >> > call display ops, it's completely useless. The same is true for
>>>> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
>>>> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>>>> >> >> > served as a helper library, though.
>>>> >> >> >
>>>> >> >> >> The abstraction layer you mentioned also means a common spot.
>>>> >> >> >> Another one, you patch also makes each sub driver have strongly
>>>> >> >> >> dependency
>>>> >> >> >> of drm framework. So how we can support existing backlight and
>>>> >> >> >> lcd
>>>> >> >> >> class
>>>> >> >> >> based lcd panel drivers if the connector is implemented in each
>>>> >> >> >> device
>>>> >> >> >> driver later?  the drm header files should be included in
>>>> >> >> >> drivers/video/backlight/xxx_lcd.c?
>>>> >> >> >>
>>>> >> >> >
>>>> >> >> > drm_bridge or drm_panel seem like good candidates for this.
>>>> >> >> >
>>>> >> >>
>>>> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if
>>>> >> >> the
>>>> >> >> drm_panel can be merged to mainline.
>>>> >> >>
>>>> >> >> >
>>>> >> >> >> And, I will introduce a new framework to support existing lcd
>>>> >> >> >> panel
>>>> >> >> >> drivers
>>>> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>>>> >> >> >> framework is
>>>> >> >> >> being tested internally. With this framework, encoder and
>>>> >> >> >> connector
>>>> >> >> >> will be
>>>> >> >> >> created when lcd panel or display bus driver such as eDP is
>>>> >> >> >> probed:
>>>> >> >> >> it
>>>> >> >> >> doesn’t really need to create encoder and connector in advance if
>>>> >> >> >> lcd
>>>> >> >> >> panel
>>>> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>>>> >> >> >> encoder
>>>> >> >> >> and
>>>> >> >> >> connector creation order, when last one is created, crtc and
>>>> >> >> >> connector
>>>> >> >> >> will
>>>> >> >> >> be connected each other. And exynos_drm_display could be
>>>> >> >> >> implemented
>>>> >> >> >> in
>>>> >> >> >> other frameworks if we have common structure for display device
>>>> >> >> >> driver.
>>>> >> >> >> And
>>>> >> >> >> also the framework will support lvds driver according to Linux
>>>> >> >> >> device
>>>> >> >> >> driver
>>>> >> >> >> model.
>>>> >> >> >>
>>>> >> >> >
>>>> >> >> > I don't really follow what you're trying to do here, but I think
>>>> >> >> > we
>>>> >> >> > should be moving in the direction of fewer abstractions in the
>>>> >> >> > exynos
>>>> >> >> > driver, not more :)
>>>> >> >> >
>>>> >> >>
>>>> >> >> Not abstraction layer, just a bridge for connecting crtc and its
>>>> >> >> corresponding encoder/connector, and lvds regardless of creation
>>>> >> >> order, and for connecting drm connector and other framework based
>>>> >> >> display ops such as drm_panel later.
>>>> >> >>
>>>> >> >> > Sean
>>>> >> >> >
>>>> >> >> >
>>>> >> >> >
>>>> >> >> >> Thanks,
>>>> >> >> >> Inki Dae
>>>> >> >> >>
>>>> >> >> >>> Sean
>>>> >> >> >>>
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> > And another one, the patch 6 passes manager object to
>>>> >> >> >>> >>> > manager_ops,
>>>> >> >> >>> and
>>>> >> >> >>> >>> for
>>>> >> >> >>> >>> > this, you made the manager object to be set to driver
>>>> >> >> >>> >>> > data;
>>>> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
>>>> >> >> >>> >>> > reasonable.
>>>> >> >> >>> Generally,
>>>> >> >> >>> >>> > driver_data would point to device driver's context object.
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
>>>> >> >> >>> >>> point.
>>>> >> >> >>> >>> The
>>>> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
>>>> >> >> >>> >>> it
>>>> >> >> >>> >>> needn't
>>>> >> >> >>> >>> be set at all once things go through dpms.
>>>> >> >> >>> >>>
>>>> >> >> >>> >>
>>>> >> >> >>> >> Generally, device drivers can call its own internal
>>>> >> >> >>> >> functions,
>>>> >> >> >>> >> and
>>>> >> >> >>> >> they
>>>> >> >> >>> will
>>>> >> >> >>> >> call that functions with ctx. However, if you set manager to
>>>> >> >> >>> driver_data
>>>> >> >> >>> >> then that functions should be called with manager object and
>>>> >> >> >>> >> also
>>>> >> >> >>> internally
>>>> >> >> >>> >> that functions should get ctx from the manager object. What
>>>> >> >> >>> >> is
>>>> >> >> >>> >> the
>>>> >> >> >>> purpose
>>>> >> >> >>> >> of manager? Do you think it's reasonable?
>>>> >> >> >>> >>
>>>> >> >> >>> >
>>>> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
>>>> >> >> >>> > implement
>>>> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>>>> >> >> >>> > manager
>>>> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>>> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>>>> >> >> >>> > pointer
>>>> >> >> >>> > to
>>>> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
>>>> >> >> >>> > IMO,
>>>> >> >> >>> > both of those solutions suck :)
>>>> >> >> >>> >
>>>> >> >> >>> > I'd much rather just set drvdata to the manager and call the
>>>> >> >> >>> > hook
>>>> >> >> >>> > directly. Like I said earlier, this is just a temporary step
>>>> >> >> >>> > since
>>>> >> >> >>> > we
>>>> >> >> >>> > remove these pm ops later in the patch series.
>>>> >> >> >>> >
>>>> >> >> >>> > Sean
>>>> >> >> >>> >
>>>> >> >> >>> >
>>>> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient
>>>> >> >> >>> >> again.
>>>> >> >> >>> >> So I
>>>> >> >> >>> will fix
>>>> >> >> >>> >> it.
>>>> >> >> >>> >>
>>>> >> >> >>> >> Thanks,
>>>> >> >> >>> >> Inki Dae
>>>> >> >> >>> >>
>>>> >> >> >>> >>> Sean
>>>> >> >> >>> >>>
>>>> >> >> >>> >>>
>>>> >> >> >>> >>> > Thanks,
>>>> >> >> >>> >>> > Inki Dae
>>>> >> >> >>> >>> >
>>>> >> >> >>> >>
>>>> >> >> >>
>>>> >> >> > _______________________________________________
>>>> >> >> > dri-devel mailing list
>>>> >> >> > dri-devel@lists.freedesktop.org
>>>> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>> >> >> _______________________________________________
>>>> >> >> dri-devel mailing list
>>>> >> >> dri-devel@lists.freedesktop.org
>>>> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>> >> >
>>>> >> >
>>>> >> >
>>>> >> > _______________________________________________
>>>> >> > dri-devel mailing list
>>>> >> > dri-devel@lists.freedesktop.org
>>>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>> >> >
>>>> >
>>>> >
>>>> >
>>>> > _______________________________________________
>>>> > dri-devel mailing list
>>>> > dri-devel@lists.freedesktop.org
>>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>> >
>>>
>>>
>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23  5:42                                 ` Inki Dae
@ 2013-10-23 12:20                                   ` Sean Paul
  2013-10-23 13:18                                     ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-23 12:20 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 1:42 AM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/10/23 Sean Paul <seanpaul@chromium.org>:
>> On Wed, Oct 23, 2013 at 12:48 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>
>>>>
>>>>
>>>> On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>>>
>>>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>> >
>>>>> >
>>>>> >
>>>>> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>>> >>
>>>>> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>> >> >
>>>>> >> >
>>>>> >> >
>>>>> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
>>>>> >> > wrote:
>>>>> >> >>
>>>>> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>>>>> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>>>>> >> >> > wrote:
>>>>> >> >> >>
>>>>> >> >> >>
>>>>> >> >> >>> -----Original Message-----
>>>>> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>>>>> >> >> >>> To: Inki Dae
>>>>> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>>> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>>> >> >> >>> manager/display/subdrv
>>>>> >> >> >>>
>>>>> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul
>>>>> >> >> >>> <seanpaul@chromium.org>
>>>>> >> >> >>> wrote:
>>>>> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae
>>>>> >> >> >>> > <inki.dae@samsung.com>
>>>>> >> >> >>> > wrote:
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>> -----Original Message-----
>>>>> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>>>> >> >> >>> >>> To: Inki Dae
>>>>> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>>> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>>> >> >> >>> >>> manager/display/subdrv
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>>>>> >> >> >>> >>> <inki.dae@samsung.com>
>>>>> >> >> >> wrote:
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>> >> -----Original Message-----
>>>>> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>>>> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>>>> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>>>>> >> >> >>> >>> >> marcheu@chromium.org;
>>>>> >> >> >>> Sean
>>>>> >> >> >>> >>> >> Paul
>>>>> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>>>>> >> >> >>> >>> >> manager/display/subdrv
>>>>> >> >> >>> >>> >>
>>>>> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
>>>>> >> >> >>> >>> >> result
>>>>> >> >> >>> >>> >> is
>>>>> >> >> >>> that
>>>>> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
>>>>> >> >> >>> >>> >> and
>>>>> >> >> >>> >>> >> encoder
>>>>> >> >> >>> >>> >> functions can directly call into display callbacks. This
>>>>> >> >> >>> >>> >> will
>>>>> >> >> >>> >>> >> allow
>>>>> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
>>>>> >> >> >>> >>> >> mixer/hdmi
>>>>> >> >> >>> >>> >> &
>>>>> >> >> >>> fimd/dp
>>>>> >> >> >>> >>> >> with common code.
>>>>> >> >> >>> >>> >>
>>>>> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>>>> >> >> >>> >>> >> ---
>>>>> >> >> >>> >>> >>
>>>>> >> >> >>> >>> >> Changes in v2:
>>>>> >> >> >>> >>> >>       - Pass display into display_ops instead of context
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
>>>>> >> >> >>> >>> > object
>>>>> >> >> >>> >>> > into
>>>>> >> >> >>> >>> > display_ops and manager_ops.
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> So you've changed your mind from when you said the
>>>>> >> >> >>> >>> following?
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>>>>> >> >> >>> >>> >>> display->ops->xxx(display, ...);
>>>>> >> >> >>> >>> >>>
>>>>> >> >> >>> >>> >>> Agree.
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >> True. Before that, My comment was to pass device object into
>>>>> >> >> >>> display_ops and
>>>>> >> >> >>> >> manager_ops, and then you said the good solution is to pass
>>>>> >> >> >>> >> manager
>>>>> >> >> >>> >> and
>>>>> >> >> >>> >> display to each driver. At that time, I thought no matter how
>>>>> >> >> >>> >> the
>>>>> >> >> >>> callback
>>>>> >> >> >>> >> is called if the framework doesn't call callbacks of each
>>>>> >> >> >>> >> driver
>>>>> >> >> >>> >> with
>>>>> >> >> >>> ctx.
>>>>> >> >> >>> >> So I agreed.
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>> It would have been nice if you had changed your mind
>>>>> >> >> >>> >>> *before* I
>>>>> >> >> >>> >>> reworked everything. At any rate, I think it's still the
>>>>> >> >> >>> >>> right
>>>>> >> >> >>> >>> thing
>>>>> >> >> >>> >>> to do.
>>>>> >> >> >>> >>
>>>>> >> >> >>> >> Really sorry about that. And I will add new patch for it so
>>>>> >> >> >>> >> you
>>>>> >> >> >>> >> don't
>>>>> >> >> >>> need
>>>>> >> >> >>> >> to concern about that.
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>>>>> >> >> >>> >>> > framework
>>>>> >> >> >>> >>> based
>>>>> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>>>>> >> >> >>> >>> > display -
>>>>> >> >> >>> it's
>>>>> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>>>>> >> >> >>> >>> > other
>>>>> >> >> >>> framework
>>>>> >> >> >>> >>> > based driver should include specific exynos drm header.
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
>>>>> >> >> >>> >>> form,
>>>>> >> >> >>> >>> we
>>>>> >> >> >>> >>> don't need to worry about this. Furthermore, these ops
>>>>> >> >> >>> >>> should
>>>>> >> >> >>> >>> just
>>>>> >> >> >>> >>> go
>>>>> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>>>>> >> >> >>> >>> anyways.
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >> Can you assure the display_ops never implemented in other
>>>>> >> >> >>> >> framework
>>>>> >> >> >>> based
>>>>> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities
>>>>> >> >> >>> >> should
>>>>> >> >> >>> >> be
>>>>> >> >> >>> opened.
>>>>> >> >> >>> >>
>>>>> >> >> >>> >
>>>>> >> >> >>> > I don't think we should let an RFC framework make the code
>>>>> >> >> >>> > more
>>>>> >> >> >>> > complicated for unclear benefit. By removing manager/display
>>>>> >> >> >>> > entirely,
>>>>> >> >> >>> > we can get rid of a *lot* of other code that is basically just
>>>>> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>>>> >> >> >>> >
>>>>> >> >> >>>
>>>>> >> >> >>> I hacked this up today to prove it out. Check out the top 5
>>>>> >> >> >>> commits
>>>>> >> >> >>> in
>>>>> >> >> >>>
>>>>> >> >> >>>
>>>>> >> >> >>>
>>>>> >> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>>>> >> >> >>> staging.
>>>>> >> >> >>> It removes exynos_drm_connector in favor of just implementing
>>>>> >> >> >>> drm_connector directly. This same treatment should be done for
>>>>> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
>>>>> >> >> >>> to
>>>>> >> >> >>> doing this.
>>>>> >> >> >>>
>>>>> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
>>>>> >> >> >>> abstraction layer. Much nicer :)
>>>>> >> >> >>>
>>>>> >> >> >>
>>>>> >> >> >> It seems that you implements connector in each device driver.
>>>>> >> >> >> Can't
>>>>> >> >> >> they be
>>>>> >> >> >> combined as common spot, exynos_connector, again to avoid codes
>>>>> >> >> >> from
>>>>> >> >> >> duplicated? :)
>>>>> >> >> >
>>>>> >> >> > There's nothing of substance being duplicated.
>>>>> >> >>
>>>>> >> >> Not true. xxx_create_connector is duplicated.
>>>>> >> >>
>>>>> >> >> > In fact, by getting rid
>>>>> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>>>>> >> >> > really
>>>>> >> >> > take a look at exynos_drm_connector, it's not doing anything
>>>>> >> >> > useful.
>>>>> >> >>
>>>>> >> >> No, That is for each driver has no any dependency of drm framework.
>>>>> >> >>
>>>>> >> >> > All it does is translate the drm callbacks into display callbacks,
>>>>> >> >> > so
>>>>> >> >> > I think it's much better to just implement the drm callbacks
>>>>> >> >> > directly.
>>>>> >> >> >
>>>>> >> >>
>>>>> >> >> No, It has strongly dependency of drm framework. Assume that we
>>>>> >> >> implemented the drm callbacks directly, and then some features are
>>>>> >> >> added to drm framework, drm_connector side. At this time, we will
>>>>> >> >> have
>>>>> >> >> to take care of each device driver according to the change. That is
>>>>> >> >> really not good. Why device drivers should have dependency of drm
>>>>> >> >> framework? Just to reduce line counts?
>>>>> >> >
>>>>> >> >
>>>>> >> >
>>>>> >> > You seem to miss the point here and elsewhere in the discussion.
>>>>> >> > drm/exynos is a drm driver, and as such it should use the drm
>>>>> >> > framework,
>>>>> >>
>>>>> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
>>>>> >> exynos drm framework, not drm framework directly. So I mean that
>>>>> >> Exynos drm framework based drivers should include only Exynos drm
>>>>> >> headers, _not drm header_ directly.
>>>>> >
>>>>> >
>>>>> > Well, I think everyone sees that exynos is different. But my point still
>>>>> > remains: why is the exynos driver in drm/ if it wants to use a different
>>>>> > framework? Right now it is blocking work on a proper drm driver...
>>>>> >
>>>>>
>>>>> Noooooo. It's not to use a different framework. It's to use a wrapper
>>>>> instead.
>>>>
>>>>
>>>> Ok, if you want to call it a wrapper, then what is the point of doing this
>>>> wrapping given that it prevents a proper drm-style implementation?
>>>>
>>>
>>> I already commented. That is for only Exynos drm framework has
>>> dependency of drm framework directly, and Exynos drm based drivers
>>> include only Exynos drm headers.
>>>
>>>>
>>>>>
>>>>> >
>>>>> >>
>>>>> >>
>>>>> >> > especially if this reduces the line count and the code
>>>>> >> > complexity (as is the case for this patch series). If you don't want
>>>>> >> > to maintain a drm driver, it simply should be moved away from drm/,
>>>>> >> > and it should be replaced by a real drm driver in my opinion.
>>>>> >>
>>>>> >> So those drivers should be in drm/exynos. Isn't that you really mean
>>>>> >> those drivers should be driver/gpu/drm?
>>>>> >
>>>>> >
>>>>> > I don't understand this sentence, sorry.
>>>>>
>>>>> Sorry, again, you mean Exynos drm based drivers should be in
>>>>> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>>>>>
>>>> Is the exynos drm useful in its current shape at all? My recommendation
>>>> would be to fork off a real drm driver in gpu/drm/exynos with the current
>>>> code as a base.
>>>>
>>>
>>> Yes as of now. of course, There could be a better way. However, I
>>> don't want for Exynos drm based drivers have dependency of drm
>>> framework directly.
>>>
>>
>> Just to satisfy my curiosity, do you actually have something that uses
>> these drivers outside of drm?
>>
>
> Never no.
>
>
>> So I think we've reached somewhat of an impasse. I'd like to move the
>> driver towards a proper drm driver (ie: no exynos
>> framework/wrapper/whatever), you'd like to keep things separate. So
>> should we create a new exynos driver drivers/drm/gpu/exynos5 to house
>> the drm driver?
>
> Did you check out other drm drivers using similar way? And If so, the
> other drm framework based drivers should be moved?

No, I haven't looked at other ARM drivers. It's besides the point,
really, that's not a compelling argument. For the exynos driver, in
particular, it doesn't make sense to wrapping everything in
exynos_drm_*

> What is the problem
> that Exynos drm based drivers include only Exynos drm headers, not drm
> framework header directly? Is that really a big issue? I _cannot_
> understand your behavior.

The problem is that it makes things unnecessarily complex for no benefit.

For example, that you wanted to implement
connector_funcs->set_property() just in the hdmi driver. This requires
that you add a new display_op in exynos_drm_drv.h, then you implement
the connector_func callback in exynos_drm_connector to check if the op
is implemented then call it, and then you implement the set_property
hook in the hdmi driver. If you didn't have the wrapper, you just
implement the hook in the hdmi driver.

Sean


> Anyway, if there are any reasons that Exynos
> drm based drivers should necessary include drm framework header
> directly, I will agree it.
>
> Thanks,
> Inki Dae
>
>>
>> Sean
>>
>>
>>> Thanks for your opinions.
>>> Inki Dae
>>>
>>>> Stéphane
>>>>
>>>>
>>>>>
>>>>> Thanks,
>>>>> Inki Dae
>>>>>
>>>>> >
>>>>> > Stéphane
>>>>> >
>>>>> >
>>>>> >>
>>>>> >> If so, That would really be
>>>>> >> horrible. :(
>>>>> >>
>>>>> >
>>>>> >
>>>>> >>
>>>>> >> Please, know that only Exynos drm framework, _not device drivers_, has
>>>>> >> all dependencies of drm framework, and also I know that other ARM
>>>>> >> based drm drivers are using same way.
>>>>> >>
>>>>> >> Thanks,
>>>>> >> Inki Dae
>>>>> >>
>>>>> >> >
>>>>> >> > Stéphane
>>>>> >> >
>>>>> >> >>
>>>>> >> >>
>>>>> >> >> > There are a bunch of real bugs that we've found as a result of
>>>>> >> >> > having
>>>>> >> >> > these abstraction layers. Take, for example, dpms. Before this
>>>>> >> >> > patchset, dpms for fimd was being tracked separately in fimd
>>>>> >> >> > driver,
>>>>> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>>>>> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
>>>>> >> >> > updated, so the others were incorrect. There was also this weird
>>>>> >> >> > gymnastics that had to happen when dpms was changed in the encoder
>>>>> >> >> > since it had to walk up to the connector level to change its dpms
>>>>> >> >> > state. If fimd just directly implemented
>>>>> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>>>>> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>>>>> >> >> >
>>>>> >> >>
>>>>> >> >> That is a issue we should take care of by using the independent
>>>>> >> >> layer.
>>>>> >> >> Then, aren't you take care of that well with the re-factoring patch
>>>>> >> >> set? :)  It seems that you are outside real point.
>>>>> >> >>
>>>>> >> >> > Take a look at exynos_drm_encoder.c  in my tree
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>>>>> >> >> > what does it do that's useful to abstract? All that it does is
>>>>> >> >> > just
>>>>> >> >> > call display ops, it's completely useless. The same is true for
>>>>> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
>>>>> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>>>>> >> >> > served as a helper library, though.
>>>>> >> >> >
>>>>> >> >> >> The abstraction layer you mentioned also means a common spot.
>>>>> >> >> >> Another one, you patch also makes each sub driver have strongly
>>>>> >> >> >> dependency
>>>>> >> >> >> of drm framework. So how we can support existing backlight and
>>>>> >> >> >> lcd
>>>>> >> >> >> class
>>>>> >> >> >> based lcd panel drivers if the connector is implemented in each
>>>>> >> >> >> device
>>>>> >> >> >> driver later?  the drm header files should be included in
>>>>> >> >> >> drivers/video/backlight/xxx_lcd.c?
>>>>> >> >> >>
>>>>> >> >> >
>>>>> >> >> > drm_bridge or drm_panel seem like good candidates for this.
>>>>> >> >> >
>>>>> >> >>
>>>>> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if
>>>>> >> >> the
>>>>> >> >> drm_panel can be merged to mainline.
>>>>> >> >>
>>>>> >> >> >
>>>>> >> >> >> And, I will introduce a new framework to support existing lcd
>>>>> >> >> >> panel
>>>>> >> >> >> drivers
>>>>> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>>>>> >> >> >> framework is
>>>>> >> >> >> being tested internally. With this framework, encoder and
>>>>> >> >> >> connector
>>>>> >> >> >> will be
>>>>> >> >> >> created when lcd panel or display bus driver such as eDP is
>>>>> >> >> >> probed:
>>>>> >> >> >> it
>>>>> >> >> >> doesn’t really need to create encoder and connector in advance if
>>>>> >> >> >> lcd
>>>>> >> >> >> panel
>>>>> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>>>>> >> >> >> encoder
>>>>> >> >> >> and
>>>>> >> >> >> connector creation order, when last one is created, crtc and
>>>>> >> >> >> connector
>>>>> >> >> >> will
>>>>> >> >> >> be connected each other. And exynos_drm_display could be
>>>>> >> >> >> implemented
>>>>> >> >> >> in
>>>>> >> >> >> other frameworks if we have common structure for display device
>>>>> >> >> >> driver.
>>>>> >> >> >> And
>>>>> >> >> >> also the framework will support lvds driver according to Linux
>>>>> >> >> >> device
>>>>> >> >> >> driver
>>>>> >> >> >> model.
>>>>> >> >> >>
>>>>> >> >> >
>>>>> >> >> > I don't really follow what you're trying to do here, but I think
>>>>> >> >> > we
>>>>> >> >> > should be moving in the direction of fewer abstractions in the
>>>>> >> >> > exynos
>>>>> >> >> > driver, not more :)
>>>>> >> >> >
>>>>> >> >>
>>>>> >> >> Not abstraction layer, just a bridge for connecting crtc and its
>>>>> >> >> corresponding encoder/connector, and lvds regardless of creation
>>>>> >> >> order, and for connecting drm connector and other framework based
>>>>> >> >> display ops such as drm_panel later.
>>>>> >> >>
>>>>> >> >> > Sean
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> >
>>>>> >> >> >> Thanks,
>>>>> >> >> >> Inki Dae
>>>>> >> >> >>
>>>>> >> >> >>> Sean
>>>>> >> >> >>>
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> > And another one, the patch 6 passes manager object to
>>>>> >> >> >>> >>> > manager_ops,
>>>>> >> >> >>> and
>>>>> >> >> >>> >>> for
>>>>> >> >> >>> >>> > this, you made the manager object to be set to driver
>>>>> >> >> >>> >>> > data;
>>>>> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
>>>>> >> >> >>> >>> > reasonable.
>>>>> >> >> >>> Generally,
>>>>> >> >> >>> >>> > driver_data would point to device driver's context object.
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
>>>>> >> >> >>> >>> point.
>>>>> >> >> >>> >>> The
>>>>> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
>>>>> >> >> >>> >>> it
>>>>> >> >> >>> >>> needn't
>>>>> >> >> >>> >>> be set at all once things go through dpms.
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>
>>>>> >> >> >>> >> Generally, device drivers can call its own internal
>>>>> >> >> >>> >> functions,
>>>>> >> >> >>> >> and
>>>>> >> >> >>> >> they
>>>>> >> >> >>> will
>>>>> >> >> >>> >> call that functions with ctx. However, if you set manager to
>>>>> >> >> >>> driver_data
>>>>> >> >> >>> >> then that functions should be called with manager object and
>>>>> >> >> >>> >> also
>>>>> >> >> >>> internally
>>>>> >> >> >>> >> that functions should get ctx from the manager object. What
>>>>> >> >> >>> >> is
>>>>> >> >> >>> >> the
>>>>> >> >> >>> purpose
>>>>> >> >> >>> >> of manager? Do you think it's reasonable?
>>>>> >> >> >>> >>
>>>>> >> >> >>> >
>>>>> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
>>>>> >> >> >>> > implement
>>>>> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>>>>> >> >> >>> > manager
>>>>> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>>>> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>>>>> >> >> >>> > pointer
>>>>> >> >> >>> > to
>>>>> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
>>>>> >> >> >>> > IMO,
>>>>> >> >> >>> > both of those solutions suck :)
>>>>> >> >> >>> >
>>>>> >> >> >>> > I'd much rather just set drvdata to the manager and call the
>>>>> >> >> >>> > hook
>>>>> >> >> >>> > directly. Like I said earlier, this is just a temporary step
>>>>> >> >> >>> > since
>>>>> >> >> >>> > we
>>>>> >> >> >>> > remove these pm ops later in the patch series.
>>>>> >> >> >>> >
>>>>> >> >> >>> > Sean
>>>>> >> >> >>> >
>>>>> >> >> >>> >
>>>>> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient
>>>>> >> >> >>> >> again.
>>>>> >> >> >>> >> So I
>>>>> >> >> >>> will fix
>>>>> >> >> >>> >> it.
>>>>> >> >> >>> >>
>>>>> >> >> >>> >> Thanks,
>>>>> >> >> >>> >> Inki Dae
>>>>> >> >> >>> >>
>>>>> >> >> >>> >>> Sean
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>>
>>>>> >> >> >>> >>> > Thanks,
>>>>> >> >> >>> >>> > Inki Dae
>>>>> >> >> >>> >>> >
>>>>> >> >> >>> >>
>>>>> >> >> >>
>>>>> >> >> > _______________________________________________
>>>>> >> >> > dri-devel mailing list
>>>>> >> >> > dri-devel@lists.freedesktop.org
>>>>> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>> >> >> _______________________________________________
>>>>> >> >> dri-devel mailing list
>>>>> >> >> dri-devel@lists.freedesktop.org
>>>>> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>> >> >
>>>>> >> >
>>>>> >> >
>>>>> >> > _______________________________________________
>>>>> >> > dri-devel mailing list
>>>>> >> > dri-devel@lists.freedesktop.org
>>>>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>> >> >
>>>>> >
>>>>> >
>>>>> >
>>>>> > _______________________________________________
>>>>> > dri-devel mailing list
>>>>> > dri-devel@lists.freedesktop.org
>>>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>> >
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 12:20                                   ` Sean Paul
@ 2013-10-23 13:18                                     ` Inki Dae
  2013-10-23 14:29                                       ` Dave Airlie
  2013-10-23 14:51                                       ` Rob Clark
  0 siblings, 2 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-23 13:18 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Sean Paul <seanpaul@chromium.org>:
> On Wed, Oct 23, 2013 at 1:42 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> 2013/10/23 Sean Paul <seanpaul@chromium.org>:
>>> On Wed, Oct 23, 2013 at 12:48 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>>
>>>>>
>>>>>
>>>>> On Tue, Oct 22, 2013 at 9:15 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>>>>
>>>>>> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>>> >
>>>>>> >
>>>>>> >
>>>>>> > On Tue, Oct 22, 2013 at 8:38 PM, Inki Dae <inki.dae@samsung.com> wrote:
>>>>>> >>
>>>>>> >> 2013/10/23 Stéphane Marchesin <stephane.marchesin@gmail.com>:
>>>>>> >> >
>>>>>> >> >
>>>>>> >> >
>>>>>> >> > On Tue, Oct 22, 2013 at 7:28 PM, Inki Dae <inki.dae@samsung.com>
>>>>>> >> > wrote:
>>>>>> >> >>
>>>>>> >> >> 2013/10/22 Sean Paul <seanpaul@chromium.org>:
>>>>>> >> >> > On Tue, Oct 22, 2013 at 1:30 AM, Inki Dae <inki.dae@samsung.com>
>>>>>> >> >> > wrote:
>>>>>> >> >> >>
>>>>>> >> >> >>
>>>>>> >> >> >>> -----Original Message-----
>>>>>> >> >> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>>> >> >> >>> Sent: Tuesday, October 22, 2013 6:18 AM
>>>>>> >> >> >>> To: Inki Dae
>>>>>> >> >> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>>>> >> >> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>>>> >> >> >>> manager/display/subdrv
>>>>>> >> >> >>>
>>>>>> >> >> >>> On Mon, Oct 21, 2013 at 10:46 AM, Sean Paul
>>>>>> >> >> >>> <seanpaul@chromium.org>
>>>>>> >> >> >>> wrote:
>>>>>> >> >> >>> > On Thu, Oct 17, 2013 at 10:31 PM, Inki Dae
>>>>>> >> >> >>> > <inki.dae@samsung.com>
>>>>>> >> >> >>> > wrote:
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>> -----Original Message-----
>>>>>> >> >> >>> >>> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>>> >> >> >>> >>> Sent: Thursday, October 17, 2013 11:37 PM
>>>>>> >> >> >>> >>> To: Inki Dae
>>>>>> >> >> >>> >>> Cc: dri-devel; Dave Airlie; Tomasz Figa; Stéphane Marchesin
>>>>>> >> >> >>> >>> Subject: Re: [PATCH v2 12/26] drm/exynos: Split
>>>>>> >> >> >>> >>> manager/display/subdrv
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> On Thu, Oct 17, 2013 at 4:21 AM, Inki Dae
>>>>>> >> >> >>> >>> <inki.dae@samsung.com>
>>>>>> >> >> >> wrote:
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>> >> -----Original Message-----
>>>>>> >> >> >>> >>> >> From: Sean Paul [mailto:seanpaul@chromium.org]
>>>>>> >> >> >>> >>> >> Sent: Thursday, October 17, 2013 4:27 AM
>>>>>> >> >> >>> >>> >> To: dri-devel@lists.freedesktop.org; inki.dae@samsung.com
>>>>>> >> >> >>> >>> >> Cc: airlied@linux.ie; tomasz.figa@gmail.com;
>>>>>> >> >> >>> >>> >> marcheu@chromium.org;
>>>>>> >> >> >>> Sean
>>>>>> >> >> >>> >>> >> Paul
>>>>>> >> >> >>> >>> >> Subject: [PATCH v2 12/26] drm/exynos: Split
>>>>>> >> >> >>> >>> >> manager/display/subdrv
>>>>>> >> >> >>> >>> >>
>>>>>> >> >> >>> >>> >> This patch splits display and manager from subdrv. The
>>>>>> >> >> >>> >>> >> result
>>>>>> >> >> >>> >>> >> is
>>>>>> >> >> >>> that
>>>>>> >> >> >>> >>> >> crtc functions can directly call into manager callbacks
>>>>>> >> >> >>> >>> >> and
>>>>>> >> >> >>> >>> >> encoder
>>>>>> >> >> >>> >>> >> functions can directly call into display callbacks. This
>>>>>> >> >> >>> >>> >> will
>>>>>> >> >> >>> >>> >> allow
>>>>>> >> >> >>> >>> >> us to remove the exynos_drm_hdmi shim and support
>>>>>> >> >> >>> >>> >> mixer/hdmi
>>>>>> >> >> >>> >>> >> &
>>>>>> >> >> >>> fimd/dp
>>>>>> >> >> >>> >>> >> with common code.
>>>>>> >> >> >>> >>> >>
>>>>>> >> >> >>> >>> >> Signed-off-by: Sean Paul <seanpaul@chromium.org>
>>>>>> >> >> >>> >>> >> ---
>>>>>> >> >> >>> >>> >>
>>>>>> >> >> >>> >>> >> Changes in v2:
>>>>>> >> >> >>> >>> >>       - Pass display into display_ops instead of context
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>> > Sorry but it seems like more reasonable to pass device
>>>>>> >> >> >>> >>> > object
>>>>>> >> >> >>> >>> > into
>>>>>> >> >> >>> >>> > display_ops and manager_ops.
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> So you've changed your mind from when you said the
>>>>>> >> >> >>> >>> following?
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> >>> manager->ops->xxx(manager, ...);
>>>>>> >> >> >>> >>> >>> display->ops->xxx(display, ...);
>>>>>> >> >> >>> >>> >>>
>>>>>> >> >> >>> >>> >>> Agree.
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >> True. Before that, My comment was to pass device object into
>>>>>> >> >> >>> display_ops and
>>>>>> >> >> >>> >> manager_ops, and then you said the good solution is to pass
>>>>>> >> >> >>> >> manager
>>>>>> >> >> >>> >> and
>>>>>> >> >> >>> >> display to each driver. At that time, I thought no matter how
>>>>>> >> >> >>> >> the
>>>>>> >> >> >>> callback
>>>>>> >> >> >>> >> is called if the framework doesn't call callbacks of each
>>>>>> >> >> >>> >> driver
>>>>>> >> >> >>> >> with
>>>>>> >> >> >>> ctx.
>>>>>> >> >> >>> >> So I agreed.
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>> It would have been nice if you had changed your mind
>>>>>> >> >> >>> >>> *before* I
>>>>>> >> >> >>> >>> reworked everything. At any rate, I think it's still the
>>>>>> >> >> >>> >>> right
>>>>>> >> >> >>> >>> thing
>>>>>> >> >> >>> >>> to do.
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >> Really sorry about that. And I will add new patch for it so
>>>>>> >> >> >>> >> you
>>>>>> >> >> >>> >> don't
>>>>>> >> >> >>> need
>>>>>> >> >> >>> >> to concern about that.
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> > I'm not sure but display_ops could be implemented in other
>>>>>> >> >> >>> >>> > framework
>>>>>> >> >> >>> >>> based
>>>>>> >> >> >>> >>> > driver such as CDF based lcd panel driver. So if you pass
>>>>>> >> >> >>> >>> > display -
>>>>>> >> >> >>> it's
>>>>>> >> >> >>> >>> > specific to exynos drm framework - into display_ops, the
>>>>>> >> >> >>> >>> > other
>>>>>> >> >> >>> framework
>>>>>> >> >> >>> >>> > based driver should include specific exynos drm header.
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> AFAIK, CDF will not land in its current separate-from-drm
>>>>>> >> >> >>> >>> form,
>>>>>> >> >> >>> >>> we
>>>>>> >> >> >>> >>> don't need to worry about this. Furthermore, these ops
>>>>>> >> >> >>> >>> should
>>>>>> >> >> >>> >>> just
>>>>>> >> >> >>> >>> go
>>>>>> >> >> >>> >>> away and become drm_crtc/drm_encoder/drm_connector funcs
>>>>>> >> >> >>> >>> anyways.
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >> Can you assure the display_ops never implemented in other
>>>>>> >> >> >>> >> framework
>>>>>> >> >> >>> based
>>>>>> >> >> >>> >> driver, not CDF? At any rate, I think all possibilities
>>>>>> >> >> >>> >> should
>>>>>> >> >> >>> >> be
>>>>>> >> >> >>> opened.
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >
>>>>>> >> >> >>> > I don't think we should let an RFC framework make the code
>>>>>> >> >> >>> > more
>>>>>> >> >> >>> > complicated for unclear benefit. By removing manager/display
>>>>>> >> >> >>> > entirely,
>>>>>> >> >> >>> > we can get rid of a *lot* of other code that is basically just
>>>>>> >> >> >>> > plumbing drm hooks (exynos_drm_connector is a good example).
>>>>>> >> >> >>> >
>>>>>> >> >> >>>
>>>>>> >> >> >>> I hacked this up today to prove it out. Check out the top 5
>>>>>> >> >> >>> commits
>>>>>> >> >> >>> in
>>>>>> >> >> >>>
>>>>>> >> >> >>>
>>>>>> >> >> >>>
>>>>>> >> >> >>> https://github.com/crseanpaul/exynos-drm-next/commits/linux-next-exynos-
>>>>>> >> >> >>> staging.
>>>>>> >> >> >>> It removes exynos_drm_connector in favor of just implementing
>>>>>> >> >> >>> drm_connector directly. This same treatment should be done for
>>>>>> >> >> >>> exynos_drm_encoder and exynos_drm_crtc, but I didn't get around
>>>>>> >> >> >>> to
>>>>>> >> >> >>> doing this.
>>>>>> >> >> >>>
>>>>>> >> >> >>> As you can see, it cuts out a lot of code and removes an entire
>>>>>> >> >> >>> abstraction layer. Much nicer :)
>>>>>> >> >> >>>
>>>>>> >> >> >>
>>>>>> >> >> >> It seems that you implements connector in each device driver.
>>>>>> >> >> >> Can't
>>>>>> >> >> >> they be
>>>>>> >> >> >> combined as common spot, exynos_connector, again to avoid codes
>>>>>> >> >> >> from
>>>>>> >> >> >> duplicated? :)
>>>>>> >> >> >
>>>>>> >> >> > There's nothing of substance being duplicated.
>>>>>> >> >>
>>>>>> >> >> Not true. xxx_create_connector is duplicated.
>>>>>> >> >>
>>>>>> >> >> > In fact, by getting rid
>>>>>> >> >> > of the exynos_drm_connector layer, we deleted 150 lines. If you
>>>>>> >> >> > really
>>>>>> >> >> > take a look at exynos_drm_connector, it's not doing anything
>>>>>> >> >> > useful.
>>>>>> >> >>
>>>>>> >> >> No, That is for each driver has no any dependency of drm framework.
>>>>>> >> >>
>>>>>> >> >> > All it does is translate the drm callbacks into display callbacks,
>>>>>> >> >> > so
>>>>>> >> >> > I think it's much better to just implement the drm callbacks
>>>>>> >> >> > directly.
>>>>>> >> >> >
>>>>>> >> >>
>>>>>> >> >> No, It has strongly dependency of drm framework. Assume that we
>>>>>> >> >> implemented the drm callbacks directly, and then some features are
>>>>>> >> >> added to drm framework, drm_connector side. At this time, we will
>>>>>> >> >> have
>>>>>> >> >> to take care of each device driver according to the change. That is
>>>>>> >> >> really not good. Why device drivers should have dependency of drm
>>>>>> >> >> framework? Just to reduce line counts?
>>>>>> >> >
>>>>>> >> >
>>>>>> >> >
>>>>>> >> > You seem to miss the point here and elsewhere in the discussion.
>>>>>> >> > drm/exynos is a drm driver, and as such it should use the drm
>>>>>> >> > framework,
>>>>>> >>
>>>>>> >> Hm.. you seem to miss something. Exynos drm based drivers are based on
>>>>>> >> exynos drm framework, not drm framework directly. So I mean that
>>>>>> >> Exynos drm framework based drivers should include only Exynos drm
>>>>>> >> headers, _not drm header_ directly.
>>>>>> >
>>>>>> >
>>>>>> > Well, I think everyone sees that exynos is different. But my point still
>>>>>> > remains: why is the exynos driver in drm/ if it wants to use a different
>>>>>> > framework? Right now it is blocking work on a proper drm driver...
>>>>>> >
>>>>>>
>>>>>> Noooooo. It's not to use a different framework. It's to use a wrapper
>>>>>> instead.
>>>>>
>>>>>
>>>>> Ok, if you want to call it a wrapper, then what is the point of doing this
>>>>> wrapping given that it prevents a proper drm-style implementation?
>>>>>
>>>>
>>>> I already commented. That is for only Exynos drm framework has
>>>> dependency of drm framework directly, and Exynos drm based drivers
>>>> include only Exynos drm headers.
>>>>
>>>>>
>>>>>>
>>>>>> >
>>>>>> >>
>>>>>> >>
>>>>>> >> > especially if this reduces the line count and the code
>>>>>> >> > complexity (as is the case for this patch series). If you don't want
>>>>>> >> > to maintain a drm driver, it simply should be moved away from drm/,
>>>>>> >> > and it should be replaced by a real drm driver in my opinion.
>>>>>> >>
>>>>>> >> So those drivers should be in drm/exynos. Isn't that you really mean
>>>>>> >> those drivers should be driver/gpu/drm?
>>>>>> >
>>>>>> >
>>>>>> > I don't understand this sentence, sorry.
>>>>>>
>>>>>> Sorry, again, you mean Exynos drm based drivers should be in
>>>>>> drivers/gpu/drm, not drivers/gpu/drm/exynos?
>>>>>>
>>>>> Is the exynos drm useful in its current shape at all? My recommendation
>>>>> would be to fork off a real drm driver in gpu/drm/exynos with the current
>>>>> code as a base.
>>>>>
>>>>
>>>> Yes as of now. of course, There could be a better way. However, I
>>>> don't want for Exynos drm based drivers have dependency of drm
>>>> framework directly.
>>>>
>>>
>>> Just to satisfy my curiosity, do you actually have something that uses
>>> these drivers outside of drm?
>>>
>>
>> Never no.
>>
>>
>>> So I think we've reached somewhat of an impasse. I'd like to move the
>>> driver towards a proper drm driver (ie: no exynos
>>> framework/wrapper/whatever), you'd like to keep things separate. So
>>> should we create a new exynos driver drivers/drm/gpu/exynos5 to house
>>> the drm driver?
>>
>> Did you check out other drm drivers using similar way? And If so, the
>> other drm framework based drivers should be moved?
>
> No, I haven't looked at other ARM drivers. It's besides the point,

Look at omapdrm, nouveau, and radeon drm drivers.

> really, that's not a compelling argument. For the exynos driver, in
> particular, it doesn't make sense to wrapping everything in
> exynos_drm_*

That is really not thing to make sense or not. If you think this
wrapping doesn't make sense, then can you argue about that the above
drivers; omapdrm, nouveau, and radeon don't also make sense? That
would definitely be just their style. If this design has some problem
so the above drm maintainers also want to change their design, then I
will merge your patch set.

>
>> What is the problem
>> that Exynos drm based drivers include only Exynos drm headers, not drm
>> framework header directly? Is that really a big issue? I _cannot_
>> understand your behavior.
>
> The problem is that it makes things unnecessarily complex for no benefit.
>
> For example, that you wanted to implement
> connector_funcs->set_property() just in the hdmi driver. This requires
> that you add a new display_op in exynos_drm_drv.h, then you implement
> the connector_func callback in exynos_drm_connector to check if the op
> is implemented then call it, and then you implement the set_property
> hook in the hdmi driver. If you didn't have the wrapper, you just
> implement the hook in the hdmi driver.
>

As I mentioned earlier, display_ops is needed to have no any
dependency of drm framework directly like below,

                                          DRM Framework
                                                       |
                                        Exynos DRM Framework
                                                    /   |   \
                                         Real device drivers

In particular, in case of ARM based DRM drivers with separated
devices, I still tend to think it's better design than that device
drivers implement the connector callbacks directly, but I will try to
consider what is the better way.

Anyway, can you fix the build error to vidi module? I cannot merge
your re-factoring patch set to exynos-drm-next.

Thanks,
Inki Dae

> Sean
>
>
>> Anyway, if there are any reasons that Exynos
>> drm based drivers should necessary include drm framework header
>> directly, I will agree it.
>>
>> Thanks,
>> Inki Dae
>>
>>>
>>> Sean
>>>
>>>
>>>> Thanks for your opinions.
>>>> Inki Dae
>>>>
>>>>> Stéphane
>>>>>
>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Inki Dae
>>>>>>
>>>>>> >
>>>>>> > Stéphane
>>>>>> >
>>>>>> >
>>>>>> >>
>>>>>> >> If so, That would really be
>>>>>> >> horrible. :(
>>>>>> >>
>>>>>> >
>>>>>> >
>>>>>> >>
>>>>>> >> Please, know that only Exynos drm framework, _not device drivers_, has
>>>>>> >> all dependencies of drm framework, and also I know that other ARM
>>>>>> >> based drm drivers are using same way.
>>>>>> >>
>>>>>> >> Thanks,
>>>>>> >> Inki Dae
>>>>>> >>
>>>>>> >> >
>>>>>> >> > Stéphane
>>>>>> >> >
>>>>>> >> >>
>>>>>> >> >>
>>>>>> >> >> > There are a bunch of real bugs that we've found as a result of
>>>>>> >> >> > having
>>>>>> >> >> > these abstraction layers. Take, for example, dpms. Before this
>>>>>> >> >> > patchset, dpms for fimd was being tracked separately in fimd
>>>>>> >> >> > driver,
>>>>>> >> >> > exynos_drm_encoder, exynos_drm_crtc, and exynos_drm_connector.
>>>>>> >> >> > Furthermore, during suspend, only fimd driver's dpms state was
>>>>>> >> >> > updated, so the others were incorrect. There was also this weird
>>>>>> >> >> > gymnastics that had to happen when dpms was changed in the encoder
>>>>>> >> >> > since it had to walk up to the connector level to change its dpms
>>>>>> >> >> > state. If fimd just directly implemented
>>>>>> >> >> > drm_crtc/drm_encoder/drm_connector (before dp was moved in), this
>>>>>> >> >> > problem wouldn't exist. The same goes for HDMI/mixer.
>>>>>> >> >> >
>>>>>> >> >>
>>>>>> >> >> That is a issue we should take care of by using the independent
>>>>>> >> >> layer.
>>>>>> >> >> Then, aren't you take care of that well with the re-factoring patch
>>>>>> >> >> set? :)  It seems that you are outside real point.
>>>>>> >> >>
>>>>>> >> >> > Take a look at exynos_drm_encoder.c  in my tree
>>>>>> >> >> >
>>>>>> >> >> >
>>>>>> >> >> >
>>>>>> >> >> > (https://github.com/crseanpaul/exynos-drm-next/blob/linux-next-exynos-staging/drivers/gpu/drm/exynos/exynos_drm_encoder.c),
>>>>>> >> >> > what does it do that's useful to abstract? All that it does is
>>>>>> >> >> > just
>>>>>> >> >> > call display ops, it's completely useless. The same is true for
>>>>>> >> >> > exynos_drm_connector, it's just dead weight. There is some useful
>>>>>> >> >> > stuff in exynos_drm_crtc for page flipping, that would be better
>>>>>> >> >> > served as a helper library, though.
>>>>>> >> >> >
>>>>>> >> >> >> The abstraction layer you mentioned also means a common spot.
>>>>>> >> >> >> Another one, you patch also makes each sub driver have strongly
>>>>>> >> >> >> dependency
>>>>>> >> >> >> of drm framework. So how we can support existing backlight and
>>>>>> >> >> >> lcd
>>>>>> >> >> >> class
>>>>>> >> >> >> based lcd panel drivers if the connector is implemented in each
>>>>>> >> >> >> device
>>>>>> >> >> >> driver later?  the drm header files should be included in
>>>>>> >> >> >> drivers/video/backlight/xxx_lcd.c?
>>>>>> >> >> >>
>>>>>> >> >> >
>>>>>> >> >> > drm_bridge or drm_panel seem like good candidates for this.
>>>>>> >> >> >
>>>>>> >> >>
>>>>>> >> >> Yes, exynos_drm_display could be replaced with drm_panel later if
>>>>>> >> >> the
>>>>>> >> >> drm_panel can be merged to mainline.
>>>>>> >> >>
>>>>>> >> >> >
>>>>>> >> >> >> And, I will introduce a new framework to support existing lcd
>>>>>> >> >> >> panel
>>>>>> >> >> >> drivers
>>>>>> >> >> >> and display bus drivers soon; as of now for Exynos drm, and the
>>>>>> >> >> >> framework is
>>>>>> >> >> >> being tested internally. With this framework, encoder and
>>>>>> >> >> >> connector
>>>>>> >> >> >> will be
>>>>>> >> >> >> created when lcd panel or display bus driver such as eDP is
>>>>>> >> >> >> probed:
>>>>>> >> >> >> it
>>>>>> >> >> >> doesn’t really need to create encoder and connector in advance if
>>>>>> >> >> >> lcd
>>>>>> >> >> >> panel
>>>>>> >> >> >> or display bus driver isn't probed yet. Regardless of crtc, and
>>>>>> >> >> >> encoder
>>>>>> >> >> >> and
>>>>>> >> >> >> connector creation order, when last one is created, crtc and
>>>>>> >> >> >> connector
>>>>>> >> >> >> will
>>>>>> >> >> >> be connected each other. And exynos_drm_display could be
>>>>>> >> >> >> implemented
>>>>>> >> >> >> in
>>>>>> >> >> >> other frameworks if we have common structure for display device
>>>>>> >> >> >> driver.
>>>>>> >> >> >> And
>>>>>> >> >> >> also the framework will support lvds driver according to Linux
>>>>>> >> >> >> device
>>>>>> >> >> >> driver
>>>>>> >> >> >> model.
>>>>>> >> >> >>
>>>>>> >> >> >
>>>>>> >> >> > I don't really follow what you're trying to do here, but I think
>>>>>> >> >> > we
>>>>>> >> >> > should be moving in the direction of fewer abstractions in the
>>>>>> >> >> > exynos
>>>>>> >> >> > driver, not more :)
>>>>>> >> >> >
>>>>>> >> >>
>>>>>> >> >> Not abstraction layer, just a bridge for connecting crtc and its
>>>>>> >> >> corresponding encoder/connector, and lvds regardless of creation
>>>>>> >> >> order, and for connecting drm connector and other framework based
>>>>>> >> >> display ops such as drm_panel later.
>>>>>> >> >>
>>>>>> >> >> > Sean
>>>>>> >> >> >
>>>>>> >> >> >
>>>>>> >> >> >
>>>>>> >> >> >> Thanks,
>>>>>> >> >> >> Inki Dae
>>>>>> >> >> >>
>>>>>> >> >> >>> Sean
>>>>>> >> >> >>>
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> > And another one, the patch 6 passes manager object to
>>>>>> >> >> >>> >>> > manager_ops,
>>>>>> >> >> >>> and
>>>>>> >> >> >>> >>> for
>>>>>> >> >> >>> >>> > this, you made the manager object to be set to driver
>>>>>> >> >> >>> >>> > data;
>>>>>> >> >> >>> >>> > platform_set_drvdata(pdev, &manager). That isn't
>>>>>> >> >> >>> >>> > reasonable.
>>>>>> >> >> >>> Generally,
>>>>>> >> >> >>> >>> > driver_data would point to device driver's context object.
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> I'm not sure why this isn't reasonable, but it's a moot
>>>>>> >> >> >>> >>> point.
>>>>>> >> >> >>> >>> The
>>>>>> >> >> >>> >>> driver data is only used up until we get rid of the pm ops,
>>>>>> >> >> >>> >>> it
>>>>>> >> >> >>> >>> needn't
>>>>>> >> >> >>> >>> be set at all once things go through dpms.
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >> Generally, device drivers can call its own internal
>>>>>> >> >> >>> >> functions,
>>>>>> >> >> >>> >> and
>>>>>> >> >> >>> >> they
>>>>>> >> >> >>> will
>>>>>> >> >> >>> >> call that functions with ctx. However, if you set manager to
>>>>>> >> >> >>> driver_data
>>>>>> >> >> >>> >> then that functions should be called with manager object and
>>>>>> >> >> >>> >> also
>>>>>> >> >> >>> internally
>>>>>> >> >> >>> >> that functions should get ctx from the manager object. What
>>>>>> >> >> >>> >> is
>>>>>> >> >> >>> >> the
>>>>>> >> >> >>> purpose
>>>>>> >> >> >>> >> of manager? Do you think it's reasonable?
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >
>>>>>> >> >> >>> > So, to avoid setting the manager as the drvdata, we could
>>>>>> >> >> >>> > implement
>>>>>> >> >> >>> > something like fimd_dpms_ctx(ctx, mode) that takes ctx and the
>>>>>> >> >> >>> > manager
>>>>>> >> >> >>> > callback calls it fimd_dpms(mgr, mode) { ctx = mgr->ctx;
>>>>>> >> >> >>> > fimd_dpms_ctx(ctx, mode); }. Alternatively, you can save a
>>>>>> >> >> >>> > pointer
>>>>>> >> >> >>> > to
>>>>>> >> >> >>> > mgr in ctx, but that creates a circular link between the two.
>>>>>> >> >> >>> > IMO,
>>>>>> >> >> >>> > both of those solutions suck :)
>>>>>> >> >> >>> >
>>>>>> >> >> >>> > I'd much rather just set drvdata to the manager and call the
>>>>>> >> >> >>> > hook
>>>>>> >> >> >>> > directly. Like I said earlier, this is just a temporary step
>>>>>> >> >> >>> > since
>>>>>> >> >> >>> > we
>>>>>> >> >> >>> > remove these pm ops later in the patch series.
>>>>>> >> >> >>> >
>>>>>> >> >> >>> > Sean
>>>>>> >> >> >>> >
>>>>>> >> >> >>> >
>>>>>> >> >> >>> >> Anyway, I'd like to say really sorry about inconvenient
>>>>>> >> >> >>> >> again.
>>>>>> >> >> >>> >> So I
>>>>>> >> >> >>> will fix
>>>>>> >> >> >>> >> it.
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >> Thanks,
>>>>>> >> >> >>> >> Inki Dae
>>>>>> >> >> >>> >>
>>>>>> >> >> >>> >>> Sean
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>>
>>>>>> >> >> >>> >>> > Thanks,
>>>>>> >> >> >>> >>> > Inki Dae
>>>>>> >> >> >>> >>> >
>>>>>> >> >> >>> >>
>>>>>> >> >> >>
>>>>>> >> >> > _______________________________________________
>>>>>> >> >> > dri-devel mailing list
>>>>>> >> >> > dri-devel@lists.freedesktop.org
>>>>>> >> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>> >> >> _______________________________________________
>>>>>> >> >> dri-devel mailing list
>>>>>> >> >> dri-devel@lists.freedesktop.org
>>>>>> >> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>> >> >
>>>>>> >> >
>>>>>> >> >
>>>>>> >> > _______________________________________________
>>>>>> >> > dri-devel mailing list
>>>>>> >> > dri-devel@lists.freedesktop.org
>>>>>> >> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>> >> >
>>>>>> >
>>>>>> >
>>>>>> >
>>>>>> > _______________________________________________
>>>>>> > dri-devel mailing list
>>>>>> > dri-devel@lists.freedesktop.org
>>>>>> > http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>> >
>>>>>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> dri-devel mailing list
>>>>> dri-devel@lists.freedesktop.org
>>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel@lists.freedesktop.org
>>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel@lists.freedesktop.org
>>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 13:18                                     ` Inki Dae
@ 2013-10-23 14:29                                       ` Dave Airlie
  2013-10-23 14:45                                         ` Sean Paul
  2013-10-23 14:51                                       ` Rob Clark
  1 sibling, 1 reply; 93+ messages in thread
From: Dave Airlie @ 2013-10-23 14:29 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

> As I mentioned earlier, display_ops is needed to have no any
> dependency of drm framework directly like below,
>
>                                           DRM Framework
>                                                        |
>                                         Exynos DRM Framework
>                                                     /   |   \
>                                          Real device drivers
>
> In particular, in case of ARM based DRM drivers with separated
> devices, I still tend to think it's better design than that device
> drivers implement the connector callbacks directly, but I will try to
> consider what is the better way.
>

I think we need to start considering a framework where subdrivers just
add drm objects themselves, then the toplevel node is responsible for
knowing that everything for the current configuration is loaded.

I realise we may need to make changes to the core drm to allow this
but we should probably start to create a strategy for fixing the API
issues that this throws up.

Note I'm not yet advocating for dynamic addition of nodes once the
device is in use, or removing them.

Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 14:29                                       ` Dave Airlie
@ 2013-10-23 14:45                                         ` Sean Paul
  2013-10-23 15:22                                           ` Dave Airlie
  2013-10-24  6:47                                           ` Inki Dae
  0 siblings, 2 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-23 14:45 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>> As I mentioned earlier, display_ops is needed to have no any
>> dependency of drm framework directly like below,
>>
>>                                           DRM Framework
>>                                                        |
>>                                         Exynos DRM Framework
>>                                                     /   |   \
>>                                          Real device drivers
>>
>> In particular, in case of ARM based DRM drivers with separated
>> devices, I still tend to think it's better design than that device
>> drivers implement the connector callbacks directly, but I will try to
>> consider what is the better way.
>>
>
> I think we need to start considering a framework where subdrivers just
> add drm objects themselves, then the toplevel node is responsible for
> knowing that everything for the current configuration is loaded.
>

It would be nice to specify the various pieces in dt, then have some
type of drm notifier to the toplevel node when everything has been
probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
drivers to be transparent as far as the device's drm driver is
concerned.

Sean


> I realise we may need to make changes to the core drm to allow this
> but we should probably start to create a strategy for fixing the API
> issues that this throws up.
>
> Note I'm not yet advocating for dynamic addition of nodes once the
> device is in use, or removing them.
>
> Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 13:18                                     ` Inki Dae
  2013-10-23 14:29                                       ` Dave Airlie
@ 2013-10-23 14:51                                       ` Rob Clark
  2013-10-24  7:46                                         ` Inki Dae
  1 sibling, 1 reply; 93+ messages in thread
From: Rob Clark @ 2013-10-23 14:51 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 9:18 AM, Inki Dae <inki.dae@samsung.com> wrote:
> Look at omapdrm, nouveau, and radeon drm drivers.


btw, please don't look at omapdrm as a "good" example in this regard.
The layering is really not a good idea and for a long time caused a
lot of problems, which we essentially solved by bypassing parts of the
layering.  I still think omapdss and omapdrm should be flattened into
a single drm driver, then net result would be a drop in # of lines of
code.  I wish there were folks like the Sean and Stéphane who cared
enough to do this for omapdrm ;-)

Other drivers have some modularity to separate code that is
significantly different across genarations (but what form that takes
differs depending on what how the hw differs across generations).
This isn't a bad thing.  But you need to look at the end result.  For
example how I split out the phy code for the mdp4 code in msm (hdmi
and dsi phy differ between otherwise similar 28nm and 45nm parts, but
the rest of the display controller blocks are basically the same).

BR,
-R

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 14:45                                         ` Sean Paul
@ 2013-10-23 15:22                                           ` Dave Airlie
  2013-10-23 15:27                                             ` Rob Clark
                                                               ` (2 more replies)
  2013-10-24  6:47                                           ` Inki Dae
  1 sibling, 3 replies; 93+ messages in thread
From: Dave Airlie @ 2013-10-23 15:22 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 3:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>>> As I mentioned earlier, display_ops is needed to have no any
>>> dependency of drm framework directly like below,
>>>
>>>                                           DRM Framework
>>>                                                        |
>>>                                         Exynos DRM Framework
>>>                                                     /   |   \
>>>                                          Real device drivers
>>>
>>> In particular, in case of ARM based DRM drivers with separated
>>> devices, I still tend to think it's better design than that device
>>> drivers implement the connector callbacks directly, but I will try to
>>> consider what is the better way.
>>>
>>
>> I think we need to start considering a framework where subdrivers just
>> add drm objects themselves, then the toplevel node is responsible for
>> knowing that everything for the current configuration is loaded.
>>
>
> It would be nice to specify the various pieces in dt, then have some
> type of drm notifier to the toplevel node when everything has been
> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
> drivers to be transparent as far as the device's drm driver is
> concerned.
>
> Sean
>
>
>> I realise we may need to make changes to the core drm to allow this
>> but we should probably start to create a strategy for fixing the API
>> issues that this throws up.
>>
>> Note I'm not yet advocating for dynamic addition of nodes once the
>> device is in use, or removing them.
>>

I do wonder if we had some sort of tag in the device tree for any nodes
involved in the display, and the core drm layer would read that list,
and when every driver registers tick things off, and when the last one
joins we get a callback and init the drm layer, we'd of course have the
basic drm layer setup prior to that so we can add the objects as the
drivers load. It might make development a bit trickier as you'd need
to make sure someone claimed ownership of all the bits for init to proceed.

Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:22                                           ` Dave Airlie
@ 2013-10-23 15:27                                             ` Rob Clark
  2013-10-23 15:27                                             ` Sean Paul
  2013-11-04 10:08                                             ` Thierry Reding
  2 siblings, 0 replies; 93+ messages in thread
From: Rob Clark @ 2013-10-23 15:27 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 11:22 AM, Dave Airlie <airlied@gmail.com> wrote:
> On Wed, Oct 23, 2013 at 3:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>> As I mentioned earlier, display_ops is needed to have no any
>>>> dependency of drm framework directly like below,
>>>>
>>>>                                           DRM Framework
>>>>                                                        |
>>>>                                         Exynos DRM Framework
>>>>                                                     /   |   \
>>>>                                          Real device drivers
>>>>
>>>> In particular, in case of ARM based DRM drivers with separated
>>>> devices, I still tend to think it's better design than that device
>>>> drivers implement the connector callbacks directly, but I will try to
>>>> consider what is the better way.
>>>>
>>>
>>> I think we need to start considering a framework where subdrivers just
>>> add drm objects themselves, then the toplevel node is responsible for
>>> knowing that everything for the current configuration is loaded.
>>>
>>
>> It would be nice to specify the various pieces in dt, then have some
>> type of drm notifier to the toplevel node when everything has been
>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>> drivers to be transparent as far as the device's drm driver is
>> concerned.
>>
>> Sean
>>
>>
>>> I realise we may need to make changes to the core drm to allow this
>>> but we should probably start to create a strategy for fixing the API
>>> issues that this throws up.
>>>
>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>> device is in use, or removing them.
>>>
>
> I do wonder if we had some sort of tag in the device tree for any nodes
> involved in the display, and the core drm layer would read that list,
> and when every driver registers tick things off, and when the last one
> joins we get a callback and init the drm layer, we'd of course have the
> basic drm layer setup prior to that so we can add the objects as the
> drivers load. It might make development a bit trickier as you'd need
> to make sure someone claimed ownership of all the bits for init to proceed.

I think we do definitely need a way to group nodes so we know what
needs to be assembled into a drm driver.  I know folks seem to believe
that DT should be software agnostic, but maybe we just need some
grouper nodes that sit on the side and know how to map device DT nodes
to software.

(The real funny thing about needing that is..  well I've yet to see
someone be able to hot-unplug a block on a piece of silicon.)

BR,
-R

> Dave.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:22                                           ` Dave Airlie
  2013-10-23 15:27                                             ` Rob Clark
@ 2013-10-23 15:27                                             ` Sean Paul
  2013-10-23 15:28                                               ` Sean Paul
  2013-10-23 15:53                                               ` Dave Airlie
  2013-11-04 10:08                                             ` Thierry Reding
  2 siblings, 2 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-23 15:27 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 11:22 AM, Dave Airlie <airlied@gmail.com> wrote:
> On Wed, Oct 23, 2013 at 3:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>> As I mentioned earlier, display_ops is needed to have no any
>>>> dependency of drm framework directly like below,
>>>>
>>>>                                           DRM Framework
>>>>                                                        |
>>>>                                         Exynos DRM Framework
>>>>                                                     /   |   \
>>>>                                          Real device drivers
>>>>
>>>> In particular, in case of ARM based DRM drivers with separated
>>>> devices, I still tend to think it's better design than that device
>>>> drivers implement the connector callbacks directly, but I will try to
>>>> consider what is the better way.
>>>>
>>>
>>> I think we need to start considering a framework where subdrivers just
>>> add drm objects themselves, then the toplevel node is responsible for
>>> knowing that everything for the current configuration is loaded.
>>>
>>
>> It would be nice to specify the various pieces in dt, then have some
>> type of drm notifier to the toplevel node when everything has been
>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>> drivers to be transparent as far as the device's drm driver is
>> concerned.
>>
>> Sean
>>
>>
>>> I realise we may need to make changes to the core drm to allow this
>>> but we should probably start to create a strategy for fixing the API
>>> issues that this throws up.
>>>
>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>> device is in use, or removing them.
>>>
>
> I do wonder if we had some sort of tag in the device tree for any nodes
> involved in the display, and the core drm layer would read that list,
> and when every driver registers tick things off, and when the last one
> joins we get a callback and init the drm layer, we'd of course have the
> basic drm layer setup prior to that so we can add the objects as the
> drivers load. It might make development a bit trickier as you'd need
> to make sure someone claimed ownership of all the bits for init to proceed.
>

Yeah, that's basically what the strawman looked like in my head.

Instead of a property in each node, I was thinking of having a
separate gfx pipe nodes that would have dt pointers to the various
pieces involved in that pipe. This would allow us to associate
standalone entities like bridges and panels with encoders in dt w/o
doing it in the drm code. I *think* this should be Ok with the dt guys
since it is still describing the hardware, but I think we'd have to
make sure it wasn't drm-specific.

Sean

> Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:27                                             ` Sean Paul
@ 2013-10-23 15:28                                               ` Sean Paul
  2013-10-23 15:53                                               ` Dave Airlie
  1 sibling, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-23 15:28 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 11:27 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Oct 23, 2013 at 11:22 AM, Dave Airlie <airlied@gmail.com> wrote:
>> On Wed, Oct 23, 2013 at 3:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
>>> On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>>> As I mentioned earlier, display_ops is needed to have no any
>>>>> dependency of drm framework directly like below,
>>>>>
>>>>>                                           DRM Framework
>>>>>                                                        |
>>>>>                                         Exynos DRM Framework
>>>>>                                                     /   |   \
>>>>>                                          Real device drivers
>>>>>
>>>>> In particular, in case of ARM based DRM drivers with separated
>>>>> devices, I still tend to think it's better design than that device
>>>>> drivers implement the connector callbacks directly, but I will try to
>>>>> consider what is the better way.
>>>>>
>>>>
>>>> I think we need to start considering a framework where subdrivers just
>>>> add drm objects themselves, then the toplevel node is responsible for
>>>> knowing that everything for the current configuration is loaded.
>>>>
>>>
>>> It would be nice to specify the various pieces in dt, then have some
>>> type of drm notifier to the toplevel node when everything has been
>>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>>> drivers to be transparent as far as the device's drm driver is
>>> concerned.
>>>
>>> Sean
>>>
>>>
>>>> I realise we may need to make changes to the core drm to allow this
>>>> but we should probably start to create a strategy for fixing the API
>>>> issues that this throws up.
>>>>
>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>>> device is in use, or removing them.
>>>>
>>
>> I do wonder if we had some sort of tag in the device tree for any nodes
>> involved in the display, and the core drm layer would read that list,
>> and when every driver registers tick things off, and when the last one
>> joins we get a callback and init the drm layer, we'd of course have the
>> basic drm layer setup prior to that so we can add the objects as the
>> drivers load. It might make development a bit trickier as you'd need
>> to make sure someone claimed ownership of all the bits for init to proceed.
>>
>
> Yeah, that's basically what the strawman looked like in my head.
>
> Instead of a property in each node, I was thinking of having a
> separate gfx pipe nodes that would have dt pointers to the various
> pieces involved in that pipe. This would allow us to associate
> standalone entities like bridges and panels with encoders in dt w/o
> doing it in the drm code. I *think* this should be Ok with the dt guys
> since it is still describing the hardware, but I think we'd have to
> make sure it wasn't drm-specific.
>

tl;dr: What Rob said

> Sean
>
>> Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:27                                             ` Sean Paul
  2013-10-23 15:28                                               ` Sean Paul
@ 2013-10-23 15:53                                               ` Dave Airlie
  2013-10-23 16:09                                                 ` Sean Paul
  1 sibling, 1 reply; 93+ messages in thread
From: Dave Airlie @ 2013-10-23 15:53 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

>>>>>
>>>>
>>>> I think we need to start considering a framework where subdrivers just
>>>> add drm objects themselves, then the toplevel node is responsible for
>>>> knowing that everything for the current configuration is loaded.
>>>>
>>>
>>> It would be nice to specify the various pieces in dt, then have some
>>> type of drm notifier to the toplevel node when everything has been
>>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>>> drivers to be transparent as far as the device's drm driver is
>>> concerned.
>>>
>>> Sean
>>>
>>>
>>>> I realise we may need to make changes to the core drm to allow this
>>>> but we should probably start to create a strategy for fixing the API
>>>> issues that this throws up.
>>>>
>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>>> device is in use, or removing them.
>>>>
>>
>> I do wonder if we had some sort of tag in the device tree for any nodes
>> involved in the display, and the core drm layer would read that list,
>> and when every driver registers tick things off, and when the last one
>> joins we get a callback and init the drm layer, we'd of course have the
>> basic drm layer setup prior to that so we can add the objects as the
>> drivers load. It might make development a bit trickier as you'd need
>> to make sure someone claimed ownership of all the bits for init to proceed.
>>
>
> Yeah, that's basically what the strawman looked like in my head.
>
> Instead of a property in each node, I was thinking of having a
> separate gfx pipe nodes that would have dt pointers to the various
> pieces involved in that pipe. This would allow us to associate
> standalone entities like bridges and panels with encoders in dt w/o
> doing it in the drm code. I *think* this should be Ok with the dt guys
> since it is still describing the hardware, but I think we'd have to
> make sure it wasn't drm-specific.
>

I suppose the question is how much dynamic pipeline construction there is,

even on things like radeon and i915 we have dynamic clock generator to
crtc to encoder setups, so I worry about static lists per-pipe, so I still
think just stating all these devices are needed for display and a list of valid
interconnections between them, then we can have the generic code model
drm crtc/encoders/connectors on that list, and construct the possible_crtcs
/possible_clones etc at that stage.

Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:53                                               ` Dave Airlie
@ 2013-10-23 16:09                                                 ` Sean Paul
  2013-10-28 16:49                                                   ` Olof Johansson
  2013-10-28 23:13                                                   ` Tomasz Figa
  0 siblings, 2 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-23 16:09 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>>>>
>>>>>
>>>>> I think we need to start considering a framework where subdrivers just
>>>>> add drm objects themselves, then the toplevel node is responsible for
>>>>> knowing that everything for the current configuration is loaded.
>>>>>
>>>>
>>>> It would be nice to specify the various pieces in dt, then have some
>>>> type of drm notifier to the toplevel node when everything has been
>>>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>>>> drivers to be transparent as far as the device's drm driver is
>>>> concerned.
>>>>
>>>> Sean
>>>>
>>>>
>>>>> I realise we may need to make changes to the core drm to allow this
>>>>> but we should probably start to create a strategy for fixing the API
>>>>> issues that this throws up.
>>>>>
>>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>>>> device is in use, or removing them.
>>>>>
>>>
>>> I do wonder if we had some sort of tag in the device tree for any nodes
>>> involved in the display, and the core drm layer would read that list,
>>> and when every driver registers tick things off, and when the last one
>>> joins we get a callback and init the drm layer, we'd of course have the
>>> basic drm layer setup prior to that so we can add the objects as the
>>> drivers load. It might make development a bit trickier as you'd need
>>> to make sure someone claimed ownership of all the bits for init to proceed.
>>>
>>
>> Yeah, that's basically what the strawman looked like in my head.
>>
>> Instead of a property in each node, I was thinking of having a
>> separate gfx pipe nodes that would have dt pointers to the various
>> pieces involved in that pipe. This would allow us to associate
>> standalone entities like bridges and panels with encoders in dt w/o
>> doing it in the drm code. I *think* this should be Ok with the dt guys
>> since it is still describing the hardware, but I think we'd have to
>> make sure it wasn't drm-specific.
>>
>
> I suppose the question is how much dynamic pipeline construction there is,
>
> even on things like radeon and i915 we have dynamic clock generator to
> crtc to encoder setups, so I worry about static lists per-pipe, so I still
> think just stating all these devices are needed for display and a list of valid
> interconnections between them, then we can have the generic code model
> drm crtc/encoders/connectors on that list, and construct the possible_crtcs
> /possible_clones etc at that stage.
>

I'm, without excuse, hopeless at devicetree, so there are probably
some violations, but something like:

display-pipelines {
  required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
&crtc-x &crtc-y>;
  pipe1 {
    bridge = <&bridge-a>;
    encoder = <&encoder-x>;
    crtc = <&crtc-y>;
  };
  pipe2 {
    encoder = <&encoder-x>;
    crtc = <&crtc-x>;
  };
  pipe3 {
    panel = <&panel-a>;
    encoder = <&encoder-y>;
    crtc = <&crtc-y>;
  };
};

I'm tempted to add connector to the pipe nodes as well, so it's
obvious which connector should be used in cases where multiple
entities in the pipe implement drm_connector. However, I'm not sure if
that would be NACKed by dt people.

I'm also not sure if there are too many combinations for i915 and
radeon to make this unreasonable. I suppose those devices could just
use required-elements and leave the pipe nodes out.

Sean



> Dave.

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 14:45                                         ` Sean Paul
  2013-10-23 15:22                                           ` Dave Airlie
@ 2013-10-24  6:47                                           ` Inki Dae
  1 sibling, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-24  6:47 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Sean Paul <seanpaul@chromium.org>:
> On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
>>> As I mentioned earlier, display_ops is needed to have no any
>>> dependency of drm framework directly like below,
>>>
>>>                                           DRM Framework
>>>                                                        |
>>>                                         Exynos DRM Framework
>>>                                                     /   |   \
>>>                                          Real device drivers
>>>
>>> In particular, in case of ARM based DRM drivers with separated
>>> devices, I still tend to think it's better design than that device
>>> drivers implement the connector callbacks directly, but I will try to
>>> consider what is the better way.
>>>
>>
>> I think we need to start considering a framework where subdrivers just
>> add drm objects themselves, then the toplevel node is responsible for
>> knowing that everything for the current configuration is loaded.
>>
>
> It would be nice to specify the various pieces in dt, then have some
> type of drm notifier to the toplevel node when everything has been
> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
> drivers to be transparent as far as the device's drm driver is
> concerned.
>

Before that, I think we need to decide that drm driver should reuse
lcd class based drivers, or just should copy the lcd class based
drivers into drm framework.

1. in case that drm driver reuses the existing lcd class based drivers,
- we would need a common layer across between Linux framebuffer and
drm framework. In other words, the lcd class based drivers and drm
driver should be able to include a header file to the common layer,
and the header should provide some callbacks such as drm_panel
structure, and also some functions to create a connector and a
encoder. Actually, that is why Exynos drm framework has a wrapper to
drm connector and encoder, and display_ops also.

2. in case that drm driver uses duplicated lcd driver,
- we wouldn't need the common layer because a connector and a encoder
can be created directly in the lcd driver so in this case, I think the
wrapper to drm connector and display_ops wouldn't be needed anymore.

And shouldn't the device tree related works be discussed after we
select one of the above two cases? or should we consider all of the
above two cases?

> Sean
>
>
>> I realise we may need to make changes to the core drm to allow this
>> but we should probably start to create a strategy for fixing the API
>> issues that this throws up.
>>
>> Note I'm not yet advocating for dynamic addition of nodes once the
>> device is in use, or removing them.
>>
>> Dave.
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 14:51                                       ` Rob Clark
@ 2013-10-24  7:46                                         ` Inki Dae
  2013-10-25  5:15                                           ` Inki Dae
  2013-10-28 20:43                                           ` Rob Clark
  0 siblings, 2 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-24  7:46 UTC (permalink / raw)
  To: Rob Clark; +Cc: Stéphane Marchesin, dri-devel

2013/10/23 Rob Clark <robdclark@gmail.com>:
> On Wed, Oct 23, 2013 at 9:18 AM, Inki Dae <inki.dae@samsung.com> wrote:
>> Look at omapdrm, nouveau, and radeon drm drivers.
>
>
> btw, please don't look at omapdrm as a "good" example in this regard.
> The layering is really not a good idea and for a long time caused a
> lot of problems, which we essentially solved by bypassing parts of the
> layering.  I still think omapdss and omapdrm should be flattened into
> a single drm driver, then net result would be a drop in # of lines of

It seems that you proper to use duplicated driver. I mean... do you
proper that omapdss driver is placed in drm framework? Otherwise, is
there any way that omapdss and omapdrm can be flattened into a single
drm driver without moving omapdss into drm framework? As I mentioned
earlier, we wanted to reuse the existing panel driver so Exynos drm
framework has the layer, wrappers to connector and encoder. Of course,
for this, we have TODO works yet, and I still think it's better way to
keep the wrapper if we should reuse the existing panel drivers.

The below would be one design for the case,


                                                              lcd panel drivers
                                                                      \ | /
                                   drm framework  -----  drm_bridge
                                                                      / | \
                                                      crtc
drivers(display controller or hdmi)


A header file of drm_bridge includes drm_panel structure having some
callbacks related to connector, and some function to register crtc and
panel driver's requests to the drm_bridge object. And the header file
can be included in the existing panel drivers. In other words,
drm_bridge will connect drm driver and lcd class based panel drivers.

struct drm_bridge {
        struct list_head list;
        unsigned int type;
        struct drm_device *drm_dev;
        struct drm_panel *panel_ops;
        ...
        int (*drm_create_enc_conn)(....);
};

A drm_bridge object has drm_panel ops and drm_create_enc_conn
callback. And once the crtc driver calls register function of the
drm_bridge with drm_create_enc_conn callback pointer, a drm_crtc is
created, and once the panel driver calls the register function with
drm_panel ops, a encoder and a connector are created. At this time,
drm_fb_helper_initial_config() can be called appropriately to connect
crtc and connector, and to display framebuffer on lcd panel.

The above is just my opinion for the case, and we are testing this way
implementing it internally.

Thanks,
Inki Dae

> code.  I wish there were folks like the Sean and Stéphane who cared
> enough to do this for omapdrm ;-)
>
> Other drivers have some modularity to separate code that is
> significantly different across genarations (but what form that takes
> differs depending on what how the hw differs across generations).
> This isn't a bad thing.  But you need to look at the end result.  For
> example how I split out the phy code for the mdp4 code in msm (hdmi
> and dsi phy differ between otherwise similar 28nm and 45nm parts, but
> the rest of the display controller blocks are basically the same).
>
> BR,
> -R
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-24  7:46                                         ` Inki Dae
@ 2013-10-25  5:15                                           ` Inki Dae
  2013-10-28 20:43                                           ` Rob Clark
  1 sibling, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-10-25  5:15 UTC (permalink / raw)
  To: Rob Clark; +Cc: Stéphane Marchesin, dri-devel

Sorry for some typos.

2013/10/24 Inki Dae <inki.dae@samsung.com>:
> 2013/10/23 Rob Clark <robdclark@gmail.com>:
>> On Wed, Oct 23, 2013 at 9:18 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>> Look at omapdrm, nouveau, and radeon drm drivers.
>>
>>
>> btw, please don't look at omapdrm as a "good" example in this regard.
>> The layering is really not a good idea and for a long time caused a
>> lot of problems, which we essentially solved by bypassing parts of the
>> layering.  I still think omapdss and omapdrm should be flattened into
>> a single drm driver, then net result would be a drop in # of lines of
>
> It seems that you proper to use duplicated driver. I mean... do you

s/proper/prefer

> proper that omapdss driver is placed in drm framework? Otherwise, is

s/proper/prefer

> there any way that omapdss and omapdrm can be flattened into a single
> drm driver without moving omapdss into drm framework? As I mentioned
> earlier, we wanted to reuse the existing panel driver so Exynos drm
> framework has the layer, wrappers to connector and encoder. Of course,
> for this, we have TODO works yet, and I still think it's better way to
> keep the wrapper if we should reuse the existing panel drivers.
>
> The below would be one design for the case,
>
>
>                                                               lcd panel drivers
>                                                                       \ | /
>                                    drm framework  -----  drm_bridge
>                                                                       / | \
>                                                       crtc
> drivers(display controller or hdmi)
>
>
> A header file of drm_bridge includes drm_panel structure having some
> callbacks related to connector, and some function to register crtc and
> panel driver's requests to the drm_bridge object. And the header file
> can be included in the existing panel drivers. In other words,
> drm_bridge will connect drm driver and lcd class based panel drivers.
>
> struct drm_bridge {
>         struct list_head list;
>         unsigned int type;
>         struct drm_device *drm_dev;
>         struct drm_panel *panel_ops;
>         ...
>         int (*drm_create_enc_conn)(....);
> };
>
> A drm_bridge object has drm_panel ops and drm_create_enc_conn
> callback. And once the crtc driver calls register function of the
> drm_bridge with drm_create_enc_conn callback pointer, a drm_crtc is
> created, and once the panel driver calls the register function with
> drm_panel ops, a encoder and a connector are created. At this time,
> drm_fb_helper_initial_config() can be called appropriately to connect
> crtc and connector, and to display framebuffer on lcd panel.
>
> The above is just my opinion for the case, and we are testing this way
> implementing it internally.
>
> Thanks,
> Inki Dae
>
>> code.  I wish there were folks like the Sean and Stéphane who cared
>> enough to do this for omapdrm ;-)
>>
>> Other drivers have some modularity to separate code that is
>> significantly different across genarations (but what form that takes
>> differs depending on what how the hw differs across generations).
>> This isn't a bad thing.  But you need to look at the end result.  For
>> example how I split out the phy code for the mdp4 code in msm (hdmi
>> and dsi phy differ between otherwise similar 28nm and 45nm parts, but
>> the rest of the display controller blocks are basically the same).
>>
>> BR,
>> -R
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 16:09                                                 ` Sean Paul
@ 2013-10-28 16:49                                                   ` Olof Johansson
  2013-10-28 17:39                                                     ` Sean Paul
  2013-10-28 23:13                                                   ` Tomasz Figa
  1 sibling, 1 reply; 93+ messages in thread
From: Olof Johansson @ 2013-10-28 16:49 UTC (permalink / raw)
  To: Sean Paul; +Cc: Stéphane Marchesin, dri-devel

On Wed, Oct 23, 2013 at 9:09 AM, Sean Paul <seanpaul@chromium.org> wrote:
> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>>>>>
>>>>>>
>>>>>> I think we need to start considering a framework where subdrivers just
>>>>>> add drm objects themselves, then the toplevel node is responsible for
>>>>>> knowing that everything for the current configuration is loaded.
>>>>>>
>>>>>
>>>>> It would be nice to specify the various pieces in dt, then have some
>>>>> type of drm notifier to the toplevel node when everything has been
>>>>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>>>>> drivers to be transparent as far as the device's drm driver is
>>>>> concerned.
>>>>>
>>>>> Sean
>>>>>
>>>>>
>>>>>> I realise we may need to make changes to the core drm to allow this
>>>>>> but we should probably start to create a strategy for fixing the API
>>>>>> issues that this throws up.
>>>>>>
>>>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>>>>> device is in use, or removing them.
>>>>>>
>>>>
>>>> I do wonder if we had some sort of tag in the device tree for any nodes
>>>> involved in the display, and the core drm layer would read that list,
>>>> and when every driver registers tick things off, and when the last one
>>>> joins we get a callback and init the drm layer, we'd of course have the
>>>> basic drm layer setup prior to that so we can add the objects as the
>>>> drivers load. It might make development a bit trickier as you'd need
>>>> to make sure someone claimed ownership of all the bits for init to proceed.
>>>>
>>>
>>> Yeah, that's basically what the strawman looked like in my head.
>>>
>>> Instead of a property in each node, I was thinking of having a
>>> separate gfx pipe nodes that would have dt pointers to the various
>>> pieces involved in that pipe. This would allow us to associate
>>> standalone entities like bridges and panels with encoders in dt w/o
>>> doing it in the drm code. I *think* this should be Ok with the dt guys
>>> since it is still describing the hardware, but I think we'd have to
>>> make sure it wasn't drm-specific.
>>>
>>
>> I suppose the question is how much dynamic pipeline construction there is,
>>
>> even on things like radeon and i915 we have dynamic clock generator to
>> crtc to encoder setups, so I worry about static lists per-pipe, so I still
>> think just stating all these devices are needed for display and a list of valid
>> interconnections between them, then we can have the generic code model
>> drm crtc/encoders/connectors on that list, and construct the possible_crtcs
>> /possible_clones etc at that stage.
>>
>
> I'm, without excuse, hopeless at devicetree, so there are probably
> some violations, but something like:

This is definitely worth discussing. I know device-tree but not DRM so
let's see if we can figure this out together. :)

>
> display-pipelines {
>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> &crtc-x &crtc-y>;

What's this supposed to mean? Are all these elements required to get
DRM up on this particular platform? Or are they just enumerating all
the possible devices that might be involved?

>   pipe1 {
>     bridge = <&bridge-a>;
>     encoder = <&encoder-x>;
>     crtc = <&crtc-y>;
>   };
>   pipe2 {
>     encoder = <&encoder-x>;
>     crtc = <&crtc-x>;
>   };
>   pipe3 {
>     panel = <&panel-a>;
>     encoder = <&encoder-y>;
>     crtc = <&crtc-y>;
>   };

Maybe it's the use of pipe as a keyword that's confusing me here, and
my lack of DRM knowledge, but wouldn't it make more sense to focus on
output connectors here? I.e. describe the outputs such as eDP, LVDS,
HDMI. The bridge, such as edp-to-lvds, should possibly be specified
under the edp node instead of in the drm node here.

Also, while the hardware can allow a very flexible connection of
pipes, I'm guessing that in reality nearly all usage of these will
follow a few common patterns, so maybe it's not required to be able to
describe the full graph in device tree?

> I'm tempted to add connector to the pipe nodes as well, so it's
> obvious which connector should be used in cases where multiple
> entities in the pipe implement drm_connector. However, I'm not sure if
> that would be NACKed by dt people.

As mentioned above, it might make sense to turn it around and describe
it around the connectors instead of the pipes.

> I'm also not sure if there are too many combinations for i915 and
> radeon to make this unreasonable. I suppose those devices could just
> use required-elements and leave the pipe nodes out.


-Olof

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-28 16:49                                                   ` Olof Johansson
@ 2013-10-28 17:39                                                     ` Sean Paul
  0 siblings, 0 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-28 17:39 UTC (permalink / raw)
  To: Olof Johansson; +Cc: Stéphane Marchesin, dri-devel

On Mon, Oct 28, 2013 at 12:49 PM, Olof Johansson <olof@lixom.net> wrote:
> On Wed, Oct 23, 2013 at 9:09 AM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
>>>>>>>>
>>>>>>>
>>>>>>> I think we need to start considering a framework where subdrivers just
>>>>>>> add drm objects themselves, then the toplevel node is responsible for
>>>>>>> knowing that everything for the current configuration is loaded.
>>>>>>>
>>>>>>
>>>>>> It would be nice to specify the various pieces in dt, then have some
>>>>>> type of drm notifier to the toplevel node when everything has been
>>>>>> probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
>>>>>> drivers to be transparent as far as the device's drm driver is
>>>>>> concerned.
>>>>>>
>>>>>> Sean
>>>>>>
>>>>>>
>>>>>>> I realise we may need to make changes to the core drm to allow this
>>>>>>> but we should probably start to create a strategy for fixing the API
>>>>>>> issues that this throws up.
>>>>>>>
>>>>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>>>>>>> device is in use, or removing them.
>>>>>>>
>>>>>
>>>>> I do wonder if we had some sort of tag in the device tree for any nodes
>>>>> involved in the display, and the core drm layer would read that list,
>>>>> and when every driver registers tick things off, and when the last one
>>>>> joins we get a callback and init the drm layer, we'd of course have the
>>>>> basic drm layer setup prior to that so we can add the objects as the
>>>>> drivers load. It might make development a bit trickier as you'd need
>>>>> to make sure someone claimed ownership of all the bits for init to proceed.
>>>>>
>>>>
>>>> Yeah, that's basically what the strawman looked like in my head.
>>>>
>>>> Instead of a property in each node, I was thinking of having a
>>>> separate gfx pipe nodes that would have dt pointers to the various
>>>> pieces involved in that pipe. This would allow us to associate
>>>> standalone entities like bridges and panels with encoders in dt w/o
>>>> doing it in the drm code. I *think* this should be Ok with the dt guys
>>>> since it is still describing the hardware, but I think we'd have to
>>>> make sure it wasn't drm-specific.
>>>>
>>>
>>> I suppose the question is how much dynamic pipeline construction there is,
>>>
>>> even on things like radeon and i915 we have dynamic clock generator to
>>> crtc to encoder setups, so I worry about static lists per-pipe, so I still
>>> think just stating all these devices are needed for display and a list of valid
>>> interconnections between them, then we can have the generic code model
>>> drm crtc/encoders/connectors on that list, and construct the possible_crtcs
>>> /possible_clones etc at that stage.
>>>
>>
>> I'm, without excuse, hopeless at devicetree, so there are probably
>> some violations, but something like:
>
> This is definitely worth discussing. I know device-tree but not DRM so
> let's see if we can figure this out together. :)
>
>>
>> display-pipelines {
>>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> &crtc-x &crtc-y>;
>
> What's this supposed to mean? Are all these elements required to get
> DRM up on this particular platform? Or are they just enumerating all
> the possible devices that might be involved?
>

I was thinking that these would be all of the pieces that are required
before drm is loaded.

So, in the multiple device-drivers scenario, these would all register
themselves with drm on probe. drm would tick them off the list as they
probe until all have been accounted for. At this point, drm would load
and call them back with a pointer to the drm_device.

In the case where there is One True DRM Driver, where the various
devices are not standalone drivers (see ptn3460 patch for this model),
this would be the list of devices that drm is responsible for linking
in. To do this, it would need to call one hook when it probes (so it
can be deferred), and than an initialization hook later once
everything is probed and ready.

>>   pipe1 {
>>     bridge = <&bridge-a>;
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-y>;
>>   };
>>   pipe2 {
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-x>;
>>   };
>>   pipe3 {
>>     panel = <&panel-a>;
>>     encoder = <&encoder-y>;
>>     crtc = <&crtc-y>;
>>   };
>
> Maybe it's the use of pipe as a keyword that's confusing me here, and
> my lack of DRM knowledge, but wouldn't it make more sense to focus on
> output connectors here? I.e. describe the outputs such as eDP, LVDS,
> HDMI. The bridge, such as edp-to-lvds, should possibly be specified
> under the edp node instead of in the drm node here.
>

Sure, I think "pipeX" is poor nomenclature on my part. It would make
more sense to have these node names translate to the actual connector
name. I was trying to be a bit opaque/non-drm-specific to avoid
describing software in the devicetree.

Again, using the ptn driver as an example, something like:

LVDS-1 {
        connector = <&ptn3460>;
        bridge = <&ptn3460>;
        encoder = <&display-port-controller>;
        crtc = <&fimd>;
};



> Also, while the hardware can allow a very flexible connection of
> pipes, I'm guessing that in reality nearly all usage of these will
> follow a few common patterns, so maybe it's not required to be able to
> describe the full graph in device tree?
>

I suspect you're correct. I think we can make bridge/encoder/crtc
arrays such that you can describe multiple pipes within one connector.
Admittedly, I have a very narrow view of the different hardware that
might use this, so there might be a better way.

Sean



>> I'm tempted to add connector to the pipe nodes as well, so it's
>> obvious which connector should be used in cases where multiple
>> entities in the pipe implement drm_connector. However, I'm not sure if
>> that would be NACKed by dt people.
>
> As mentioned above, it might make sense to turn it around and describe
> it around the connectors instead of the pipes.
>
>> I'm also not sure if there are too many combinations for i915 and
>> radeon to make this unreasonable. I suppose those devices could just
>> use required-elements and leave the pipe nodes out.
>
>
> -Olof

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-24  7:46                                         ` Inki Dae
  2013-10-25  5:15                                           ` Inki Dae
@ 2013-10-28 20:43                                           ` Rob Clark
  1 sibling, 0 replies; 93+ messages in thread
From: Rob Clark @ 2013-10-28 20:43 UTC (permalink / raw)
  To: Inki Dae; +Cc: Stéphane Marchesin, dri-devel

On Thu, Oct 24, 2013 at 3:46 AM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/10/23 Rob Clark <robdclark@gmail.com>:
>> On Wed, Oct 23, 2013 at 9:18 AM, Inki Dae <inki.dae@samsung.com> wrote:
>>> Look at omapdrm, nouveau, and radeon drm drivers.
>>
>>
>> btw, please don't look at omapdrm as a "good" example in this regard.
>> The layering is really not a good idea and for a long time caused a
>> lot of problems, which we essentially solved by bypassing parts of the
>> layering.  I still think omapdss and omapdrm should be flattened into
>> a single drm driver, then net result would be a drop in # of lines of
>
> It seems that you proper to use duplicated driver. I mean... do you
> proper that omapdss driver is placed in drm framework? Otherwise, is
> there any way that omapdss and omapdrm can be flattened into a single
> drm driver without moving omapdss into drm framework? As I mentioned
> earlier, we wanted to reuse the existing panel driver so Exynos drm
> framework has the layer, wrappers to connector and encoder. Of course,
> for this, we have TODO works yet, and I still think it's better way to
> keep the wrapper if we should reuse the existing panel drivers.

If it were my decision, I would duplicate (+refactor) the code into
drm..  there ends up being some duplication between fbdev and drm, but
the benefit is less risk of breaking other subsystem (fbdev) in the
short term and more flexibility to refactor things to fit better into
how drm/kms works.

In the long term, fbdev stops being something we care about, so the
duplicate code is just a transient problem.  But what ends up in drm
we live with for a long time, so it is easier in the long run to not
have to care about both fbdev and drm with the same code.

BR,
-R

> The below would be one design for the case,
>
>
>                                                               lcd panel drivers
>                                                                       \ | /
>                                    drm framework  -----  drm_bridge
>                                                                       / | \
>                                                       crtc
> drivers(display controller or hdmi)
>
>
> A header file of drm_bridge includes drm_panel structure having some
> callbacks related to connector, and some function to register crtc and
> panel driver's requests to the drm_bridge object. And the header file
> can be included in the existing panel drivers. In other words,
> drm_bridge will connect drm driver and lcd class based panel drivers.
>
> struct drm_bridge {
>         struct list_head list;
>         unsigned int type;
>         struct drm_device *drm_dev;
>         struct drm_panel *panel_ops;
>         ...
>         int (*drm_create_enc_conn)(....);
> };
>
> A drm_bridge object has drm_panel ops and drm_create_enc_conn
> callback. And once the crtc driver calls register function of the
> drm_bridge with drm_create_enc_conn callback pointer, a drm_crtc is
> created, and once the panel driver calls the register function with
> drm_panel ops, a encoder and a connector are created. At this time,
> drm_fb_helper_initial_config() can be called appropriately to connect
> crtc and connector, and to display framebuffer on lcd panel.
>
> The above is just my opinion for the case, and we are testing this way
> implementing it internally.
>
> Thanks,
> Inki Dae
>
>> code.  I wish there were folks like the Sean and Stéphane who cared
>> enough to do this for omapdrm ;-)
>>
>> Other drivers have some modularity to separate code that is
>> significantly different across genarations (but what form that takes
>> differs depending on what how the hw differs across generations).
>> This isn't a bad thing.  But you need to look at the end result.  For
>> example how I split out the phy code for the mdp4 code in msm (hdmi
>> and dsi phy differ between otherwise similar 28nm and 45nm parts, but
>> the rest of the display controller blocks are basically the same).
>>
>> BR,
>> -R
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 16:09                                                 ` Sean Paul
  2013-10-28 16:49                                                   ` Olof Johansson
@ 2013-10-28 23:13                                                   ` Tomasz Figa
  2013-10-29 19:19                                                     ` Olof Johansson
  2013-10-29 20:36                                                     ` Sean Paul
  1 sibling, 2 replies; 93+ messages in thread
From: Tomasz Figa @ 2013-10-28 23:13 UTC (permalink / raw)
  To: dri-devel; +Cc: Laurent Pinchart, Sylwester Nawrocki, Stéphane Marchesin

Hi,

On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
> >>>>> I think we need to start considering a framework where subdrivers
> >>>>> just
> >>>>> add drm objects themselves, then the toplevel node is responsible
> >>>>> for
> >>>>> knowing that everything for the current configuration is loaded.
> >>>> 
> >>>> It would be nice to specify the various pieces in dt, then have
> >>>> some
> >>>> type of drm notifier to the toplevel node when everything has been
> >>>> probed. Doing it in the dt would allow standalone
> >>>> drm_bridge/drm_panel
> >>>> drivers to be transparent as far as the device's drm driver is
> >>>> concerned.
> >>>> 
> >>>> Sean
> >>>> 
> >>>>> I realise we may need to make changes to the core drm to allow
> >>>>> this
> >>>>> but we should probably start to create a strategy for fixing the
> >>>>> API
> >>>>> issues that this throws up.
> >>>>> 
> >>>>> Note I'm not yet advocating for dynamic addition of nodes once the
> >>>>> device is in use, or removing them.
> >>> 
> >>> I do wonder if we had some sort of tag in the device tree for any
> >>> nodes
> >>> involved in the display, and the core drm layer would read that
> >>> list,
> >>> and when every driver registers tick things off, and when the last
> >>> one
> >>> joins we get a callback and init the drm layer, we'd of course have
> >>> the
> >>> basic drm layer setup prior to that so we can add the objects as the
> >>> drivers load. It might make development a bit trickier as you'd need
> >>> to make sure someone claimed ownership of all the bits for init to
> >>> proceed.>> 
> >> Yeah, that's basically what the strawman looked like in my head.
> >> 
> >> Instead of a property in each node, I was thinking of having a
> >> separate gfx pipe nodes that would have dt pointers to the various
> >> pieces involved in that pipe. This would allow us to associate
> >> standalone entities like bridges and panels with encoders in dt w/o
> >> doing it in the drm code. I *think* this should be Ok with the dt
> >> guys
> >> since it is still describing the hardware, but I think we'd have to
> >> make sure it wasn't drm-specific.
> > 
> > I suppose the question is how much dynamic pipeline construction there
> > is,
> > 
> > even on things like radeon and i915 we have dynamic clock generator to
> > crtc to encoder setups, so I worry about static lists per-pipe, so I
> > still think just stating all these devices are needed for display and
> > a list of valid interconnections between them, then we can have the
> > generic code model drm crtc/encoders/connectors on that list, and
> > construct the possible_crtcs /possible_clones etc at that stage.
> 
> I'm, without excuse, hopeless at devicetree, so there are probably
> some violations, but something like:
> 
> display-pipelines {
>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> &crtc-x &crtc-y>;
>   pipe1 {
>     bridge = <&bridge-a>;
>     encoder = <&encoder-x>;
>     crtc = <&crtc-y>;
>   };
>   pipe2 {
>     encoder = <&encoder-x>;
>     crtc = <&crtc-x>;
>   };
>   pipe3 {
>     panel = <&panel-a>;
>     encoder = <&encoder-y>;
>     crtc = <&crtc-y>;
>   };
> };
> 
> I'm tempted to add connector to the pipe nodes as well, so it's
> obvious which connector should be used in cases where multiple
> entities in the pipe implement drm_connector. However, I'm not sure if
> that would be NACKed by dt people.
> 
> I'm also not sure if there are too many combinations for i915 and
> radeon to make this unreasonable. I suppose those devices could just
> use required-elements and leave the pipe nodes out.

Just to put my two cents in, as one of the people involved into "the 
device tree movement", I'd say that instead of creating artifical 
entities, such as display-pipelines and all of the pipeX'es, device tree 
should represent relations between nodes.

According to the generic DT bindings we already have for video-interfaces 
[1] your example connection layout would look as follows:

panel-a {
	/* Single input port */
	port {
		panel_a: endpoint@0 {
			remote-endpoint = <&encoder_y_out>;
		};
	};
};

bridge-a {
	ports {
		/* Input port */
		port@0 {
			bridge_a_in: endpoint@0 {
				remote-endpoint = <&encoder_x_out>;
			};
		};

		/*
		 * Since it is a bridge, port@1 should be probably
		 * present here as well...
		 */
	};
};

encoder-x {
	ports {
		/* Input port */
		port@0 {
			encoder_x_in0: endpoint@0 {
				remote-endpoint = <&crtc_x>;
			};

			encoder_x_in1: endpoint@1 {
				remote-endpoint = <&crtc_y_out0>;
			};
		};

		/* Output port */
		port@1 {
			encoder_x_out: endpoint@0 {
				remote-endpoint = <&bridge_a_in>;
			};
		};
	};
};

encoder-y {
	ports {
		/* Input port */
		port@0 {
			encoder_y_in: endpoint@0 {
				remote-endpoint = <&encoder_y_in>;
			};
		};

		/* Output port */
		port@1 {
			encoder_y_out: endpoint@0 {
				remote-endpoint = <&panel_a>;
			};
		};
	};
};

crtc-x {
	/* Single output port */
	port {
		crtc_x: endpoint@0 {
			remote-endpoint = <&encoder_x_in0>;
		};
	};
};

crtc-y {
	/* Single output port */
	port {
		crtc_y_out0: endpoint@0 {
			remote-endpoint = <&encoder_x_in1>;
		};

		crtc_y_out1: endpoint@1 {
			remote-endpoint = <&encoder_y_in>;
		};
	};
};

If I didn't make any typos, then the nodes above should not only represent 
fully the layout of your sample video pipelines, but also map connections 
between video entities with their physical endpoints, allowing respective 
drivers to properly configure any muxes based purely on DT data. Of course 
this also includes dependencies between all display entities.

[1] Documentation/devicetree/bindings/media/video-interfaces.txt

Best regards,
Tomasz

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-28 23:13                                                   ` Tomasz Figa
@ 2013-10-29 19:19                                                     ` Olof Johansson
  2013-10-29 19:23                                                       ` Tomasz Figa
  2013-10-29 20:36                                                     ` Sean Paul
  1 sibling, 1 reply; 93+ messages in thread
From: Olof Johansson @ 2013-10-29 19:19 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart,
	DRI mailing list

On Mon, Oct 28, 2013 at 4:13 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi,
>
> On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
>> >>>>> I think we need to start considering a framework where subdrivers
>> >>>>> just
>> >>>>> add drm objects themselves, then the toplevel node is responsible
>> >>>>> for
>> >>>>> knowing that everything for the current configuration is loaded.
>> >>>>
>> >>>> It would be nice to specify the various pieces in dt, then have
>> >>>> some
>> >>>> type of drm notifier to the toplevel node when everything has been
>> >>>> probed. Doing it in the dt would allow standalone
>> >>>> drm_bridge/drm_panel
>> >>>> drivers to be transparent as far as the device's drm driver is
>> >>>> concerned.
>> >>>>
>> >>>> Sean
>> >>>>
>> >>>>> I realise we may need to make changes to the core drm to allow
>> >>>>> this
>> >>>>> but we should probably start to create a strategy for fixing the
>> >>>>> API
>> >>>>> issues that this throws up.
>> >>>>>
>> >>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>> >>>>> device is in use, or removing them.
>> >>>
>> >>> I do wonder if we had some sort of tag in the device tree for any
>> >>> nodes
>> >>> involved in the display, and the core drm layer would read that
>> >>> list,
>> >>> and when every driver registers tick things off, and when the last
>> >>> one
>> >>> joins we get a callback and init the drm layer, we'd of course have
>> >>> the
>> >>> basic drm layer setup prior to that so we can add the objects as the
>> >>> drivers load. It might make development a bit trickier as you'd need
>> >>> to make sure someone claimed ownership of all the bits for init to
>> >>> proceed.>>
>> >> Yeah, that's basically what the strawman looked like in my head.
>> >>
>> >> Instead of a property in each node, I was thinking of having a
>> >> separate gfx pipe nodes that would have dt pointers to the various
>> >> pieces involved in that pipe. This would allow us to associate
>> >> standalone entities like bridges and panels with encoders in dt w/o
>> >> doing it in the drm code. I *think* this should be Ok with the dt
>> >> guys
>> >> since it is still describing the hardware, but I think we'd have to
>> >> make sure it wasn't drm-specific.
>> >
>> > I suppose the question is how much dynamic pipeline construction there
>> > is,
>> >
>> > even on things like radeon and i915 we have dynamic clock generator to
>> > crtc to encoder setups, so I worry about static lists per-pipe, so I
>> > still think just stating all these devices are needed for display and
>> > a list of valid interconnections between them, then we can have the
>> > generic code model drm crtc/encoders/connectors on that list, and
>> > construct the possible_crtcs /possible_clones etc at that stage.
>>
>> I'm, without excuse, hopeless at devicetree, so there are probably
>> some violations, but something like:
>>
>> display-pipelines {
>>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> &crtc-x &crtc-y>;
>>   pipe1 {
>>     bridge = <&bridge-a>;
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-y>;
>>   };
>>   pipe2 {
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-x>;
>>   };
>>   pipe3 {
>>     panel = <&panel-a>;
>>     encoder = <&encoder-y>;
>>     crtc = <&crtc-y>;
>>   };
>> };
>>
>> I'm tempted to add connector to the pipe nodes as well, so it's
>> obvious which connector should be used in cases where multiple
>> entities in the pipe implement drm_connector. However, I'm not sure if
>> that would be NACKed by dt people.
>>
>> I'm also not sure if there are too many combinations for i915 and
>> radeon to make this unreasonable. I suppose those devices could just
>> use required-elements and leave the pipe nodes out.
>
> Just to put my two cents in, as one of the people involved into "the
> device tree movement", I'd say that instead of creating artifical
> entities, such as display-pipelines and all of the pipeX'es, device tree
> should represent relations between nodes.
>
> According to the generic DT bindings we already have for video-interfaces
> [1] your example connection layout would look as follows:
>
> panel-a {
>         /* Single input port */
>         port {
>                 panel_a: endpoint@0 {
>                         remote-endpoint = <&encoder_y_out>;
>                 };
>         };
> };
>
> bridge-a {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         bridge_a_in: endpoint@0 {
>                                 remote-endpoint = <&encoder_x_out>;
>                         };
>                 };
>
>                 /*
>                  * Since it is a bridge, port@1 should be probably
>                  * present here as well...
>                  */
>         };
> };
>
> encoder-x {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         encoder_x_in0: endpoint@0 {
>                                 remote-endpoint = <&crtc_x>;
>                         };
>
>                         encoder_x_in1: endpoint@1 {
>                                 remote-endpoint = <&crtc_y_out0>;
>                         };
>                 };
>
>                 /* Output port */
>                 port@1 {
>                         encoder_x_out: endpoint@0 {
>                                 remote-endpoint = <&bridge_a_in>;
>                         };
>                 };
>         };
> };
>
> encoder-y {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         encoder_y_in: endpoint@0 {
>                                 remote-endpoint = <&encoder_y_in>;
>                         };
>                 };
>
>                 /* Output port */
>                 port@1 {
>                         encoder_y_out: endpoint@0 {
>                                 remote-endpoint = <&panel_a>;
>                         };
>                 };
>         };
> };
>
> crtc-x {
>         /* Single output port */
>         port {
>                 crtc_x: endpoint@0 {
>                         remote-endpoint = <&encoder_x_in0>;
>                 };
>         };
> };
>
> crtc-y {
>         /* Single output port */
>         port {
>                 crtc_y_out0: endpoint@0 {
>                         remote-endpoint = <&encoder_x_in1>;
>                 };
>
>                 crtc_y_out1: endpoint@1 {
>                         remote-endpoint = <&encoder_y_in>;
>                 };
>         };
> };
>
> If I didn't make any typos, then the nodes above should not only represent
> fully the layout of your sample video pipelines, but also map connections
> between video entities with their physical endpoints, allowing respective
> drivers to properly configure any muxes based purely on DT data. Of course
> this also includes dependencies between all display entities.


It's a very deeply nested structure, I'm not sure there's a need to
make a ports {} subnode really.

Also, I don't know if it makes sense to always name it
remote-endpoint, or to use a more flexible name depending on what is
actually connected, over which bus, etc.

But overall this looks sane-ish.


-Olof

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 19:19                                                     ` Olof Johansson
@ 2013-10-29 19:23                                                       ` Tomasz Figa
  2013-10-29 19:47                                                         ` Sylwester Nawrocki
  0 siblings, 1 reply; 93+ messages in thread
From: Tomasz Figa @ 2013-10-29 19:23 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart,
	DRI mailing list

On Tuesday 29 of October 2013 12:19:35 Olof Johansson wrote:
> On Mon, Oct 28, 2013 at 4:13 PM, Tomasz Figa <tomasz.figa@gmail.com> 
wrote:
> > Hi,
> > 
> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> 
wrote:
> >> >>>>> I think we need to start considering a framework where
> >> >>>>> subdrivers
> >> >>>>> just
> >> >>>>> add drm objects themselves, then the toplevel node is
> >> >>>>> responsible
> >> >>>>> for
> >> >>>>> knowing that everything for the current configuration is
> >> >>>>> loaded.
> >> >>>> 
> >> >>>> It would be nice to specify the various pieces in dt, then have
> >> >>>> some
> >> >>>> type of drm notifier to the toplevel node when everything has
> >> >>>> been
> >> >>>> probed. Doing it in the dt would allow standalone
> >> >>>> drm_bridge/drm_panel
> >> >>>> drivers to be transparent as far as the device's drm driver is
> >> >>>> concerned.
> >> >>>> 
> >> >>>> Sean
> >> >>>> 
> >> >>>>> I realise we may need to make changes to the core drm to allow
> >> >>>>> this
> >> >>>>> but we should probably start to create a strategy for fixing
> >> >>>>> the
> >> >>>>> API
> >> >>>>> issues that this throws up.
> >> >>>>> 
> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> >> >>>>> the
> >> >>>>> device is in use, or removing them.
> >> >>> 
> >> >>> I do wonder if we had some sort of tag in the device tree for any
> >> >>> nodes
> >> >>> involved in the display, and the core drm layer would read that
> >> >>> list,
> >> >>> and when every driver registers tick things off, and when the
> >> >>> last
> >> >>> one
> >> >>> joins we get a callback and init the drm layer, we'd of course
> >> >>> have
> >> >>> the
> >> >>> basic drm layer setup prior to that so we can add the objects as
> >> >>> the
> >> >>> drivers load. It might make development a bit trickier as you'd
> >> >>> need
> >> >>> to make sure someone claimed ownership of all the bits for init
> >> >>> to
> >> >>> proceed.>>
> >> >> 
> >> >> Yeah, that's basically what the strawman looked like in my head.
> >> >> 
> >> >> Instead of a property in each node, I was thinking of having a
> >> >> separate gfx pipe nodes that would have dt pointers to the various
> >> >> pieces involved in that pipe. This would allow us to associate
> >> >> standalone entities like bridges and panels with encoders in dt
> >> >> w/o
> >> >> doing it in the drm code. I *think* this should be Ok with the dt
> >> >> guys
> >> >> since it is still describing the hardware, but I think we'd have
> >> >> to
> >> >> make sure it wasn't drm-specific.
> >> > 
> >> > I suppose the question is how much dynamic pipeline construction
> >> > there
> >> > is,
> >> > 
> >> > even on things like radeon and i915 we have dynamic clock generator
> >> > to
> >> > crtc to encoder setups, so I worry about static lists per-pipe, so
> >> > I
> >> > still think just stating all these devices are needed for display
> >> > and
> >> > a list of valid interconnections between them, then we can have the
> >> > generic code model drm crtc/encoders/connectors on that list, and
> >> > construct the possible_crtcs /possible_clones etc at that stage.
> >> 
> >> I'm, without excuse, hopeless at devicetree, so there are probably
> >> some violations, but something like:
> >> 
> >> display-pipelines {
> >> 
> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> >> 
> >> &crtc-x &crtc-y>;
> >> 
> >>   pipe1 {
> >>   
> >>     bridge = <&bridge-a>;
> >>     encoder = <&encoder-x>;
> >>     crtc = <&crtc-y>;
> >>   
> >>   };
> >>   pipe2 {
> >>   
> >>     encoder = <&encoder-x>;
> >>     crtc = <&crtc-x>;
> >>   
> >>   };
> >>   pipe3 {
> >>   
> >>     panel = <&panel-a>;
> >>     encoder = <&encoder-y>;
> >>     crtc = <&crtc-y>;
> >>   
> >>   };
> >> 
> >> };
> >> 
> >> I'm tempted to add connector to the pipe nodes as well, so it's
> >> obvious which connector should be used in cases where multiple
> >> entities in the pipe implement drm_connector. However, I'm not sure
> >> if
> >> that would be NACKed by dt people.
> >> 
> >> I'm also not sure if there are too many combinations for i915 and
> >> radeon to make this unreasonable. I suppose those devices could just
> >> use required-elements and leave the pipe nodes out.
> > 
> > Just to put my two cents in, as one of the people involved into "the
> > device tree movement", I'd say that instead of creating artifical
> > entities, such as display-pipelines and all of the pipeX'es, device
> > tree should represent relations between nodes.
> > 
> > According to the generic DT bindings we already have for
> > video-interfaces [1] your example connection layout would look as
> > follows:
> > 
> > panel-a {
> > 
> >         /* Single input port */
> >         port {
> >         
> >                 panel_a: endpoint@0 {
> >                 
> >                         remote-endpoint = <&encoder_y_out>;
> >                 
> >                 };
> >         
> >         };
> > 
> > };
> > 
> > bridge-a {
> > 
> >         ports {
> >         
> >                 /* Input port */
> >                 port@0 {
> >                 
> >                         bridge_a_in: endpoint@0 {
> >                         
> >                                 remote-endpoint = <&encoder_x_out>;
> >                         
> >                         };
> >                 
> >                 };
> >                 
> >                 /*
> >                 
> >                  * Since it is a bridge, port@1 should be probably
> >                  * present here as well...
> >                  */
> >         
> >         };
> > 
> > };
> > 
> > encoder-x {
> > 
> >         ports {
> >         
> >                 /* Input port */
> >                 port@0 {
> >                 
> >                         encoder_x_in0: endpoint@0 {
> >                         
> >                                 remote-endpoint = <&crtc_x>;
> >                         
> >                         };
> >                         
> >                         encoder_x_in1: endpoint@1 {
> >                         
> >                                 remote-endpoint = <&crtc_y_out0>;
> >                         
> >                         };
> >                 
> >                 };
> >                 
> >                 /* Output port */
> >                 port@1 {
> >                 
> >                         encoder_x_out: endpoint@0 {
> >                         
> >                                 remote-endpoint = <&bridge_a_in>;
> >                         
> >                         };
> >                 
> >                 };
> >         
> >         };
> > 
> > };
> > 
> > encoder-y {
> > 
> >         ports {
> >         
> >                 /* Input port */
> >                 port@0 {
> >                 
> >                         encoder_y_in: endpoint@0 {
> >                         
> >                                 remote-endpoint = <&encoder_y_in>;
> >                         
> >                         };
> >                 
> >                 };
> >                 
> >                 /* Output port */
> >                 port@1 {
> >                 
> >                         encoder_y_out: endpoint@0 {
> >                         
> >                                 remote-endpoint = <&panel_a>;
> >                         
> >                         };
> >                 
> >                 };
> >         
> >         };
> > 
> > };
> > 
> > crtc-x {
> > 
> >         /* Single output port */
> >         port {
> >         
> >                 crtc_x: endpoint@0 {
> >                 
> >                         remote-endpoint = <&encoder_x_in0>;
> >                 
> >                 };
> >         
> >         };
> > 
> > };
> > 
> > crtc-y {
> > 
> >         /* Single output port */
> >         port {
> >         
> >                 crtc_y_out0: endpoint@0 {
> >                 
> >                         remote-endpoint = <&encoder_x_in1>;
> >                 
> >                 };
> >                 
> >                 crtc_y_out1: endpoint@1 {
> >                 
> >                         remote-endpoint = <&encoder_y_in>;
> >                 
> >                 };
> >         
> >         };
> > 
> > };
> > 
> > If I didn't make any typos, then the nodes above should not only
> > represent fully the layout of your sample video pipelines, but also
> > map connections between video entities with their physical endpoints,
> > allowing respective drivers to properly configure any muxes based
> > purely on DT data. Of course this also includes dependencies between
> > all display entities.
> 
> It's a very deeply nested structure, I'm not sure there's a need to
> make a ports {} subnode really.
> 
> Also, I don't know if it makes sense to always name it
> remote-endpoint, or to use a more flexible name depending on what is
> actually connected, over which bus, etc.
>
> But overall this looks sane-ish.

I fully agree with you. Personally I would take a bit different design 
decisions when designing this bindings, but here I'm just pointing an 
already defined binding that should suit the needs described in this 
thread, to avoid reinventing the wheel.

Best regards,
Tomasz

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 19:23                                                       ` Tomasz Figa
@ 2013-10-29 19:47                                                         ` Sylwester Nawrocki
  2013-10-29 23:08                                                           ` Laurent Pinchart
  0 siblings, 1 reply; 93+ messages in thread
From: Sylwester Nawrocki @ 2013-10-29 19:47 UTC (permalink / raw)
  To: Tomasz Figa, Olof Johansson
  Cc: Stéphane Marchesin, Laurent Pinchart, DRI mailing list

Hi,

On 29/10/13 20:23, Tomasz Figa wrote:
>> It's a very deeply nested structure, I'm not sure there's a need to
>> > make a ports {} subnode really.
>> > 
>> > Also, I don't know if it makes sense to always name it
>> > remote-endpoint, or to use a more flexible name depending on what is
>> > actually connected, over which bus, etc.

I have been thinking about a 'bus_type' as an 'endpoint' node property.
Currently the data bus type is derived from selected properties in
endpoint node, which is IMO not good enough.

I'm not sure if naming 'remote-endpoint' differently would be helpful,
as it is now it seems easier to write a generic links parser.

Nevertheless I wish we have defined a bit simplified option in this binding
right from the beginning.

>> > But overall this looks sane-ish.
>
> I fully agree with you. Personally I would take a bit different design 
> decisions when designing this bindings, but here I'm just pointing an 
> already defined binding that should suit the needs described in this 
> thread, to avoid reinventing the wheel.

The 'ports' node is optional. It needs to be used only if, e.g. bridge-a
node contains device child nodes and these sub-nodes use 'reg' property.
In such case #address-cells, #size-cells properties for 'port' nodes could
be conflicting with those for the device child nodes.

Thanks,
Sylwester

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-28 23:13                                                   ` Tomasz Figa
  2013-10-29 19:19                                                     ` Olof Johansson
@ 2013-10-29 20:36                                                     ` Sean Paul
  2013-10-29 20:50                                                       ` Tomasz Figa
  1 sibling, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-29 20:36 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart, dri-devel

On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi,
>
> On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> wrote:
>> >>>>> I think we need to start considering a framework where subdrivers
>> >>>>> just
>> >>>>> add drm objects themselves, then the toplevel node is responsible
>> >>>>> for
>> >>>>> knowing that everything for the current configuration is loaded.
>> >>>>
>> >>>> It would be nice to specify the various pieces in dt, then have
>> >>>> some
>> >>>> type of drm notifier to the toplevel node when everything has been
>> >>>> probed. Doing it in the dt would allow standalone
>> >>>> drm_bridge/drm_panel
>> >>>> drivers to be transparent as far as the device's drm driver is
>> >>>> concerned.
>> >>>>
>> >>>> Sean
>> >>>>
>> >>>>> I realise we may need to make changes to the core drm to allow
>> >>>>> this
>> >>>>> but we should probably start to create a strategy for fixing the
>> >>>>> API
>> >>>>> issues that this throws up.
>> >>>>>
>> >>>>> Note I'm not yet advocating for dynamic addition of nodes once the
>> >>>>> device is in use, or removing them.
>> >>>
>> >>> I do wonder if we had some sort of tag in the device tree for any
>> >>> nodes
>> >>> involved in the display, and the core drm layer would read that
>> >>> list,
>> >>> and when every driver registers tick things off, and when the last
>> >>> one
>> >>> joins we get a callback and init the drm layer, we'd of course have
>> >>> the
>> >>> basic drm layer setup prior to that so we can add the objects as the
>> >>> drivers load. It might make development a bit trickier as you'd need
>> >>> to make sure someone claimed ownership of all the bits for init to
>> >>> proceed.>>
>> >> Yeah, that's basically what the strawman looked like in my head.
>> >>
>> >> Instead of a property in each node, I was thinking of having a
>> >> separate gfx pipe nodes that would have dt pointers to the various
>> >> pieces involved in that pipe. This would allow us to associate
>> >> standalone entities like bridges and panels with encoders in dt w/o
>> >> doing it in the drm code. I *think* this should be Ok with the dt
>> >> guys
>> >> since it is still describing the hardware, but I think we'd have to
>> >> make sure it wasn't drm-specific.
>> >
>> > I suppose the question is how much dynamic pipeline construction there
>> > is,
>> >
>> > even on things like radeon and i915 we have dynamic clock generator to
>> > crtc to encoder setups, so I worry about static lists per-pipe, so I
>> > still think just stating all these devices are needed for display and
>> > a list of valid interconnections between them, then we can have the
>> > generic code model drm crtc/encoders/connectors on that list, and
>> > construct the possible_crtcs /possible_clones etc at that stage.
>>
>> I'm, without excuse, hopeless at devicetree, so there are probably
>> some violations, but something like:
>>
>> display-pipelines {
>>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> &crtc-x &crtc-y>;
>>   pipe1 {
>>     bridge = <&bridge-a>;
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-y>;
>>   };
>>   pipe2 {
>>     encoder = <&encoder-x>;
>>     crtc = <&crtc-x>;
>>   };
>>   pipe3 {
>>     panel = <&panel-a>;
>>     encoder = <&encoder-y>;
>>     crtc = <&crtc-y>;
>>   };
>> };
>>
>> I'm tempted to add connector to the pipe nodes as well, so it's
>> obvious which connector should be used in cases where multiple
>> entities in the pipe implement drm_connector. However, I'm not sure if
>> that would be NACKed by dt people.
>>
>> I'm also not sure if there are too many combinations for i915 and
>> radeon to make this unreasonable. I suppose those devices could just
>> use required-elements and leave the pipe nodes out.
>
> Just to put my two cents in, as one of the people involved into "the
> device tree movement", I'd say that instead of creating artifical
> entities, such as display-pipelines and all of the pipeX'es, device tree
> should represent relations between nodes.
>
> According to the generic DT bindings we already have for video-interfaces
> [1] your example connection layout would look as follows:
>

Hi Tomasz
Thanks for sending this along.

I think the general consensus is that each drm driver should be
implemented as a singular driver. That is, N:1 binding to driver
mapping, where there are N IP blocks. Optional devices (such as
bridges, panels) probably make sense to spin off as standalone
drivers.

An example: exynos_drm_drv would be a platform_driver which implements
drm_driver. On drm_load, it would enumerate the various dt nodes for
its IP blocks and initialize them with direct calls (like
exynos_drm_fimd_initialize). If the board uses a bridge (say for
eDP->LVDS), that bridge driver would be a real driver with its own
probe.

I think the ideal situation would be for the drm layer to manage the
standalone drivers in a way that is transparent to the main driver,
such that it doesn't need to know which type of hardware can hang off
it. It will need to know if one exists since it might need to forego
creating a connector, but it need not know anything else about it.

To accomplish this, I think we need:
 (1) Some way for drm to enumerate the standalone drivers, so it can
know when all of them have been probed
 (2) A drm registration function that's called by the standalone
drivers once they're probed, and a hook with drm_device pointer called
during drm_load for them to register their drm_* implementations
 (3) Something that will allow for deferred probe if the main driver
kicks off before the standalones are in, it would need to be called
before drm_platform/pci_init

I think we'll need to expand on the media bindings to achieve (1). I'm
not sure what the best way to tease out the standalone devices would
be.

Sean



> panel-a {
>         /* Single input port */
>         port {
>                 panel_a: endpoint@0 {
>                         remote-endpoint = <&encoder_y_out>;
>                 };
>         };
> };
>
> bridge-a {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         bridge_a_in: endpoint@0 {
>                                 remote-endpoint = <&encoder_x_out>;
>                         };
>                 };
>
>                 /*
>                  * Since it is a bridge, port@1 should be probably
>                  * present here as well...
>                  */
>         };
> };
>
> encoder-x {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         encoder_x_in0: endpoint@0 {
>                                 remote-endpoint = <&crtc_x>;
>                         };
>
>                         encoder_x_in1: endpoint@1 {
>                                 remote-endpoint = <&crtc_y_out0>;
>                         };
>                 };
>
>                 /* Output port */
>                 port@1 {
>                         encoder_x_out: endpoint@0 {
>                                 remote-endpoint = <&bridge_a_in>;
>                         };
>                 };
>         };
> };
>
> encoder-y {
>         ports {
>                 /* Input port */
>                 port@0 {
>                         encoder_y_in: endpoint@0 {
>                                 remote-endpoint = <&encoder_y_in>;
>                         };
>                 };
>
>                 /* Output port */
>                 port@1 {
>                         encoder_y_out: endpoint@0 {
>                                 remote-endpoint = <&panel_a>;
>                         };
>                 };
>         };
> };
>
> crtc-x {
>         /* Single output port */
>         port {
>                 crtc_x: endpoint@0 {
>                         remote-endpoint = <&encoder_x_in0>;
>                 };
>         };
> };
>
> crtc-y {
>         /* Single output port */
>         port {
>                 crtc_y_out0: endpoint@0 {
>                         remote-endpoint = <&encoder_x_in1>;
>                 };
>
>                 crtc_y_out1: endpoint@1 {
>                         remote-endpoint = <&encoder_y_in>;
>                 };
>         };
> };
>
> If I didn't make any typos, then the nodes above should not only represent
> fully the layout of your sample video pipelines, but also map connections
> between video entities with their physical endpoints, allowing respective
> drivers to properly configure any muxes based purely on DT data. Of course
> this also includes dependencies between all display entities.
>
> [1] Documentation/devicetree/bindings/media/video-interfaces.txt
>
> Best regards,
> Tomasz
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 20:36                                                     ` Sean Paul
@ 2013-10-29 20:50                                                       ` Tomasz Figa
  2013-10-29 21:29                                                         ` Rob Clark
                                                                           ` (2 more replies)
  0 siblings, 3 replies; 93+ messages in thread
From: Tomasz Figa @ 2013-10-29 20:50 UTC (permalink / raw)
  To: Sean Paul
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart, dri-devel

Hi Sean,

On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com> 
wrote:
> > Hi,
> > 
> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com> 
wrote:
> >> >>>>> I think we need to start considering a framework where
> >> >>>>> subdrivers
> >> >>>>> just
> >> >>>>> add drm objects themselves, then the toplevel node is
> >> >>>>> responsible
> >> >>>>> for
> >> >>>>> knowing that everything for the current configuration is
> >> >>>>> loaded.
> >> >>>> 
> >> >>>> It would be nice to specify the various pieces in dt, then have
> >> >>>> some
> >> >>>> type of drm notifier to the toplevel node when everything has
> >> >>>> been
> >> >>>> probed. Doing it in the dt would allow standalone
> >> >>>> drm_bridge/drm_panel
> >> >>>> drivers to be transparent as far as the device's drm driver is
> >> >>>> concerned.
> >> >>>> 
> >> >>>> Sean
> >> >>>> 
> >> >>>>> I realise we may need to make changes to the core drm to allow
> >> >>>>> this
> >> >>>>> but we should probably start to create a strategy for fixing
> >> >>>>> the
> >> >>>>> API
> >> >>>>> issues that this throws up.
> >> >>>>> 
> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> >> >>>>> the
> >> >>>>> device is in use, or removing them.
> >> >>> 
> >> >>> I do wonder if we had some sort of tag in the device tree for any
> >> >>> nodes
> >> >>> involved in the display, and the core drm layer would read that
> >> >>> list,
> >> >>> and when every driver registers tick things off, and when the
> >> >>> last
> >> >>> one
> >> >>> joins we get a callback and init the drm layer, we'd of course
> >> >>> have
> >> >>> the
> >> >>> basic drm layer setup prior to that so we can add the objects as
> >> >>> the
> >> >>> drivers load. It might make development a bit trickier as you'd
> >> >>> need
> >> >>> to make sure someone claimed ownership of all the bits for init
> >> >>> to
> >> >>> proceed.>>
> >> >> 
> >> >> Yeah, that's basically what the strawman looked like in my head.
> >> >> 
> >> >> Instead of a property in each node, I was thinking of having a
> >> >> separate gfx pipe nodes that would have dt pointers to the various
> >> >> pieces involved in that pipe. This would allow us to associate
> >> >> standalone entities like bridges and panels with encoders in dt
> >> >> w/o
> >> >> doing it in the drm code. I *think* this should be Ok with the dt
> >> >> guys
> >> >> since it is still describing the hardware, but I think we'd have
> >> >> to
> >> >> make sure it wasn't drm-specific.
> >> > 
> >> > I suppose the question is how much dynamic pipeline construction
> >> > there
> >> > is,
> >> > 
> >> > even on things like radeon and i915 we have dynamic clock generator
> >> > to
> >> > crtc to encoder setups, so I worry about static lists per-pipe, so
> >> > I
> >> > still think just stating all these devices are needed for display
> >> > and
> >> > a list of valid interconnections between them, then we can have the
> >> > generic code model drm crtc/encoders/connectors on that list, and
> >> > construct the possible_crtcs /possible_clones etc at that stage.
> >> 
> >> I'm, without excuse, hopeless at devicetree, so there are probably
> >> some violations, but something like:
> >> 
> >> display-pipelines {
> >> 
> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> >> 
> >> &crtc-x &crtc-y>;
> >> 
> >>   pipe1 {
> >>   
> >>     bridge = <&bridge-a>;
> >>     encoder = <&encoder-x>;
> >>     crtc = <&crtc-y>;
> >>   
> >>   };
> >>   pipe2 {
> >>   
> >>     encoder = <&encoder-x>;
> >>     crtc = <&crtc-x>;
> >>   
> >>   };
> >>   pipe3 {
> >>   
> >>     panel = <&panel-a>;
> >>     encoder = <&encoder-y>;
> >>     crtc = <&crtc-y>;
> >>   
> >>   };
> >> 
> >> };
> >> 
> >> I'm tempted to add connector to the pipe nodes as well, so it's
> >> obvious which connector should be used in cases where multiple
> >> entities in the pipe implement drm_connector. However, I'm not sure
> >> if
> >> that would be NACKed by dt people.
> >> 
> >> I'm also not sure if there are too many combinations for i915 and
> >> radeon to make this unreasonable. I suppose those devices could just
> >> use required-elements and leave the pipe nodes out.
> > 
> > Just to put my two cents in, as one of the people involved into "the
> > device tree movement", I'd say that instead of creating artifical
> > entities, such as display-pipelines and all of the pipeX'es, device
> > tree should represent relations between nodes.
> > 
> > According to the generic DT bindings we already have for
> > video-interfaces
> > [1] your example connection layout would look as follows:
> Hi Tomasz
> Thanks for sending this along.
> 
> I think the general consensus is that each drm driver should be
> implemented as a singular driver. That is, N:1 binding to driver
> mapping, where there are N IP blocks. Optional devices (such as
> bridges, panels) probably make sense to spin off as standalone
> drivers.

I believe this is a huge step backwards from current kernel design
standards, which prefer modularity.

Having multiple IPs being part of the DRM subsystem in a SoC, it would be 
nice to have the possibility to compile just a subset of support for them 
into the kernel and load rest of them as modules. (e.g. basic LCD 
controller on a mobile phone compiled in and external connectors, like 
HDMI as modules)

Not even saying that from development perspective, a huge single driver 
would be much more difficult to test and debug, than several smaller 
drivers, which could be developed separately.

Unless there is a misunderstanding here, I think this is broken.

> An example: exynos_drm_drv would be a platform_driver which implements
> drm_driver. On drm_load, it would enumerate the various dt nodes for
> its IP blocks and initialize them with direct calls (like
> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> eDP->LVDS), that bridge driver would be a real driver with its own
> probe.
> 
> I think the ideal situation would be for the drm layer to manage the
> standalone drivers in a way that is transparent to the main driver,
> such that it doesn't need to know which type of hardware can hang off
> it. It will need to know if one exists since it might need to forego
> creating a connector, but it need not know anything else about it.
> 
> To accomplish this, I think we need:
>  (1) Some way for drm to enumerate the standalone drivers, so it can
> know when all of them have been probed
>  (2) A drm registration function that's called by the standalone
> drivers once they're probed, and a hook with drm_device pointer called
> during drm_load for them to register their drm_* implementations
>  (3) Something that will allow for deferred probe if the main driver
> kicks off before the standalones are in, it would need to be called
> before drm_platform/pci_init
> 
> I think we'll need to expand on the media bindings to achieve (1).

Could you elaborate on why you think so?

I believe the video interface bindings contain everything needed for this 
case, except, of course, some device/bus specific parts, but those are to 
be defined by separate device/bus specific bindings.

Best regards,
Tomasz

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 20:50                                                       ` Tomasz Figa
@ 2013-10-29 21:29                                                         ` Rob Clark
  2013-10-29 23:32                                                           ` Laurent Pinchart
  2013-11-04 10:10                                                           ` Thierry Reding
  2013-10-30  3:46                                                         ` Stéphane Marchesin
  2013-10-30 15:32                                                         ` Sean Paul
  2 siblings, 2 replies; 93+ messages in thread
From: Rob Clark @ 2013-10-29 21:29 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Stéphane Marchesin, dri-devel, Laurent Pinchart, Sylwester Nawrocki

On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Sean,
>
> On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
>> On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
> wrote:
>> > Hi,
>> >
>> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
> wrote:
>> >> >>>>> I think we need to start considering a framework where
>> >> >>>>> subdrivers
>> >> >>>>> just
>> >> >>>>> add drm objects themselves, then the toplevel node is
>> >> >>>>> responsible
>> >> >>>>> for
>> >> >>>>> knowing that everything for the current configuration is
>> >> >>>>> loaded.
>> >> >>>>
>> >> >>>> It would be nice to specify the various pieces in dt, then have
>> >> >>>> some
>> >> >>>> type of drm notifier to the toplevel node when everything has
>> >> >>>> been
>> >> >>>> probed. Doing it in the dt would allow standalone
>> >> >>>> drm_bridge/drm_panel
>> >> >>>> drivers to be transparent as far as the device's drm driver is
>> >> >>>> concerned.
>> >> >>>>
>> >> >>>> Sean
>> >> >>>>
>> >> >>>>> I realise we may need to make changes to the core drm to allow
>> >> >>>>> this
>> >> >>>>> but we should probably start to create a strategy for fixing
>> >> >>>>> the
>> >> >>>>> API
>> >> >>>>> issues that this throws up.
>> >> >>>>>
>> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
>> >> >>>>> the
>> >> >>>>> device is in use, or removing them.
>> >> >>>
>> >> >>> I do wonder if we had some sort of tag in the device tree for any
>> >> >>> nodes
>> >> >>> involved in the display, and the core drm layer would read that
>> >> >>> list,
>> >> >>> and when every driver registers tick things off, and when the
>> >> >>> last
>> >> >>> one
>> >> >>> joins we get a callback and init the drm layer, we'd of course
>> >> >>> have
>> >> >>> the
>> >> >>> basic drm layer setup prior to that so we can add the objects as
>> >> >>> the
>> >> >>> drivers load. It might make development a bit trickier as you'd
>> >> >>> need
>> >> >>> to make sure someone claimed ownership of all the bits for init
>> >> >>> to
>> >> >>> proceed.>>
>> >> >>
>> >> >> Yeah, that's basically what the strawman looked like in my head.
>> >> >>
>> >> >> Instead of a property in each node, I was thinking of having a
>> >> >> separate gfx pipe nodes that would have dt pointers to the various
>> >> >> pieces involved in that pipe. This would allow us to associate
>> >> >> standalone entities like bridges and panels with encoders in dt
>> >> >> w/o
>> >> >> doing it in the drm code. I *think* this should be Ok with the dt
>> >> >> guys
>> >> >> since it is still describing the hardware, but I think we'd have
>> >> >> to
>> >> >> make sure it wasn't drm-specific.
>> >> >
>> >> > I suppose the question is how much dynamic pipeline construction
>> >> > there
>> >> > is,
>> >> >
>> >> > even on things like radeon and i915 we have dynamic clock generator
>> >> > to
>> >> > crtc to encoder setups, so I worry about static lists per-pipe, so
>> >> > I
>> >> > still think just stating all these devices are needed for display
>> >> > and
>> >> > a list of valid interconnections between them, then we can have the
>> >> > generic code model drm crtc/encoders/connectors on that list, and
>> >> > construct the possible_crtcs /possible_clones etc at that stage.
>> >>
>> >> I'm, without excuse, hopeless at devicetree, so there are probably
>> >> some violations, but something like:
>> >>
>> >> display-pipelines {
>> >>
>> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> >>
>> >> &crtc-x &crtc-y>;
>> >>
>> >>   pipe1 {
>> >>
>> >>     bridge = <&bridge-a>;
>> >>     encoder = <&encoder-x>;
>> >>     crtc = <&crtc-y>;
>> >>
>> >>   };
>> >>   pipe2 {
>> >>
>> >>     encoder = <&encoder-x>;
>> >>     crtc = <&crtc-x>;
>> >>
>> >>   };
>> >>   pipe3 {
>> >>
>> >>     panel = <&panel-a>;
>> >>     encoder = <&encoder-y>;
>> >>     crtc = <&crtc-y>;
>> >>
>> >>   };
>> >>
>> >> };
>> >>
>> >> I'm tempted to add connector to the pipe nodes as well, so it's
>> >> obvious which connector should be used in cases where multiple
>> >> entities in the pipe implement drm_connector. However, I'm not sure
>> >> if
>> >> that would be NACKed by dt people.
>> >>
>> >> I'm also not sure if there are too many combinations for i915 and
>> >> radeon to make this unreasonable. I suppose those devices could just
>> >> use required-elements and leave the pipe nodes out.
>> >
>> > Just to put my two cents in, as one of the people involved into "the
>> > device tree movement", I'd say that instead of creating artifical
>> > entities, such as display-pipelines and all of the pipeX'es, device
>> > tree should represent relations between nodes.
>> >
>> > According to the generic DT bindings we already have for
>> > video-interfaces
>> > [1] your example connection layout would look as follows:
>> Hi Tomasz
>> Thanks for sending this along.
>>
>> I think the general consensus is that each drm driver should be
>> implemented as a singular driver. That is, N:1 binding to driver
>> mapping, where there are N IP blocks. Optional devices (such as
>> bridges, panels) probably make sense to spin off as standalone
>> drivers.
>
> I believe this is a huge step backwards from current kernel design
> standards, which prefer modularity.

But it makes things behave in the way that userspace expects, which is
more important.

> Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> nice to have the possibility to compile just a subset of support for them
> into the kernel and load rest of them as modules. (e.g. basic LCD
> controller on a mobile phone compiled in and external connectors, like
> HDMI as modules)

I think I've mentioned before, that userspace is not prepared to deal
w/ crtc/encoder/connector's dynamically appearing/disappearing.
Perhaps there are ways to improve that, but I haven't come across
hardware where the hdmi block can actually be dynamically removed.

BR,
-R

> Not even saying that from development perspective, a huge single driver
> would be much more difficult to test and debug, than several smaller
> drivers, which could be developed separately.
>
> Unless there is a misunderstanding here, I think this is broken.
>
>> An example: exynos_drm_drv would be a platform_driver which implements
>> drm_driver. On drm_load, it would enumerate the various dt nodes for
>> its IP blocks and initialize them with direct calls (like
>> exynos_drm_fimd_initialize). If the board uses a bridge (say for
>> eDP->LVDS), that bridge driver would be a real driver with its own
>> probe.
>>
>> I think the ideal situation would be for the drm layer to manage the
>> standalone drivers in a way that is transparent to the main driver,
>> such that it doesn't need to know which type of hardware can hang off
>> it. It will need to know if one exists since it might need to forego
>> creating a connector, but it need not know anything else about it.
>>
>> To accomplish this, I think we need:
>>  (1) Some way for drm to enumerate the standalone drivers, so it can
>> know when all of them have been probed
>>  (2) A drm registration function that's called by the standalone
>> drivers once they're probed, and a hook with drm_device pointer called
>> during drm_load for them to register their drm_* implementations
>>  (3) Something that will allow for deferred probe if the main driver
>> kicks off before the standalones are in, it would need to be called
>> before drm_platform/pci_init
>>
>> I think we'll need to expand on the media bindings to achieve (1).
>
> Could you elaborate on why you think so?
>
> I believe the video interface bindings contain everything needed for this
> case, except, of course, some device/bus specific parts, but those are to
> be defined by separate device/bus specific bindings.
>
> 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] 93+ messages in thread

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 19:47                                                         ` Sylwester Nawrocki
@ 2013-10-29 23:08                                                           ` Laurent Pinchart
  0 siblings, 0 replies; 93+ messages in thread
From: Laurent Pinchart @ 2013-10-29 23:08 UTC (permalink / raw)
  To: Sylwester Nawrocki; +Cc: Stéphane Marchesin, DRI mailing list

Hello,

On Tuesday 29 October 2013 20:47:44 Sylwester Nawrocki wrote:
> On 29/10/13 20:23, Tomasz Figa wrote:
> > On Tuesday 29 of October 2013 12:19:35 Olof Johansson wrote:
> > > It's a very deeply nested structure, I'm not sure there's a need to
> > > make a ports {} subnode really.

Agreed, this can be simplified. We've introduced the ports node to group 
multiple ports when the device tree node that contains them also has child 
devices (which is a pretty uncommon case). When this happens, we need 
potentially different #address-cells values for the ports and for the child 
devices. In all other case the ports node can be omitted and the port nodes 
placed directly as children of the device node.

> > > Also, I don't know if it makes sense to always name it remote-endpoint,
> > > or to use a more flexible name depending on what is actually connected,
> > > over which bus, etc.
> 
> I have been thinking about a 'bus_type' as an 'endpoint' node property.
> Currently the data bus type is derived from selected properties in
> endpoint node, which is IMO not good enough.

I agree, a bus type would be useful. I've also been thinking about adding a 
direction property for ports, although that information could be considered as 
device driver knowledge.

> I'm not sure if naming 'remote-endpoint' differently would be helpful, as it
> is now it seems easier to write a generic links parser.
> 
> Nevertheless I wish we have defined a bit simplified option in this binding
> right from the beginning.

It's not too late to clean it up and create a v2 :-)

> >> > But overall this looks sane-ish.
> > 
> > I fully agree with you. Personally I would take a bit different design
> > decisions when designing this bindings, but here I'm just pointing an
> > already defined binding that should suit the needs described in this
> > thread, to avoid reinventing the wheel.
> 
> The 'ports' node is optional. It needs to be used only if, e.g. bridge-a
> node contains device child nodes and these sub-nodes use 'reg' property.
> In such case #address-cells, #size-cells properties for 'port' nodes could
> be conflicting with those for the device child nodes.

I should have read Sylwester's e-mail completely before writing the same 
explanation above :-)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 21:29                                                         ` Rob Clark
@ 2013-10-29 23:32                                                           ` Laurent Pinchart
  2013-11-04 10:21                                                             ` Thierry Reding
  2013-11-04 10:10                                                           ` Thierry Reding
  1 sibling, 1 reply; 93+ messages in thread
From: Laurent Pinchart @ 2013-10-29 23:32 UTC (permalink / raw)
  To: Rob Clark; +Cc: Stéphane Marchesin, dri-devel, Sylwester Nawrocki

Hello,

On Tuesday 29 October 2013 17:29:55 Rob Clark wrote:
> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa wrote:
> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa wrote:
> >> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> >> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie wrote:
> >> >> >>>>> I think we need to start considering a framework where
> >> >> >>>>> subdrivers just add drm objects themselves, then the toplevel
> >> >> >>>>> node is responsible for knowing that everything for the current
> >> >> >>>>> configuration is loaded.
> >> >> >>>> 
> >> >> >>>> It would be nice to specify the various pieces in dt, then have
> >> >> >>>> some type of drm notifier to the toplevel node when everything
> >> >> >>>> has been probed. Doing it in the dt would allow standalone
> >> >> >>>> drm_bridge/drm_panel drivers to be transparent as far as the
> >> >> >>>> device's drm driver is concerned.
> >> >> >>>> 
> >> >> >>>> Sean
> >> >> >>>> 
> >> >> >>>>> I realise we may need to make changes to the core drm to allow
> >> >> >>>>> this but we should probably start to create a strategy for
> >> >> >>>>> fixing the API issues that this throws up.
> >> >> >>>>> 
> >> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> >> >> >>>>> the device is in use, or removing them.
> >> >> >>> 
> >> >> >>> I do wonder if we had some sort of tag in the device tree for any
> >> >> >>> nodes involved in the display, and the core drm layer would read
> >> >> >>> that list, and when every driver registers tick things off, and
> >> >> >>> when the last one joins we get a callback and init the drm layer,
> >> >> >>> we'd of course have the basic drm layer setup prior to that so we
> >> >> >>> can add the objects as the drivers load. It might make development
> >> >> >>> a bit trickier as you'd need to make sure someone claimed
> >> >> >>> ownership of all the bits for init to proceed.
> >> >> >> 
> >> >> >> Yeah, that's basically what the strawman looked like in my head.
> >> >> >> 
> >> >> >> Instead of a property in each node, I was thinking of having a
> >> >> >> separate gfx pipe nodes that would have dt pointers to the various
> >> >> >> pieces involved in that pipe. This would allow us to associate
> >> >> >> standalone entities like bridges and panels with encoders in dt
> >> >> >> w/o doing it in the drm code. I *think* this should be Ok with the
> >> >> >> dt guys since it is still describing the hardware, but I think we'd
> >> >> >> have to make sure it wasn't drm-specific.
> >> >> > 
> >> >> > I suppose the question is how much dynamic pipeline construction
> >> >> > there is, even on things like radeon and i915 we have dynamic clock
> >> >> > generator to crtc to encoder setups, so I worry about static lists
> >> >> > per-pipe, so I still think just stating all these devices are needed
> >> >> > for display and a list of valid interconnections between them, then
> >> >> > we can have the generic code model drm crtc/encoders/connectors on
> >> >> > that list, and construct the possible_crtcs /possible_clones etc at
> >> >> > that stage.
> >> >> 
> >> >> I'm, without excuse, hopeless at devicetree, so there are probably
> >> >> some violations, but something like:
> >> >> 
> >> >> display-pipelines {
> >> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> >> >> &crtc-x &crtc-y>;
> >> >> 
> >> >>   pipe1 {
> >> >>     bridge = <&bridge-a>;
> >> >>     encoder = <&encoder-x>;
> >> >>     crtc = <&crtc-y>;
> >> >>   };
> >> >>   pipe2 {
> >> >>     encoder = <&encoder-x>;
> >> >>     crtc = <&crtc-x>;
> >> >>   };
> >> >>   pipe3 {
> >> >>     panel = <&panel-a>;
> >> >>     encoder = <&encoder-y>;
> >> >>     crtc = <&crtc-y>;
> >> >>   };
> >> >> };
> >> >> 
> >> >> I'm tempted to add connector to the pipe nodes as well, so it's
> >> >> obvious which connector should be used in cases where multiple
> >> >> entities in the pipe implement drm_connector. However, I'm not sure
> >> >> if that would be NACKed by dt people.
> >> >> 
> >> >> I'm also not sure if there are too many combinations for i915 and
> >> >> radeon to make this unreasonable. I suppose those devices could just
> >> >> use required-elements and leave the pipe nodes out.
> >> > 
> >> > Just to put my two cents in, as one of the people involved into "the
> >> > device tree movement", I'd say that instead of creating artifical
> >> > entities, such as display-pipelines and all of the pipeX'es, device
> >> > tree should represent relations between nodes.
> >> > 
> >> > According to the generic DT bindings we already have for
> >> > video-interfaces
> >> 
> >> > [1] your example connection layout would look as follows:
> >> Hi Tomasz
> >> Thanks for sending this along.
> >> 
> >> I think the general consensus is that each drm driver should be
> >> implemented as a singular driver. That is, N:1 binding to driver
> >> mapping, where there are N IP blocks. Optional devices (such as
> >> bridges, panels) probably make sense to spin off as standalone
> >> drivers.
> > 
> > I believe this is a huge step backwards from current kernel design
> > standards, which prefer modularity.

I'd like to adopt a middle ground position on this matter.

Without a doubt external I2C devices will have their own device tree node, 
separate from the display controller node(s). I believe we've settled on that.

At the other extreme, it makes no sense to handle IP cores that are tightly 
coupled with separate device instances (and possibly separate drivers). A 
display controller with a CRTC that includes a scaler that shares many 
configuration registers with the scanout engine shouldn't be created from two 
devices.

What's left to debate is everything in-between. I believe than an on-SoC HDMI 
encoder that is completely decoupled from the display controller (different 
reigster space, different clocks, different power domain, ...) should be 
modeled as a separate device, especially if that IP core is used in other SoCs 
with different display controllers. I'm also ready to ultimately accept the 
driver author's decision to tightly couple the two drivers. We can probably 
come up with several guidelines to help taking decisions, but there will be no 
strict one-size-fits-them-all rule we can apply here, especially before 
gaining experience from applying the model to several drivers. I'm not too 
worried, I believe we'll be able to take the right path along the way.

> But it makes things behave in the way that userspace expects, which is
> more important.
> 
> > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> > nice to have the possibility to compile just a subset of support for them
> > into the kernel and load rest of them as modules. (e.g. basic LCD
> > controller on a mobile phone compiled in and external connectors, like
> > HDMI as modules)
> 
> I think I've mentioned before, that userspace is not prepared to deal
> w/ crtc/encoder/connector's dynamically appearing/disappearing.
> Perhaps there are ways to improve that, but I haven't come across
> hardware where the hdmi block can actually be dynamically removed.

Userspace will need to prepare for that in the longer term, as we'll likely 
see more needs for highly dynamic pipelines (one such use case is partial 
reconfiguration in FPGA: albeit marginal today, we can't just ignore it in the 
long term). I don't want to solve this problem now though (even CDF made no 
attempt at doing so ;-)).

> > Not even saying that from development perspective, a huge single driver
> > would be much more difficult to test and debug, than several smaller
> > drivers, which could be developed separately.
> > 
> > Unless there is a misunderstanding here, I think this is broken.
> > 
> >> An example: exynos_drm_drv would be a platform_driver which implements
> >> drm_driver. On drm_load, it would enumerate the various dt nodes for
> >> its IP blocks and initialize them with direct calls (like
> >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> >> eDP->LVDS), that bridge driver would be a real driver with its own
> >> probe.
> >> 
> >> I think the ideal situation would be for the drm layer to manage the
> >> standalone drivers in a way that is transparent to the main driver,
> >> such that it doesn't need to know which type of hardware can hang off
> >> it. It will need to know if one exists since it might need to forego
> >> creating a connector, but it need not know anything else about it.
> >> 
> >> To accomplish this, I think we need:
> >>
> >> (1) Some way for drm to enumerate the standalone drivers, so it can
> >> know when all of them have been probed
> >> 
> >> (2) A drm registration function that's called by the standalone
> >> drivers once they're probed, and a hook with drm_device pointer called
> >> during drm_load for them to register their drm_* implementations
> >> 
> >> (3) Something that will allow for deferred probe if the main driver
> >> kicks off before the standalones are in, it would need to be called
> >> before drm_platform/pci_init

I believe we should defer probing of the sub-drivers only, as we could run 
into a circular dependency issue if we defer probing on all sides. The main 
driver should use a notification mechanism instead. This idea has been 
discussed during the kernel summit and seemed to not have caused a strong 
disagreement.

I will give this a try, given that I already have a working implementation as 
part of my CDF RFC. I "just" need to extract it as a standalone change (BTW, I 
wish people would have read the CDF RFC in a bit more details, as it contains 
ideas that have been proposed on the list by other developers during the last 
couple of weeks. It's both saddening and slightly offending to post ideas that 
get ignored because of disagreements on the big picture and see them proposed 
as brand new later on).

> >> I think we'll need to expand on the media bindings to achieve (1).
> > 
> > Could you elaborate on why you think so?
> > 
> > I believe the video interface bindings contain everything needed for this
> > case, except, of course, some device/bus specific parts, but those are to
> > be defined by separate device/bus specific bindings.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 20:50                                                       ` Tomasz Figa
  2013-10-29 21:29                                                         ` Rob Clark
@ 2013-10-30  3:46                                                         ` Stéphane Marchesin
  2013-11-04 10:25                                                           ` Thierry Reding
  2013-10-30 15:32                                                         ` Sean Paul
  2 siblings, 1 reply; 93+ messages in thread
From: Stéphane Marchesin @ 2013-10-30  3:46 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Stéphane Marchesin, dri-devel, Laurent Pinchart, Sylwester Nawrocki


[-- Attachment #1.1: Type: text/plain, Size: 8650 bytes --]

On Tue, Oct 29, 2013 at 1:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:

> Hi Sean,
>
> On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
> wrote:
> > > Hi,
> > >
> > > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> > >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
> wrote:
> > >> >>>>> I think we need to start considering a framework where
> > >> >>>>> subdrivers
> > >> >>>>> just
> > >> >>>>> add drm objects themselves, then the toplevel node is
> > >> >>>>> responsible
> > >> >>>>> for
> > >> >>>>> knowing that everything for the current configuration is
> > >> >>>>> loaded.
> > >> >>>>
> > >> >>>> It would be nice to specify the various pieces in dt, then have
> > >> >>>> some
> > >> >>>> type of drm notifier to the toplevel node when everything has
> > >> >>>> been
> > >> >>>> probed. Doing it in the dt would allow standalone
> > >> >>>> drm_bridge/drm_panel
> > >> >>>> drivers to be transparent as far as the device's drm driver is
> > >> >>>> concerned.
> > >> >>>>
> > >> >>>> Sean
> > >> >>>>
> > >> >>>>> I realise we may need to make changes to the core drm to allow
> > >> >>>>> this
> > >> >>>>> but we should probably start to create a strategy for fixing
> > >> >>>>> the
> > >> >>>>> API
> > >> >>>>> issues that this throws up.
> > >> >>>>>
> > >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> > >> >>>>> the
> > >> >>>>> device is in use, or removing them.
> > >> >>>
> > >> >>> I do wonder if we had some sort of tag in the device tree for any
> > >> >>> nodes
> > >> >>> involved in the display, and the core drm layer would read that
> > >> >>> list,
> > >> >>> and when every driver registers tick things off, and when the
> > >> >>> last
> > >> >>> one
> > >> >>> joins we get a callback and init the drm layer, we'd of course
> > >> >>> have
> > >> >>> the
> > >> >>> basic drm layer setup prior to that so we can add the objects as
> > >> >>> the
> > >> >>> drivers load. It might make development a bit trickier as you'd
> > >> >>> need
> > >> >>> to make sure someone claimed ownership of all the bits for init
> > >> >>> to
> > >> >>> proceed.>>
> > >> >>
> > >> >> Yeah, that's basically what the strawman looked like in my head.
> > >> >>
> > >> >> Instead of a property in each node, I was thinking of having a
> > >> >> separate gfx pipe nodes that would have dt pointers to the various
> > >> >> pieces involved in that pipe. This would allow us to associate
> > >> >> standalone entities like bridges and panels with encoders in dt
> > >> >> w/o
> > >> >> doing it in the drm code. I *think* this should be Ok with the dt
> > >> >> guys
> > >> >> since it is still describing the hardware, but I think we'd have
> > >> >> to
> > >> >> make sure it wasn't drm-specific.
> > >> >
> > >> > I suppose the question is how much dynamic pipeline construction
> > >> > there
> > >> > is,
> > >> >
> > >> > even on things like radeon and i915 we have dynamic clock generator
> > >> > to
> > >> > crtc to encoder setups, so I worry about static lists per-pipe, so
> > >> > I
> > >> > still think just stating all these devices are needed for display
> > >> > and
> > >> > a list of valid interconnections between them, then we can have the
> > >> > generic code model drm crtc/encoders/connectors on that list, and
> > >> > construct the possible_crtcs /possible_clones etc at that stage.
> > >>
> > >> I'm, without excuse, hopeless at devicetree, so there are probably
> > >> some violations, but something like:
> > >>
> > >> display-pipelines {
> > >>
> > >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> > >>
> > >> &crtc-x &crtc-y>;
> > >>
> > >>   pipe1 {
> > >>
> > >>     bridge = <&bridge-a>;
> > >>     encoder = <&encoder-x>;
> > >>     crtc = <&crtc-y>;
> > >>
> > >>   };
> > >>   pipe2 {
> > >>
> > >>     encoder = <&encoder-x>;
> > >>     crtc = <&crtc-x>;
> > >>
> > >>   };
> > >>   pipe3 {
> > >>
> > >>     panel = <&panel-a>;
> > >>     encoder = <&encoder-y>;
> > >>     crtc = <&crtc-y>;
> > >>
> > >>   };
> > >>
> > >> };
> > >>
> > >> I'm tempted to add connector to the pipe nodes as well, so it's
> > >> obvious which connector should be used in cases where multiple
> > >> entities in the pipe implement drm_connector. However, I'm not sure
> > >> if
> > >> that would be NACKed by dt people.
> > >>
> > >> I'm also not sure if there are too many combinations for i915 and
> > >> radeon to make this unreasonable. I suppose those devices could just
> > >> use required-elements and leave the pipe nodes out.
> > >
> > > Just to put my two cents in, as one of the people involved into "the
> > > device tree movement", I'd say that instead of creating artifical
> > > entities, such as display-pipelines and all of the pipeX'es, device
> > > tree should represent relations between nodes.
> > >
> > > According to the generic DT bindings we already have for
> > > video-interfaces
> > > [1] your example connection layout would look as follows:
> > Hi Tomasz
> > Thanks for sending this along.
> >
> > I think the general consensus is that each drm driver should be
> > implemented as a singular driver. That is, N:1 binding to driver
> > mapping, where there are N IP blocks. Optional devices (such as
> > bridges, panels) probably make sense to spin off as standalone
> > drivers.
>
> I believe this is a huge step backwards from current kernel design
> standards, which prefer modularity.
>
> Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> nice to have the possibility to compile just a subset of support for them
> into the kernel and load rest of them as modules. (e.g. basic LCD
> controller on a mobile phone compiled in and external connectors, like
> HDMI as modules)
>
> Not even saying that from development perspective, a huge single driver
> would be much more difficult to test and debug, than several smaller
> drivers, which could be developed separately.
>

This is the opposite of our experience, though. A series of small drivers
like what's in drm/exynos can become really tedious/difficult to
coordinate. If you have separate drivers, everything needs to be
synchronized, but also has to account for potentially different loading
order.

It seems you're only thinking about the basic case, where you only support
a single resolution, no dpms, no suspend to ram... But when you want full
fledged functionality, then the issues I described become much more
prevalent.

Stéphane


>
> Unless there is a misunderstanding here, I think this is broken.
>
> > An example: exynos_drm_drv would be a platform_driver which implements
> > drm_driver. On drm_load, it would enumerate the various dt nodes for
> > its IP blocks and initialize them with direct calls (like
> > exynos_drm_fimd_initialize). If the board uses a bridge (say for
> > eDP->LVDS), that bridge driver would be a real driver with its own
> > probe.
> >
> > I think the ideal situation would be for the drm layer to manage the
> > standalone drivers in a way that is transparent to the main driver,
> > such that it doesn't need to know which type of hardware can hang off
> > it. It will need to know if one exists since it might need to forego
> > creating a connector, but it need not know anything else about it.
> >
> > To accomplish this, I think we need:
> >  (1) Some way for drm to enumerate the standalone drivers, so it can
> > know when all of them have been probed
> >  (2) A drm registration function that's called by the standalone
> > drivers once they're probed, and a hook with drm_device pointer called
> > during drm_load for them to register their drm_* implementations
> >  (3) Something that will allow for deferred probe if the main driver
> > kicks off before the standalones are in, it would need to be called
> > before drm_platform/pci_init
> >
> > I think we'll need to expand on the media bindings to achieve (1).
>
> Could you elaborate on why you think so?
>
> I believe the video interface bindings contain everything needed for this
> case, except, of course, some device/bus specific parts, but those are to
> be defined by separate device/bus specific bindings.
>
> Best regards,
> Tomasz
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

[-- Attachment #1.2: Type: text/html, Size: 12022 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 20:50                                                       ` Tomasz Figa
  2013-10-29 21:29                                                         ` Rob Clark
  2013-10-30  3:46                                                         ` Stéphane Marchesin
@ 2013-10-30 15:32                                                         ` Sean Paul
  2013-10-30 15:45                                                           ` Laurent Pinchart
                                                                             ` (2 more replies)
  2 siblings, 3 replies; 93+ messages in thread
From: Sean Paul @ 2013-10-30 15:32 UTC (permalink / raw)
  To: Tomasz Figa
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart, dri-devel

On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> Hi Sean,
>
> On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
>> On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
> wrote:
>> > Hi,
>> >
>> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
> wrote:
>> >> >>>>> I think we need to start considering a framework where
>> >> >>>>> subdrivers
>> >> >>>>> just
>> >> >>>>> add drm objects themselves, then the toplevel node is
>> >> >>>>> responsible
>> >> >>>>> for
>> >> >>>>> knowing that everything for the current configuration is
>> >> >>>>> loaded.
>> >> >>>>
>> >> >>>> It would be nice to specify the various pieces in dt, then have
>> >> >>>> some
>> >> >>>> type of drm notifier to the toplevel node when everything has
>> >> >>>> been
>> >> >>>> probed. Doing it in the dt would allow standalone
>> >> >>>> drm_bridge/drm_panel
>> >> >>>> drivers to be transparent as far as the device's drm driver is
>> >> >>>> concerned.
>> >> >>>>
>> >> >>>> Sean
>> >> >>>>
>> >> >>>>> I realise we may need to make changes to the core drm to allow
>> >> >>>>> this
>> >> >>>>> but we should probably start to create a strategy for fixing
>> >> >>>>> the
>> >> >>>>> API
>> >> >>>>> issues that this throws up.
>> >> >>>>>
>> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
>> >> >>>>> the
>> >> >>>>> device is in use, or removing them.
>> >> >>>
>> >> >>> I do wonder if we had some sort of tag in the device tree for any
>> >> >>> nodes
>> >> >>> involved in the display, and the core drm layer would read that
>> >> >>> list,
>> >> >>> and when every driver registers tick things off, and when the
>> >> >>> last
>> >> >>> one
>> >> >>> joins we get a callback and init the drm layer, we'd of course
>> >> >>> have
>> >> >>> the
>> >> >>> basic drm layer setup prior to that so we can add the objects as
>> >> >>> the
>> >> >>> drivers load. It might make development a bit trickier as you'd
>> >> >>> need
>> >> >>> to make sure someone claimed ownership of all the bits for init
>> >> >>> to
>> >> >>> proceed.>>
>> >> >>
>> >> >> Yeah, that's basically what the strawman looked like in my head.
>> >> >>
>> >> >> Instead of a property in each node, I was thinking of having a
>> >> >> separate gfx pipe nodes that would have dt pointers to the various
>> >> >> pieces involved in that pipe. This would allow us to associate
>> >> >> standalone entities like bridges and panels with encoders in dt
>> >> >> w/o
>> >> >> doing it in the drm code. I *think* this should be Ok with the dt
>> >> >> guys
>> >> >> since it is still describing the hardware, but I think we'd have
>> >> >> to
>> >> >> make sure it wasn't drm-specific.
>> >> >
>> >> > I suppose the question is how much dynamic pipeline construction
>> >> > there
>> >> > is,
>> >> >
>> >> > even on things like radeon and i915 we have dynamic clock generator
>> >> > to
>> >> > crtc to encoder setups, so I worry about static lists per-pipe, so
>> >> > I
>> >> > still think just stating all these devices are needed for display
>> >> > and
>> >> > a list of valid interconnections between them, then we can have the
>> >> > generic code model drm crtc/encoders/connectors on that list, and
>> >> > construct the possible_crtcs /possible_clones etc at that stage.
>> >>
>> >> I'm, without excuse, hopeless at devicetree, so there are probably
>> >> some violations, but something like:
>> >>
>> >> display-pipelines {
>> >>
>> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> >>
>> >> &crtc-x &crtc-y>;
>> >>
>> >>   pipe1 {
>> >>
>> >>     bridge = <&bridge-a>;
>> >>     encoder = <&encoder-x>;
>> >>     crtc = <&crtc-y>;
>> >>
>> >>   };
>> >>   pipe2 {
>> >>
>> >>     encoder = <&encoder-x>;
>> >>     crtc = <&crtc-x>;
>> >>
>> >>   };
>> >>   pipe3 {
>> >>
>> >>     panel = <&panel-a>;
>> >>     encoder = <&encoder-y>;
>> >>     crtc = <&crtc-y>;
>> >>
>> >>   };
>> >>
>> >> };
>> >>
>> >> I'm tempted to add connector to the pipe nodes as well, so it's
>> >> obvious which connector should be used in cases where multiple
>> >> entities in the pipe implement drm_connector. However, I'm not sure
>> >> if
>> >> that would be NACKed by dt people.
>> >>
>> >> I'm also not sure if there are too many combinations for i915 and
>> >> radeon to make this unreasonable. I suppose those devices could just
>> >> use required-elements and leave the pipe nodes out.
>> >
>> > Just to put my two cents in, as one of the people involved into "the
>> > device tree movement", I'd say that instead of creating artifical
>> > entities, such as display-pipelines and all of the pipeX'es, device
>> > tree should represent relations between nodes.
>> >
>> > According to the generic DT bindings we already have for
>> > video-interfaces
>> > [1] your example connection layout would look as follows:
>> Hi Tomasz
>> Thanks for sending this along.
>>
>> I think the general consensus is that each drm driver should be
>> implemented as a singular driver. That is, N:1 binding to driver
>> mapping, where there are N IP blocks. Optional devices (such as
>> bridges, panels) probably make sense to spin off as standalone
>> drivers.
>
> I believe this is a huge step backwards from current kernel design
> standards, which prefer modularity.
>
> Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> nice to have the possibility to compile just a subset of support for them
> into the kernel and load rest of them as modules. (e.g. basic LCD
> controller on a mobile phone compiled in and external connectors, like
> HDMI as modules)
>
> Not even saying that from development perspective, a huge single driver
> would be much more difficult to test and debug, than several smaller
> drivers, which could be developed separately.
>
> Unless there is a misunderstanding here, I think this is broken.
>

I'll defer to Stéphane's answer here. In theory it sounds good, but
things get messy in practice.

>> An example: exynos_drm_drv would be a platform_driver which implements
>> drm_driver. On drm_load, it would enumerate the various dt nodes for
>> its IP blocks and initialize them with direct calls (like
>> exynos_drm_fimd_initialize). If the board uses a bridge (say for
>> eDP->LVDS), that bridge driver would be a real driver with its own
>> probe.
>>
>> I think the ideal situation would be for the drm layer to manage the
>> standalone drivers in a way that is transparent to the main driver,
>> such that it doesn't need to know which type of hardware can hang off
>> it. It will need to know if one exists since it might need to forego
>> creating a connector, but it need not know anything else about it.
>>
>> To accomplish this, I think we need:
>>  (1) Some way for drm to enumerate the standalone drivers, so it can
>> know when all of them have been probed
>>  (2) A drm registration function that's called by the standalone
>> drivers once they're probed, and a hook with drm_device pointer called
>> during drm_load for them to register their drm_* implementations
>>  (3) Something that will allow for deferred probe if the main driver
>> kicks off before the standalones are in, it would need to be called
>> before drm_platform/pci_init
>>
>> I think we'll need to expand on the media bindings to achieve (1).
>
> Could you elaborate on why you think so?
>
> I believe the video interface bindings contain everything needed for this
> case, except, of course, some device/bus specific parts, but those are to
> be defined by separate device/bus specific bindings.
>

AFAICT, there is no way for drm to enumerate all of the pieces that
need probing before it loads (ie: how do you enumerate all device
nodes with pipe {} subnode[s]). I've given this more thought, and I
think the following could work without forcing unified/split drivers
(ie: it can be left to the driver author to choose).

If there was some way for drm to know all of the pieces that need to
be probed/initialized before calling drm_load, it could provide an API
for various drivers to "claim" nodes. This API would accept the
device_node being claimed as well as an initialize hook that will be
called back to give the standalone driver a pointer to the drm_device.

The main drm driver, which is responsible for calling
drm_platform/pci_init, would claim the nodes it plans on implementing
in the probe. It would then check drm to see if all requred nodes had
been claimed. If they have not been claimed, that probe would defer
and try again later.

Once all required nodes have been "claimed", the main driver's probe
would call drm_platform/pci_init to kick off load(). After load() has
finished, the drm layer would then call the various standalone driver
hooks that were previously registered when it claimed its node. These
hooks would allow the driver to register its
crtc/encoder/bridge/connector.

Multi-driver solutions could work within this framework, as could
integrated ones. This would also allow things like bridge drivers to
be completely transparent.

I hope that made sense ;)

Sean



> Best regards,
> Tomasz
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:32                                                         ` Sean Paul
@ 2013-10-30 15:45                                                           ` Laurent Pinchart
  2013-10-30 15:56                                                             ` Sean Paul
  2013-10-30 15:53                                                           ` Daniel Vetter
  2013-11-04 10:36                                                           ` Thierry Reding
  2 siblings, 1 reply; 93+ messages in thread
From: Laurent Pinchart @ 2013-10-30 15:45 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Grant Likely, Sylwester Nawrocki, Stéphane Marchesin

On Wednesday 30 October 2013 11:32:24 Sean Paul wrote:
> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa wrote:
> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:

[snip]

> >> An example: exynos_drm_drv would be a platform_driver which implements
> >> drm_driver. On drm_load, it would enumerate the various dt nodes for
> >> its IP blocks and initialize them with direct calls (like
> >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> >> eDP->LVDS), that bridge driver would be a real driver with its own
> >> probe.
> >> 
> >> I think the ideal situation would be for the drm layer to manage the
> >> standalone drivers in a way that is transparent to the main driver,
> >> such that it doesn't need to know which type of hardware can hang off
> >> it. It will need to know if one exists since it might need to forego
> >> creating a connector, but it need not know anything else about it.
> >> 
> >> To accomplish this, I think we need:
> >> (1) Some way for drm to enumerate the standalone drivers, so it can
> >> know when all of them have been probed
> >> 
> >> (2) A drm registration function that's called by the standalone
> >> drivers once they're probed, and a hook with drm_device pointer called
> >> during drm_load for them to register their drm_* implementations
> >> 
> >> (3) Something that will allow for deferred probe if the main driver
> >> kicks off before the standalones are in, it would need to be called
> >> before drm_platform/pci_init
> >> 
> >> I think we'll need to expand on the media bindings to achieve (1).
> > 
> > Could you elaborate on why you think so?
> > 
> > I believe the video interface bindings contain everything needed for this
> > case, except, of course, some device/bus specific parts, but those are to
> > be defined by separate device/bus specific bindings.
> 
> AFAICT, there is no way for drm to enumerate all of the pieces that
> need probing before it loads (ie: how do you enumerate all device
> nodes with pipe {} subnode[s]). I've given this more thought, and I
> think the following could work without forcing unified/split drivers
> (ie: it can be left to the driver author to choose).
> 
> If there was some way for drm to know all of the pieces that need to
> be probed/initialized before calling drm_load, it could provide an API
> for various drivers to "claim" nodes. This API would accept the
> device_node being claimed as well as an initialize hook that will be
> called back to give the standalone driver a pointer to the drm_device.
> 
> The main drm driver, which is responsible for calling
> drm_platform/pci_init, would claim the nodes it plans on implementing
> in the probe. It would then check drm to see if all requred nodes had
> been claimed. If they have not been claimed, that probe would defer
> and try again later.
> 
> Once all required nodes have been "claimed", the main driver's probe
> would call drm_platform/pci_init to kick off load(). After load() has
> finished, the drm layer would then call the various standalone driver
> hooks that were previously registered when it claimed its node. These
> hooks would allow the driver to register its
> crtc/encoder/bridge/connector.
> 
> Multi-driver solutions could work within this framework, as could
> integrated ones. This would also allow things like bridge drivers to
> be completely transparent.

Have you all configured your spam filters to reject anything that is or has 
been related to CDF ?

Split in two patches, the first one adding the infrastructure, the second one 
adding OF support.

http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/2d19e74ab8d86aaf5d54c34c6bc940508f793512
http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/e8c4380ca4a6a62fa9d8bc340a6dcbd123b4f674

The code can be extracted as a stand-alone solution, either specific to DRM, 
or at the struct device level. As the problem is not DRM-specific, the later 
would probably make more sense (if I'm not mistaken Grant Likely - CCed- 
mentioned during the kernel summit was in favor of adding the code in the 
device core).

We've solved the exact same problem in V4L, do we *really* need to adopt the 
NIH approach and reinvent the wheel ?

> I hope that made sense ;)

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:32                                                         ` Sean Paul
  2013-10-30 15:45                                                           ` Laurent Pinchart
@ 2013-10-30 15:53                                                           ` Daniel Vetter
  2013-11-04 10:13                                                             ` Laurent Pinchart
  2013-11-04 10:36                                                           ` Thierry Reding
  2 siblings, 1 reply; 93+ messages in thread
From: Daniel Vetter @ 2013-10-30 15:53 UTC (permalink / raw)
  To: Sean Paul
  Cc: Stéphane Marchesin, dri-devel, Sylwester Nawrocki, Laurent Pinchart

On Wed, Oct 30, 2013 at 4:32 PM, Sean Paul <seanpaul@chromium.org> wrote:
> Once all required nodes have been "claimed", the main driver's probe
> would call drm_platform/pci_init to kick off load(). After load() has
> finished, the drm layer would then call the various standalone driver
> hooks that were previously registered when it claimed its node. These
> hooks would allow the driver to register its
> crtc/encoder/bridge/connector.

Just a quick comment on calling the ->driver_load callback: I plan to
look again my "kill drm midlayer" series so that drivers are in full
control of the load sequence. Then they could do whatever delayed
loading the need to do by calling into optional helpers (hopefully
shared with asoc and v4l and other aggregate devices madness) and the
drm core simply does not need to care: The driver only
registers/allocates the drm_device once it's ready to do so.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:45                                                           ` Laurent Pinchart
@ 2013-10-30 15:56                                                             ` Sean Paul
  2013-11-04 10:12                                                               ` Laurent Pinchart
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-10-30 15:56 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: dri-devel, Grant Likely, Sylwester Nawrocki, Stéphane Marchesin

On Wed, Oct 30, 2013 at 11:45 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
> On Wednesday 30 October 2013 11:32:24 Sean Paul wrote:
>> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa wrote:
>> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
>
> [snip]
>
>> >> An example: exynos_drm_drv would be a platform_driver which implements
>> >> drm_driver. On drm_load, it would enumerate the various dt nodes for
>> >> its IP blocks and initialize them with direct calls (like
>> >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
>> >> eDP->LVDS), that bridge driver would be a real driver with its own
>> >> probe.
>> >>
>> >> I think the ideal situation would be for the drm layer to manage the
>> >> standalone drivers in a way that is transparent to the main driver,
>> >> such that it doesn't need to know which type of hardware can hang off
>> >> it. It will need to know if one exists since it might need to forego
>> >> creating a connector, but it need not know anything else about it.
>> >>
>> >> To accomplish this, I think we need:
>> >> (1) Some way for drm to enumerate the standalone drivers, so it can
>> >> know when all of them have been probed
>> >>
>> >> (2) A drm registration function that's called by the standalone
>> >> drivers once they're probed, and a hook with drm_device pointer called
>> >> during drm_load for them to register their drm_* implementations
>> >>
>> >> (3) Something that will allow for deferred probe if the main driver
>> >> kicks off before the standalones are in, it would need to be called
>> >> before drm_platform/pci_init
>> >>
>> >> I think we'll need to expand on the media bindings to achieve (1).
>> >
>> > Could you elaborate on why you think so?
>> >
>> > I believe the video interface bindings contain everything needed for this
>> > case, except, of course, some device/bus specific parts, but those are to
>> > be defined by separate device/bus specific bindings.
>>
>> AFAICT, there is no way for drm to enumerate all of the pieces that
>> need probing before it loads (ie: how do you enumerate all device
>> nodes with pipe {} subnode[s]). I've given this more thought, and I
>> think the following could work without forcing unified/split drivers
>> (ie: it can be left to the driver author to choose).
>>
>> If there was some way for drm to know all of the pieces that need to
>> be probed/initialized before calling drm_load, it could provide an API
>> for various drivers to "claim" nodes. This API would accept the
>> device_node being claimed as well as an initialize hook that will be
>> called back to give the standalone driver a pointer to the drm_device.
>>
>> The main drm driver, which is responsible for calling
>> drm_platform/pci_init, would claim the nodes it plans on implementing
>> in the probe. It would then check drm to see if all requred nodes had
>> been claimed. If they have not been claimed, that probe would defer
>> and try again later.
>>
>> Once all required nodes have been "claimed", the main driver's probe
>> would call drm_platform/pci_init to kick off load(). After load() has
>> finished, the drm layer would then call the various standalone driver
>> hooks that were previously registered when it claimed its node. These
>> hooks would allow the driver to register its
>> crtc/encoder/bridge/connector.
>>
>> Multi-driver solutions could work within this framework, as could
>> integrated ones. This would also allow things like bridge drivers to
>> be completely transparent.
>
> Have you all configured your spam filters to reject anything that is or has
> been related to CDF ?
>
> Split in two patches, the first one adding the infrastructure, the second one
> adding OF support.
>
> http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/2d19e74ab8d86aaf5d54c34c6bc940508f793512
> http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/e8c4380ca4a6a62fa9d8bc340a6dcbd123b4f674
>
> The code can be extracted as a stand-alone solution, either specific to DRM,
> or at the struct device level. As the problem is not DRM-specific, the later
> would probably make more sense (if I'm not mistaken Grant Likely - CCed-
> mentioned during the kernel summit was in favor of adding the code in the
> device core).
>
> We've solved the exact same problem in V4L, do we *really* need to adopt the
> NIH approach and reinvent the wheel ?
>

Laurent,
I really don't care how the functionality gets in, or what form it
takes. This isn't NIH, I just want something that can be merged.

When we talked about CDF at plumbers, I thought the plan was to split
it up into the logical pieces and integrate it into drm. I haven't
seen any movement on this front, is that still your intention? If so,
I look forward to the patch.

Sean



>> I hope that made sense ;)
>
> --
> Regards,
>
> Laurent Pinchart
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-23 15:22                                           ` Dave Airlie
  2013-10-23 15:27                                             ` Rob Clark
  2013-10-23 15:27                                             ` Sean Paul
@ 2013-11-04 10:08                                             ` Thierry Reding
  2 siblings, 0 replies; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 10:08 UTC (permalink / raw)
  To: Dave Airlie; +Cc: Stéphane Marchesin, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 2608 bytes --]

On Wed, Oct 23, 2013 at 04:22:11PM +0100, Dave Airlie wrote:
> On Wed, Oct 23, 2013 at 3:45 PM, Sean Paul <seanpaul@chromium.org> wrote:
> > On Wed, Oct 23, 2013 at 10:29 AM, Dave Airlie <airlied@gmail.com> wrote:
> >>> As I mentioned earlier, display_ops is needed to have no any
> >>> dependency of drm framework directly like below,
> >>>
> >>>                                           DRM Framework
> >>>                                                        |
> >>>                                         Exynos DRM Framework
> >>>                                                     /   |   \
> >>>                                          Real device drivers
> >>>
> >>> In particular, in case of ARM based DRM drivers with separated
> >>> devices, I still tend to think it's better design than that device
> >>> drivers implement the connector callbacks directly, but I will try to
> >>> consider what is the better way.
> >>>
> >>
> >> I think we need to start considering a framework where subdrivers just
> >> add drm objects themselves, then the toplevel node is responsible for
> >> knowing that everything for the current configuration is loaded.
> >>
> >
> > It would be nice to specify the various pieces in dt, then have some
> > type of drm notifier to the toplevel node when everything has been
> > probed. Doing it in the dt would allow standalone drm_bridge/drm_panel
> > drivers to be transparent as far as the device's drm driver is
> > concerned.
> >
> > Sean
> >
> >
> >> I realise we may need to make changes to the core drm to allow this
> >> but we should probably start to create a strategy for fixing the API
> >> issues that this throws up.
> >>
> >> Note I'm not yet advocating for dynamic addition of nodes once the
> >> device is in use, or removing them.
> >>
> 
> I do wonder if we had some sort of tag in the device tree for any nodes
> involved in the display, and the core drm layer would read that list,
> and when every driver registers tick things off, and when the last one
> joins we get a callback and init the drm layer, we'd of course have the
> basic drm layer setup prior to that so we can add the objects as the
> drivers load. It might make development a bit trickier as you'd need
> to make sure someone claimed ownership of all the bits for init to proceed.

I'm curious whether anyone actually ever bothered to look at the Tegra
driver. It pretty much does all of this already.

Granted the hardware may be more friendly than on most other SoCs, but
essentially the problem is the same.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 21:29                                                         ` Rob Clark
  2013-10-29 23:32                                                           ` Laurent Pinchart
@ 2013-11-04 10:10                                                           ` Thierry Reding
  2013-11-04 12:14                                                             ` Rob Clark
  1 sibling, 1 reply; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 10:10 UTC (permalink / raw)
  To: Rob Clark
  Cc: Stéphane Marchesin, Sylwester Nawrocki, dri-devel, Laurent Pinchart


[-- Attachment #1.1: Type: text/plain, Size: 605 bytes --]

On Tue, Oct 29, 2013 at 05:29:55PM -0400, Rob Clark wrote:
> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
[...]
> > I believe this is a huge step backwards from current kernel design
> > standards, which prefer modularity.
> 
> But it makes things behave in the way that userspace expects, which is
> more important.

Why would userspace care about the modularity of kernel drivers? The
only thing that userspace should care about is whether there's a DRM
device or not. How the kernel makes that happen should be completely
irrelevant to userspace.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:56                                                             ` Sean Paul
@ 2013-11-04 10:12                                                               ` Laurent Pinchart
  0 siblings, 0 replies; 93+ messages in thread
From: Laurent Pinchart @ 2013-11-04 10:12 UTC (permalink / raw)
  To: Sean Paul
  Cc: dri-devel, Grant Likely, Sylwester Nawrocki, Stéphane Marchesin

Hi Sean,

Sorry for the late reply.

On Wednesday 30 October 2013 11:56:18 Sean Paul wrote:
> On Wed, Oct 30, 2013 at 11:45 AM, Laurent Pinchart wrote:
> > On Wednesday 30 October 2013 11:32:24 Sean Paul wrote:
> >> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa wrote:
> >> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> > [snip]
> > 
> >> >> An example: exynos_drm_drv would be a platform_driver which implements
> >> >> drm_driver. On drm_load, it would enumerate the various dt nodes for
> >> >> its IP blocks and initialize them with direct calls (like
> >> >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> >> >> eDP->LVDS), that bridge driver would be a real driver with its own
> >> >> probe.
> >> >> 
> >> >> I think the ideal situation would be for the drm layer to manage the
> >> >> standalone drivers in a way that is transparent to the main driver,
> >> >> such that it doesn't need to know which type of hardware can hang off
> >> >> it. It will need to know if one exists since it might need to forego
> >> >> creating a connector, but it need not know anything else about it.
> >> >> 
> >> >> To accomplish this, I think we need:
> >> >> (1) Some way for drm to enumerate the standalone drivers, so it can
> >> >> know when all of them have been probed
> >> >> 
> >> >> (2) A drm registration function that's called by the standalone
> >> >> drivers once they're probed, and a hook with drm_device pointer called
> >> >> during drm_load for them to register their drm_* implementations
> >> >> 
> >> >> (3) Something that will allow for deferred probe if the main driver
> >> >> kicks off before the standalones are in, it would need to be called
> >> >> before drm_platform/pci_init
> >> >> 
> >> >> I think we'll need to expand on the media bindings to achieve (1).
> >> > 
> >> > Could you elaborate on why you think so?
> >> > 
> >> > I believe the video interface bindings contain everything needed for
> >> > this
> >> > case, except, of course, some device/bus specific parts, but those are
> >> > to
> >> > be defined by separate device/bus specific bindings.
> >> 
> >> AFAICT, there is no way for drm to enumerate all of the pieces that
> >> need probing before it loads (ie: how do you enumerate all device
> >> nodes with pipe {} subnode[s]). I've given this more thought, and I
> >> think the following could work without forcing unified/split drivers
> >> (ie: it can be left to the driver author to choose).
> >> 
> >> If there was some way for drm to know all of the pieces that need to
> >> be probed/initialized before calling drm_load, it could provide an API
> >> for various drivers to "claim" nodes. This API would accept the
> >> device_node being claimed as well as an initialize hook that will be
> >> called back to give the standalone driver a pointer to the drm_device.
> >> 
> >> The main drm driver, which is responsible for calling
> >> drm_platform/pci_init, would claim the nodes it plans on implementing
> >> in the probe. It would then check drm to see if all requred nodes had
> >> been claimed. If they have not been claimed, that probe would defer
> >> and try again later.
> >> 
> >> Once all required nodes have been "claimed", the main driver's probe
> >> would call drm_platform/pci_init to kick off load(). After load() has
> >> finished, the drm layer would then call the various standalone driver
> >> hooks that were previously registered when it claimed its node. These
> >> hooks would allow the driver to register its
> >> crtc/encoder/bridge/connector.
> >> 
> >> Multi-driver solutions could work within this framework, as could
> >> integrated ones. This would also allow things like bridge drivers to
> >> be completely transparent.
> > 
> > Have you all configured your spam filters to reject anything that is or
> > has
> > been related to CDF ?
> > 
> > Split in two patches, the first one adding the infrastructure, the second
> > one adding OF support.
> > 
> > http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/2d19e74ab8d86aaf5d54
> > c34c6bc940508f793512
> > http://git.linuxtv.org/pinchartl/fbdev.git/commitdiff/e8c4380ca4a6a62fa9d
> > 8bc340a6dcbd123b4f674
> > 
> > The code can be extracted as a stand-alone solution, either specific to
> > DRM, or at the struct device level. As the problem is not DRM-specific,
> > the later would probably make more sense (if I'm not mistaken Grant
> > Likely - CCed- mentioned during the kernel summit was in favor of adding
> > the code in the device core).
> > 
> > We've solved the exact same problem in V4L, do we *really* need to adopt
> > the NIH approach and reinvent the wheel ?
> 
> Laurent,
> I really don't care how the functionality gets in, or what form it takes.
> This isn't NIH, I just want something that can be merged.

Great :-)

> When we talked about CDF at plumbers, I thought the plan was to split it up
> into the logical pieces and integrate it into drm. I haven't seen any
> movement on this front, is that still your intention? If so, I look forward
> to the patch.

Yes, it's still my intention, and the DT bindings + notifier code will be the 
first piece. I hope to post a first version at the end of the week(end). Sorry 
for the delay.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:53                                                           ` Daniel Vetter
@ 2013-11-04 10:13                                                             ` Laurent Pinchart
  0 siblings, 0 replies; 93+ messages in thread
From: Laurent Pinchart @ 2013-11-04 10:13 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: Stéphane Marchesin, dri-devel, Sylwester Nawrocki

Hi Daniel,

On Wednesday 30 October 2013 16:53:22 Daniel Vetter wrote:
> On Wed, Oct 30, 2013 at 4:32 PM, Sean Paul <seanpaul@chromium.org> wrote:
> > Once all required nodes have been "claimed", the main driver's probe
> > would call drm_platform/pci_init to kick off load(). After load() has
> > finished, the drm layer would then call the various standalone driver
> > hooks that were previously registered when it claimed its node. These
> > hooks would allow the driver to register its
> > crtc/encoder/bridge/connector.
> 
> Just a quick comment on calling the ->driver_load callback: I plan to
> look again my "kill drm midlayer" series so that drivers are in full
> control of the load sequence. Then they could do whatever delayed
> loading the need to do by calling into optional helpers (hopefully
> shared with asoc and v4l and other aggregate devices madness) and the
> drm core simply does not need to care: The driver only
> registers/allocates the drm_device once it's ready to do so.

That would be great ! Please let me know if you would like me to test patches 
with the R-Car DU driver.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-29 23:32                                                           ` Laurent Pinchart
@ 2013-11-04 10:21                                                             ` Thierry Reding
  0 siblings, 0 replies; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 10:21 UTC (permalink / raw)
  To: Laurent Pinchart; +Cc: Stéphane Marchesin, Sylwester Nawrocki, dri-devel


[-- Attachment #1.1: Type: text/plain, Size: 11128 bytes --]

On Wed, Oct 30, 2013 at 12:32:11AM +0100, Laurent Pinchart wrote:
> Hello,
> 
> On Tuesday 29 October 2013 17:29:55 Rob Clark wrote:
> > On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa wrote:
> > > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> > > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa wrote:
> > >> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> > >> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie wrote:
> > >> >> >>>>> I think we need to start considering a framework where
> > >> >> >>>>> subdrivers just add drm objects themselves, then the toplevel
> > >> >> >>>>> node is responsible for knowing that everything for the current
> > >> >> >>>>> configuration is loaded.
> > >> >> >>>> 
> > >> >> >>>> It would be nice to specify the various pieces in dt, then have
> > >> >> >>>> some type of drm notifier to the toplevel node when everything
> > >> >> >>>> has been probed. Doing it in the dt would allow standalone
> > >> >> >>>> drm_bridge/drm_panel drivers to be transparent as far as the
> > >> >> >>>> device's drm driver is concerned.
> > >> >> >>>> 
> > >> >> >>>> Sean
> > >> >> >>>> 
> > >> >> >>>>> I realise we may need to make changes to the core drm to allow
> > >> >> >>>>> this but we should probably start to create a strategy for
> > >> >> >>>>> fixing the API issues that this throws up.
> > >> >> >>>>> 
> > >> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> > >> >> >>>>> the device is in use, or removing them.
> > >> >> >>> 
> > >> >> >>> I do wonder if we had some sort of tag in the device tree for any
> > >> >> >>> nodes involved in the display, and the core drm layer would read
> > >> >> >>> that list, and when every driver registers tick things off, and
> > >> >> >>> when the last one joins we get a callback and init the drm layer,
> > >> >> >>> we'd of course have the basic drm layer setup prior to that so we
> > >> >> >>> can add the objects as the drivers load. It might make development
> > >> >> >>> a bit trickier as you'd need to make sure someone claimed
> > >> >> >>> ownership of all the bits for init to proceed.
> > >> >> >> 
> > >> >> >> Yeah, that's basically what the strawman looked like in my head.
> > >> >> >> 
> > >> >> >> Instead of a property in each node, I was thinking of having a
> > >> >> >> separate gfx pipe nodes that would have dt pointers to the various
> > >> >> >> pieces involved in that pipe. This would allow us to associate
> > >> >> >> standalone entities like bridges and panels with encoders in dt
> > >> >> >> w/o doing it in the drm code. I *think* this should be Ok with the
> > >> >> >> dt guys since it is still describing the hardware, but I think we'd
> > >> >> >> have to make sure it wasn't drm-specific.
> > >> >> > 
> > >> >> > I suppose the question is how much dynamic pipeline construction
> > >> >> > there is, even on things like radeon and i915 we have dynamic clock
> > >> >> > generator to crtc to encoder setups, so I worry about static lists
> > >> >> > per-pipe, so I still think just stating all these devices are needed
> > >> >> > for display and a list of valid interconnections between them, then
> > >> >> > we can have the generic code model drm crtc/encoders/connectors on
> > >> >> > that list, and construct the possible_crtcs /possible_clones etc at
> > >> >> > that stage.
> > >> >> 
> > >> >> I'm, without excuse, hopeless at devicetree, so there are probably
> > >> >> some violations, but something like:
> > >> >> 
> > >> >> display-pipelines {
> > >> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> > >> >> &crtc-x &crtc-y>;
> > >> >> 
> > >> >>   pipe1 {
> > >> >>     bridge = <&bridge-a>;
> > >> >>     encoder = <&encoder-x>;
> > >> >>     crtc = <&crtc-y>;
> > >> >>   };
> > >> >>   pipe2 {
> > >> >>     encoder = <&encoder-x>;
> > >> >>     crtc = <&crtc-x>;
> > >> >>   };
> > >> >>   pipe3 {
> > >> >>     panel = <&panel-a>;
> > >> >>     encoder = <&encoder-y>;
> > >> >>     crtc = <&crtc-y>;
> > >> >>   };
> > >> >> };
> > >> >> 
> > >> >> I'm tempted to add connector to the pipe nodes as well, so it's
> > >> >> obvious which connector should be used in cases where multiple
> > >> >> entities in the pipe implement drm_connector. However, I'm not sure
> > >> >> if that would be NACKed by dt people.
> > >> >> 
> > >> >> I'm also not sure if there are too many combinations for i915 and
> > >> >> radeon to make this unreasonable. I suppose those devices could just
> > >> >> use required-elements and leave the pipe nodes out.
> > >> > 
> > >> > Just to put my two cents in, as one of the people involved into "the
> > >> > device tree movement", I'd say that instead of creating artifical
> > >> > entities, such as display-pipelines and all of the pipeX'es, device
> > >> > tree should represent relations between nodes.
> > >> > 
> > >> > According to the generic DT bindings we already have for
> > >> > video-interfaces
> > >> 
> > >> > [1] your example connection layout would look as follows:
> > >> Hi Tomasz
> > >> Thanks for sending this along.
> > >> 
> > >> I think the general consensus is that each drm driver should be
> > >> implemented as a singular driver. That is, N:1 binding to driver
> > >> mapping, where there are N IP blocks. Optional devices (such as
> > >> bridges, panels) probably make sense to spin off as standalone
> > >> drivers.
> > > 
> > > I believe this is a huge step backwards from current kernel design
> > > standards, which prefer modularity.
> 
> I'd like to adopt a middle ground position on this matter.
> 
> Without a doubt external I2C devices will have their own device tree node, 
> separate from the display controller node(s). I believe we've settled on that.
> 
> At the other extreme, it makes no sense to handle IP cores that are tightly 
> coupled with separate device instances (and possibly separate drivers). A 
> display controller with a CRTC that includes a scaler that shares many 
> configuration registers with the scanout engine shouldn't be created from two 
> devices.
> 
> What's left to debate is everything in-between. I believe than an on-SoC HDMI 
> encoder that is completely decoupled from the display controller (different 
> reigster space, different clocks, different power domain, ...) should be 
> modeled as a separate device, especially if that IP core is used in other SoCs 
> with different display controllers. I'm also ready to ultimately accept the 
> driver author's decision to tightly couple the two drivers. We can probably 
> come up with several guidelines to help taking decisions, but there will be no 
> strict one-size-fits-them-all rule we can apply here, especially before 
> gaining experience from applying the model to several drivers. I'm not too 
> worried, I believe we'll be able to take the right path along the way.
> 
> > But it makes things behave in the way that userspace expects, which is
> > more important.
> > 
> > > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> > > nice to have the possibility to compile just a subset of support for them
> > > into the kernel and load rest of them as modules. (e.g. basic LCD
> > > controller on a mobile phone compiled in and external connectors, like
> > > HDMI as modules)
> > 
> > I think I've mentioned before, that userspace is not prepared to deal
> > w/ crtc/encoder/connector's dynamically appearing/disappearing.
> > Perhaps there are ways to improve that, but I haven't come across
> > hardware where the hdmi block can actually be dynamically removed.
> 
> Userspace will need to prepare for that in the longer term, as we'll likely 
> see more needs for highly dynamic pipelines (one such use case is partial 
> reconfiguration in FPGA: albeit marginal today, we can't just ignore it in the 
> long term). I don't want to solve this problem now though (even CDF made no 
> attempt at doing so ;-)).
> 
> > > Not even saying that from development perspective, a huge single driver
> > > would be much more difficult to test and debug, than several smaller
> > > drivers, which could be developed separately.
> > > 
> > > Unless there is a misunderstanding here, I think this is broken.
> > > 
> > >> An example: exynos_drm_drv would be a platform_driver which implements
> > >> drm_driver. On drm_load, it would enumerate the various dt nodes for
> > >> its IP blocks and initialize them with direct calls (like
> > >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> > >> eDP->LVDS), that bridge driver would be a real driver with its own
> > >> probe.
> > >> 
> > >> I think the ideal situation would be for the drm layer to manage the
> > >> standalone drivers in a way that is transparent to the main driver,
> > >> such that it doesn't need to know which type of hardware can hang off
> > >> it. It will need to know if one exists since it might need to forego
> > >> creating a connector, but it need not know anything else about it.
> > >> 
> > >> To accomplish this, I think we need:
> > >>
> > >> (1) Some way for drm to enumerate the standalone drivers, so it can
> > >> know when all of them have been probed
> > >> 
> > >> (2) A drm registration function that's called by the standalone
> > >> drivers once they're probed, and a hook with drm_device pointer called
> > >> during drm_load for them to register their drm_* implementations
> > >> 
> > >> (3) Something that will allow for deferred probe if the main driver
> > >> kicks off before the standalones are in, it would need to be called
> > >> before drm_platform/pci_init
> 
> I believe we should defer probing of the sub-drivers only, as we could run 
> into a circular dependency issue if we defer probing on all sides. The main 
> driver should use a notification mechanism instead. This idea has been 
> discussed during the kernel summit and seemed to not have caused a strong 
> disagreement.
> 
> I will give this a try, given that I already have a working implementation as 
> part of my CDF RFC. I "just" need to extract it as a standalone change (BTW, I 
> wish people would have read the CDF RFC in a bit more details, as it contains 
> ideas that have been proposed on the list by other developers during the last 
> couple of weeks. It's both saddening and slightly offending to post ideas that 
> get ignored because of disagreements on the big picture and see them proposed 
> as brand new later on).

I'll join in your whining. The Tegra DRM driver has implemented most of
the ideas discussed here since the beginning. Oh... and that even
predates CDF by a few months.

Then again, perhaps I shouldn't complain all that loudly about people
not looking at my driver since I don't look at most other DRM drivers
either.

Perhaps we should have a poll: who on this list has actually looked at
any of the other DRM drivers?

It seems to me like we really ought to improve how we cooperate.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30  3:46                                                         ` Stéphane Marchesin
@ 2013-11-04 10:25                                                           ` Thierry Reding
  2013-11-04 11:30                                                             ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 10:25 UTC (permalink / raw)
  To: Stéphane Marchesin
  Cc: Stéphane Marchesin, Sylwester Nawrocki, dri-devel, Laurent Pinchart


[-- Attachment #1.1: Type: text/plain, Size: 7557 bytes --]

On Tue, Oct 29, 2013 at 08:46:03PM -0700, Stéphane Marchesin wrote:
> On Tue, Oct 29, 2013 at 1:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> 
> > Hi Sean,
> >
> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
> > wrote:
> > > > Hi,
> > > >
> > > > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> > > >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
> > wrote:
> > > >> >>>>> I think we need to start considering a framework where
> > > >> >>>>> subdrivers
> > > >> >>>>> just
> > > >> >>>>> add drm objects themselves, then the toplevel node is
> > > >> >>>>> responsible
> > > >> >>>>> for
> > > >> >>>>> knowing that everything for the current configuration is
> > > >> >>>>> loaded.
> > > >> >>>>
> > > >> >>>> It would be nice to specify the various pieces in dt, then have
> > > >> >>>> some
> > > >> >>>> type of drm notifier to the toplevel node when everything has
> > > >> >>>> been
> > > >> >>>> probed. Doing it in the dt would allow standalone
> > > >> >>>> drm_bridge/drm_panel
> > > >> >>>> drivers to be transparent as far as the device's drm driver is
> > > >> >>>> concerned.
> > > >> >>>>
> > > >> >>>> Sean
> > > >> >>>>
> > > >> >>>>> I realise we may need to make changes to the core drm to allow
> > > >> >>>>> this
> > > >> >>>>> but we should probably start to create a strategy for fixing
> > > >> >>>>> the
> > > >> >>>>> API
> > > >> >>>>> issues that this throws up.
> > > >> >>>>>
> > > >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> > > >> >>>>> the
> > > >> >>>>> device is in use, or removing them.
> > > >> >>>
> > > >> >>> I do wonder if we had some sort of tag in the device tree for any
> > > >> >>> nodes
> > > >> >>> involved in the display, and the core drm layer would read that
> > > >> >>> list,
> > > >> >>> and when every driver registers tick things off, and when the
> > > >> >>> last
> > > >> >>> one
> > > >> >>> joins we get a callback and init the drm layer, we'd of course
> > > >> >>> have
> > > >> >>> the
> > > >> >>> basic drm layer setup prior to that so we can add the objects as
> > > >> >>> the
> > > >> >>> drivers load. It might make development a bit trickier as you'd
> > > >> >>> need
> > > >> >>> to make sure someone claimed ownership of all the bits for init
> > > >> >>> to
> > > >> >>> proceed.>>
> > > >> >>
> > > >> >> Yeah, that's basically what the strawman looked like in my head.
> > > >> >>
> > > >> >> Instead of a property in each node, I was thinking of having a
> > > >> >> separate gfx pipe nodes that would have dt pointers to the various
> > > >> >> pieces involved in that pipe. This would allow us to associate
> > > >> >> standalone entities like bridges and panels with encoders in dt
> > > >> >> w/o
> > > >> >> doing it in the drm code. I *think* this should be Ok with the dt
> > > >> >> guys
> > > >> >> since it is still describing the hardware, but I think we'd have
> > > >> >> to
> > > >> >> make sure it wasn't drm-specific.
> > > >> >
> > > >> > I suppose the question is how much dynamic pipeline construction
> > > >> > there
> > > >> > is,
> > > >> >
> > > >> > even on things like radeon and i915 we have dynamic clock generator
> > > >> > to
> > > >> > crtc to encoder setups, so I worry about static lists per-pipe, so
> > > >> > I
> > > >> > still think just stating all these devices are needed for display
> > > >> > and
> > > >> > a list of valid interconnections between them, then we can have the
> > > >> > generic code model drm crtc/encoders/connectors on that list, and
> > > >> > construct the possible_crtcs /possible_clones etc at that stage.
> > > >>
> > > >> I'm, without excuse, hopeless at devicetree, so there are probably
> > > >> some violations, but something like:
> > > >>
> > > >> display-pipelines {
> > > >>
> > > >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> > > >>
> > > >> &crtc-x &crtc-y>;
> > > >>
> > > >>   pipe1 {
> > > >>
> > > >>     bridge = <&bridge-a>;
> > > >>     encoder = <&encoder-x>;
> > > >>     crtc = <&crtc-y>;
> > > >>
> > > >>   };
> > > >>   pipe2 {
> > > >>
> > > >>     encoder = <&encoder-x>;
> > > >>     crtc = <&crtc-x>;
> > > >>
> > > >>   };
> > > >>   pipe3 {
> > > >>
> > > >>     panel = <&panel-a>;
> > > >>     encoder = <&encoder-y>;
> > > >>     crtc = <&crtc-y>;
> > > >>
> > > >>   };
> > > >>
> > > >> };
> > > >>
> > > >> I'm tempted to add connector to the pipe nodes as well, so it's
> > > >> obvious which connector should be used in cases where multiple
> > > >> entities in the pipe implement drm_connector. However, I'm not sure
> > > >> if
> > > >> that would be NACKed by dt people.
> > > >>
> > > >> I'm also not sure if there are too many combinations for i915 and
> > > >> radeon to make this unreasonable. I suppose those devices could just
> > > >> use required-elements and leave the pipe nodes out.
> > > >
> > > > Just to put my two cents in, as one of the people involved into "the
> > > > device tree movement", I'd say that instead of creating artifical
> > > > entities, such as display-pipelines and all of the pipeX'es, device
> > > > tree should represent relations between nodes.
> > > >
> > > > According to the generic DT bindings we already have for
> > > > video-interfaces
> > > > [1] your example connection layout would look as follows:
> > > Hi Tomasz
> > > Thanks for sending this along.
> > >
> > > I think the general consensus is that each drm driver should be
> > > implemented as a singular driver. That is, N:1 binding to driver
> > > mapping, where there are N IP blocks. Optional devices (such as
> > > bridges, panels) probably make sense to spin off as standalone
> > > drivers.
> >
> > I believe this is a huge step backwards from current kernel design
> > standards, which prefer modularity.
> >
> > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> > nice to have the possibility to compile just a subset of support for them
> > into the kernel and load rest of them as modules. (e.g. basic LCD
> > controller on a mobile phone compiled in and external connectors, like
> > HDMI as modules)
> >
> > Not even saying that from development perspective, a huge single driver
> > would be much more difficult to test and debug, than several smaller
> > drivers, which could be developed separately.
> >
> 
> This is the opposite of our experience, though. A series of small drivers
> like what's in drm/exynos can become really tedious/difficult to
> coordinate. If you have separate drivers, everything needs to be
> synchronized, but also has to account for potentially different loading
> order.
> 
> It seems you're only thinking about the basic case, where you only support
> a single resolution, no dpms, no suspend to ram... But when you want full
> fledged functionality, then the issues I described become much more
> prevalent.

I fail to see how this is relevant here. It's fairly clear that even if
a DRM driver is composed of more than a single platform driver, there's
still a single point of coordination (the DRM driver). How does that
have any impact on what features the driver can support? All of the
features will be exposed via DRM, whether you use multiple drivers or a
single monolithic one underneath is completely irrelevant.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-10-30 15:32                                                         ` Sean Paul
  2013-10-30 15:45                                                           ` Laurent Pinchart
  2013-10-30 15:53                                                           ` Daniel Vetter
@ 2013-11-04 10:36                                                           ` Thierry Reding
  2 siblings, 0 replies; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 10:36 UTC (permalink / raw)
  To: Sean Paul
  Cc: Stéphane Marchesin, dri-devel, Sylwester Nawrocki, Laurent Pinchart


[-- Attachment #1.1: Type: text/plain, Size: 11089 bytes --]

On Wed, Oct 30, 2013 at 11:32:24AM -0400, Sean Paul wrote:
> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> > Hi Sean,
> >
> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> >> On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
> > wrote:
> >> > Hi,
> >> >
> >> > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> >> >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
> > wrote:
> >> >> >>>>> I think we need to start considering a framework where
> >> >> >>>>> subdrivers
> >> >> >>>>> just
> >> >> >>>>> add drm objects themselves, then the toplevel node is
> >> >> >>>>> responsible
> >> >> >>>>> for
> >> >> >>>>> knowing that everything for the current configuration is
> >> >> >>>>> loaded.
> >> >> >>>>
> >> >> >>>> It would be nice to specify the various pieces in dt, then have
> >> >> >>>> some
> >> >> >>>> type of drm notifier to the toplevel node when everything has
> >> >> >>>> been
> >> >> >>>> probed. Doing it in the dt would allow standalone
> >> >> >>>> drm_bridge/drm_panel
> >> >> >>>> drivers to be transparent as far as the device's drm driver is
> >> >> >>>> concerned.
> >> >> >>>>
> >> >> >>>> Sean
> >> >> >>>>
> >> >> >>>>> I realise we may need to make changes to the core drm to allow
> >> >> >>>>> this
> >> >> >>>>> but we should probably start to create a strategy for fixing
> >> >> >>>>> the
> >> >> >>>>> API
> >> >> >>>>> issues that this throws up.
> >> >> >>>>>
> >> >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
> >> >> >>>>> the
> >> >> >>>>> device is in use, or removing them.
> >> >> >>>
> >> >> >>> I do wonder if we had some sort of tag in the device tree for any
> >> >> >>> nodes
> >> >> >>> involved in the display, and the core drm layer would read that
> >> >> >>> list,
> >> >> >>> and when every driver registers tick things off, and when the
> >> >> >>> last
> >> >> >>> one
> >> >> >>> joins we get a callback and init the drm layer, we'd of course
> >> >> >>> have
> >> >> >>> the
> >> >> >>> basic drm layer setup prior to that so we can add the objects as
> >> >> >>> the
> >> >> >>> drivers load. It might make development a bit trickier as you'd
> >> >> >>> need
> >> >> >>> to make sure someone claimed ownership of all the bits for init
> >> >> >>> to
> >> >> >>> proceed.>>
> >> >> >>
> >> >> >> Yeah, that's basically what the strawman looked like in my head.
> >> >> >>
> >> >> >> Instead of a property in each node, I was thinking of having a
> >> >> >> separate gfx pipe nodes that would have dt pointers to the various
> >> >> >> pieces involved in that pipe. This would allow us to associate
> >> >> >> standalone entities like bridges and panels with encoders in dt
> >> >> >> w/o
> >> >> >> doing it in the drm code. I *think* this should be Ok with the dt
> >> >> >> guys
> >> >> >> since it is still describing the hardware, but I think we'd have
> >> >> >> to
> >> >> >> make sure it wasn't drm-specific.
> >> >> >
> >> >> > I suppose the question is how much dynamic pipeline construction
> >> >> > there
> >> >> > is,
> >> >> >
> >> >> > even on things like radeon and i915 we have dynamic clock generator
> >> >> > to
> >> >> > crtc to encoder setups, so I worry about static lists per-pipe, so
> >> >> > I
> >> >> > still think just stating all these devices are needed for display
> >> >> > and
> >> >> > a list of valid interconnections between them, then we can have the
> >> >> > generic code model drm crtc/encoders/connectors on that list, and
> >> >> > construct the possible_crtcs /possible_clones etc at that stage.
> >> >>
> >> >> I'm, without excuse, hopeless at devicetree, so there are probably
> >> >> some violations, but something like:
> >> >>
> >> >> display-pipelines {
> >> >>
> >> >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> >> >>
> >> >> &crtc-x &crtc-y>;
> >> >>
> >> >>   pipe1 {
> >> >>
> >> >>     bridge = <&bridge-a>;
> >> >>     encoder = <&encoder-x>;
> >> >>     crtc = <&crtc-y>;
> >> >>
> >> >>   };
> >> >>   pipe2 {
> >> >>
> >> >>     encoder = <&encoder-x>;
> >> >>     crtc = <&crtc-x>;
> >> >>
> >> >>   };
> >> >>   pipe3 {
> >> >>
> >> >>     panel = <&panel-a>;
> >> >>     encoder = <&encoder-y>;
> >> >>     crtc = <&crtc-y>;
> >> >>
> >> >>   };
> >> >>
> >> >> };
> >> >>
> >> >> I'm tempted to add connector to the pipe nodes as well, so it's
> >> >> obvious which connector should be used in cases where multiple
> >> >> entities in the pipe implement drm_connector. However, I'm not sure
> >> >> if
> >> >> that would be NACKed by dt people.
> >> >>
> >> >> I'm also not sure if there are too many combinations for i915 and
> >> >> radeon to make this unreasonable. I suppose those devices could just
> >> >> use required-elements and leave the pipe nodes out.
> >> >
> >> > Just to put my two cents in, as one of the people involved into "the
> >> > device tree movement", I'd say that instead of creating artifical
> >> > entities, such as display-pipelines and all of the pipeX'es, device
> >> > tree should represent relations between nodes.
> >> >
> >> > According to the generic DT bindings we already have for
> >> > video-interfaces
> >> > [1] your example connection layout would look as follows:
> >> Hi Tomasz
> >> Thanks for sending this along.
> >>
> >> I think the general consensus is that each drm driver should be
> >> implemented as a singular driver. That is, N:1 binding to driver
> >> mapping, where there are N IP blocks. Optional devices (such as
> >> bridges, panels) probably make sense to spin off as standalone
> >> drivers.
> >
> > I believe this is a huge step backwards from current kernel design
> > standards, which prefer modularity.
> >
> > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
> > nice to have the possibility to compile just a subset of support for them
> > into the kernel and load rest of them as modules. (e.g. basic LCD
> > controller on a mobile phone compiled in and external connectors, like
> > HDMI as modules)
> >
> > Not even saying that from development perspective, a huge single driver
> > would be much more difficult to test and debug, than several smaller
> > drivers, which could be developed separately.
> >
> > Unless there is a misunderstanding here, I think this is broken.
> >
> 
> I'll defer to Stéphane's answer here. In theory it sounds good, but
> things get messy in practice.
> 
> >> An example: exynos_drm_drv would be a platform_driver which implements
> >> drm_driver. On drm_load, it would enumerate the various dt nodes for
> >> its IP blocks and initialize them with direct calls (like
> >> exynos_drm_fimd_initialize). If the board uses a bridge (say for
> >> eDP->LVDS), that bridge driver would be a real driver with its own
> >> probe.
> >>
> >> I think the ideal situation would be for the drm layer to manage the
> >> standalone drivers in a way that is transparent to the main driver,
> >> such that it doesn't need to know which type of hardware can hang off
> >> it. It will need to know if one exists since it might need to forego
> >> creating a connector, but it need not know anything else about it.
> >>
> >> To accomplish this, I think we need:
> >>  (1) Some way for drm to enumerate the standalone drivers, so it can
> >> know when all of them have been probed
> >>  (2) A drm registration function that's called by the standalone
> >> drivers once they're probed, and a hook with drm_device pointer called
> >> during drm_load for them to register their drm_* implementations
> >>  (3) Something that will allow for deferred probe if the main driver
> >> kicks off before the standalones are in, it would need to be called
> >> before drm_platform/pci_init
> >>
> >> I think we'll need to expand on the media bindings to achieve (1).
> >
> > Could you elaborate on why you think so?
> >
> > I believe the video interface bindings contain everything needed for this
> > case, except, of course, some device/bus specific parts, but those are to
> > be defined by separate device/bus specific bindings.
> >
> 
> AFAICT, there is no way for drm to enumerate all of the pieces that
> need probing before it loads (ie: how do you enumerate all device
> nodes with pipe {} subnode[s]). I've given this more thought, and I
> think the following could work without forcing unified/split drivers
> (ie: it can be left to the driver author to choose).
> 
> If there was some way for drm to know all of the pieces that need to
> be probed/initialized before calling drm_load, it could provide an API
> for various drivers to "claim" nodes. This API would accept the
> device_node being claimed as well as an initialize hook that will be
> called back to give the standalone driver a pointer to the drm_device.
> 
> The main drm driver, which is responsible for calling
> drm_platform/pci_init, would claim the nodes it plans on implementing
> in the probe. It would then check drm to see if all requred nodes had
> been claimed. If they have not been claimed, that probe would defer
> and try again later.
> 
> Once all required nodes have been "claimed", the main driver's probe
> would call drm_platform/pci_init to kick off load(). After load() has
> finished, the drm layer would then call the various standalone driver
> hooks that were previously registered when it claimed its node. These
> hooks would allow the driver to register its
> crtc/encoder/bridge/connector.
> 
> Multi-driver solutions could work within this framework, as could
> integrated ones. This would also allow things like bridge drivers to
> be completely transparent.
> 
> I hope that made sense ;)

I'll just go and repeat myself in the hope to increase chances of
someone reading it: I recommend looking at the Tegra DRM driver which
solves a lot of these issues already (in much the same way that you
suggest here).

The version in the tree that I've submitted for 3.13 (I think Dave
hasn't merged it yet) is improved in many ways. Unfortunately it isn't
quite as generic as I would've liked it to be and rather tied to how the
Tegra SoC is architected, but I've volunteered elsewhere to look into
further abstracting things away in order to turn it into something that
could even be used outside of DRM. I haven't received much feedback,
though, so I have close to no idea what the requirements for others are,
and hence it's difficult to know where to start.

In case anyone's interested, there's some code here:

	http://cgit.freedesktop.org/tegra/linux/log/?h=drm/for-next

More specifically:

	http://cgit.freedesktop.org/tegra/linux/tree/drivers/gpu/host1x/bus.c?h=drm/for-next
	http://cgit.freedesktop.org/tegra/linux/tree/drivers/gpu/drm/tegra/bus.c?h=drm/for-next
	http://cgit.freedesktop.org/tegra/linux/tree/drivers/gpu/drm/tegra/drm.c?h=drm/for-next

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 10:25                                                           ` Thierry Reding
@ 2013-11-04 11:30                                                             ` Inki Dae
  2013-11-04 15:44                                                               ` Sean Paul
  0 siblings, 1 reply; 93+ messages in thread
From: Inki Dae @ 2013-11-04 11:30 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Laurent Pinchart, dri-devel, Sylwester Nawrocki, Stéphane Marchesin

2013/11/4 Thierry Reding <thierry.reding@gmail.com>:
> On Tue, Oct 29, 2013 at 08:46:03PM -0700, Stéphane Marchesin wrote:
>> On Tue, Oct 29, 2013 at 1:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
>>
>> > Hi Sean,
>> >
>> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
>> > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
>> > wrote:
>> > > > Hi,
>> > > >
>> > > > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>> > > >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
>> > wrote:
>> > > >> >>>>> I think we need to start considering a framework where
>> > > >> >>>>> subdrivers
>> > > >> >>>>> just
>> > > >> >>>>> add drm objects themselves, then the toplevel node is
>> > > >> >>>>> responsible
>> > > >> >>>>> for
>> > > >> >>>>> knowing that everything for the current configuration is
>> > > >> >>>>> loaded.
>> > > >> >>>>
>> > > >> >>>> It would be nice to specify the various pieces in dt, then have
>> > > >> >>>> some
>> > > >> >>>> type of drm notifier to the toplevel node when everything has
>> > > >> >>>> been
>> > > >> >>>> probed. Doing it in the dt would allow standalone
>> > > >> >>>> drm_bridge/drm_panel
>> > > >> >>>> drivers to be transparent as far as the device's drm driver is
>> > > >> >>>> concerned.
>> > > >> >>>>
>> > > >> >>>> Sean
>> > > >> >>>>
>> > > >> >>>>> I realise we may need to make changes to the core drm to allow
>> > > >> >>>>> this
>> > > >> >>>>> but we should probably start to create a strategy for fixing
>> > > >> >>>>> the
>> > > >> >>>>> API
>> > > >> >>>>> issues that this throws up.
>> > > >> >>>>>
>> > > >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
>> > > >> >>>>> the
>> > > >> >>>>> device is in use, or removing them.
>> > > >> >>>
>> > > >> >>> I do wonder if we had some sort of tag in the device tree for any
>> > > >> >>> nodes
>> > > >> >>> involved in the display, and the core drm layer would read that
>> > > >> >>> list,
>> > > >> >>> and when every driver registers tick things off, and when the
>> > > >> >>> last
>> > > >> >>> one
>> > > >> >>> joins we get a callback and init the drm layer, we'd of course
>> > > >> >>> have
>> > > >> >>> the
>> > > >> >>> basic drm layer setup prior to that so we can add the objects as
>> > > >> >>> the
>> > > >> >>> drivers load. It might make development a bit trickier as you'd
>> > > >> >>> need
>> > > >> >>> to make sure someone claimed ownership of all the bits for init
>> > > >> >>> to
>> > > >> >>> proceed.>>
>> > > >> >>
>> > > >> >> Yeah, that's basically what the strawman looked like in my head.
>> > > >> >>
>> > > >> >> Instead of a property in each node, I was thinking of having a
>> > > >> >> separate gfx pipe nodes that would have dt pointers to the various
>> > > >> >> pieces involved in that pipe. This would allow us to associate
>> > > >> >> standalone entities like bridges and panels with encoders in dt
>> > > >> >> w/o
>> > > >> >> doing it in the drm code. I *think* this should be Ok with the dt
>> > > >> >> guys
>> > > >> >> since it is still describing the hardware, but I think we'd have
>> > > >> >> to
>> > > >> >> make sure it wasn't drm-specific.
>> > > >> >
>> > > >> > I suppose the question is how much dynamic pipeline construction
>> > > >> > there
>> > > >> > is,
>> > > >> >
>> > > >> > even on things like radeon and i915 we have dynamic clock generator
>> > > >> > to
>> > > >> > crtc to encoder setups, so I worry about static lists per-pipe, so
>> > > >> > I
>> > > >> > still think just stating all these devices are needed for display
>> > > >> > and
>> > > >> > a list of valid interconnections between them, then we can have the
>> > > >> > generic code model drm crtc/encoders/connectors on that list, and
>> > > >> > construct the possible_crtcs /possible_clones etc at that stage.
>> > > >>
>> > > >> I'm, without excuse, hopeless at devicetree, so there are probably
>> > > >> some violations, but something like:
>> > > >>
>> > > >> display-pipelines {
>> > > >>
>> > > >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>> > > >>
>> > > >> &crtc-x &crtc-y>;
>> > > >>
>> > > >>   pipe1 {
>> > > >>
>> > > >>     bridge = <&bridge-a>;
>> > > >>     encoder = <&encoder-x>;
>> > > >>     crtc = <&crtc-y>;
>> > > >>
>> > > >>   };
>> > > >>   pipe2 {
>> > > >>
>> > > >>     encoder = <&encoder-x>;
>> > > >>     crtc = <&crtc-x>;
>> > > >>
>> > > >>   };
>> > > >>   pipe3 {
>> > > >>
>> > > >>     panel = <&panel-a>;
>> > > >>     encoder = <&encoder-y>;
>> > > >>     crtc = <&crtc-y>;
>> > > >>
>> > > >>   };
>> > > >>
>> > > >> };
>> > > >>
>> > > >> I'm tempted to add connector to the pipe nodes as well, so it's
>> > > >> obvious which connector should be used in cases where multiple
>> > > >> entities in the pipe implement drm_connector. However, I'm not sure
>> > > >> if
>> > > >> that would be NACKed by dt people.
>> > > >>
>> > > >> I'm also not sure if there are too many combinations for i915 and
>> > > >> radeon to make this unreasonable. I suppose those devices could just
>> > > >> use required-elements and leave the pipe nodes out.
>> > > >
>> > > > Just to put my two cents in, as one of the people involved into "the
>> > > > device tree movement", I'd say that instead of creating artifical
>> > > > entities, such as display-pipelines and all of the pipeX'es, device
>> > > > tree should represent relations between nodes.
>> > > >
>> > > > According to the generic DT bindings we already have for
>> > > > video-interfaces
>> > > > [1] your example connection layout would look as follows:
>> > > Hi Tomasz
>> > > Thanks for sending this along.
>> > >
>> > > I think the general consensus is that each drm driver should be
>> > > implemented as a singular driver. That is, N:1 binding to driver
>> > > mapping, where there are N IP blocks. Optional devices (such as
>> > > bridges, panels) probably make sense to spin off as standalone
>> > > drivers.
>> >
>> > I believe this is a huge step backwards from current kernel design
>> > standards, which prefer modularity.
>> >
>> > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
>> > nice to have the possibility to compile just a subset of support for them
>> > into the kernel and load rest of them as modules. (e.g. basic LCD
>> > controller on a mobile phone compiled in and external connectors, like
>> > HDMI as modules)
>> >
>> > Not even saying that from development perspective, a huge single driver
>> > would be much more difficult to test and debug, than several smaller
>> > drivers, which could be developed separately.
>> >
>>
>> This is the opposite of our experience, though. A series of small drivers
>> like what's in drm/exynos can become really tedious/difficult to
>> coordinate. If you have separate drivers, everything needs to be
>> synchronized, but also has to account for potentially different loading
>> order.
>>
>> It seems you're only thinking about the basic case, where you only support
>> a single resolution, no dpms, no suspend to ram... But when you want full
>> fledged functionality, then the issues I described become much more
>> prevalent.
>
> I fail to see how this is relevant here. It's fairly clear that even if
> a DRM driver is composed of more than a single platform driver, there's
> still a single point of coordination (the DRM driver). How does that
> have any impact on what features the driver can support? All of the
> features will be exposed via DRM, whether you use multiple drivers or a
> single monolithic one underneath is completely irrelevant.
>

+1

I think a single drm driver - all sub drivers are controlled by dpms
of top level - is definitely what we should go to but it's not clear
that a single drm driver should necessary be a huge single driver yet.
Even if we use one more sub drivers based on driver model, we can
avoid the issues, the loading and power ordering issues.

So I'd like to ask question to Google people. Are there really any
cases that the loading and power ordering issues can be incurred in
case that a drm driver uses one more sub drivers based on driver
model? With the re-factoring patch from Sean, I think Exynos drm
driver also has no these issues anymore even through Exynos drm driver
uses one more sub drivers based on driver model. That is why it's not
clear to me yet.

Thanks,
Inki Dae

> Thierry
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 10:10                                                           ` Thierry Reding
@ 2013-11-04 12:14                                                             ` Rob Clark
  2013-11-04 12:52                                                               ` Thierry Reding
  0 siblings, 1 reply; 93+ messages in thread
From: Rob Clark @ 2013-11-04 12:14 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stéphane Marchesin, Sylwester Nawrocki, dri-devel, Laurent Pinchart

On Mon, Nov 4, 2013 at 5:10 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
> On Tue, Oct 29, 2013 at 05:29:55PM -0400, Rob Clark wrote:
>> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> [...]
>> > I believe this is a huge step backwards from current kernel design
>> > standards, which prefer modularity.
>>
>> But it makes things behave in the way that userspace expects, which is
>> more important.
>
> Why would userspace care about the modularity of kernel drivers? The
> only thing that userspace should care about is whether there's a DRM
> device or not. How the kernel makes that happen should be completely
> irrelevant to userspace.

What I was referring to was userspace not expecting parts of the drm
(crtcs/encoders/connectors) driver to show up incrementally. You can
avoid that, but it is more of a hassle currently (ie. most drivers
that need to do this, including a few that I've written, end up
needing some form of
stuff-devices-in-global-variables-that-main-driver-checks-for).

BR,
-R

> Thierry

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 12:14                                                             ` Rob Clark
@ 2013-11-04 12:52                                                               ` Thierry Reding
  2013-11-04 16:12                                                                 ` Daniel Vetter
  0 siblings, 1 reply; 93+ messages in thread
From: Thierry Reding @ 2013-11-04 12:52 UTC (permalink / raw)
  To: Rob Clark
  Cc: Stéphane Marchesin, Sylwester Nawrocki, dri-devel, Laurent Pinchart


[-- Attachment #1.1: Type: text/plain, Size: 1816 bytes --]

On Mon, Nov 04, 2013 at 07:14:27AM -0500, Rob Clark wrote:
> On Mon, Nov 4, 2013 at 5:10 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
> > On Tue, Oct 29, 2013 at 05:29:55PM -0400, Rob Clark wrote:
> >> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> > [...]
> >> > I believe this is a huge step backwards from current kernel design
> >> > standards, which prefer modularity.
> >>
> >> But it makes things behave in the way that userspace expects, which is
> >> more important.
> >
> > Why would userspace care about the modularity of kernel drivers? The
> > only thing that userspace should care about is whether there's a DRM
> > device or not. How the kernel makes that happen should be completely
> > irrelevant to userspace.
> 
> What I was referring to was userspace not expecting parts of the drm
> (crtcs/encoders/connectors) driver to show up incrementally. You can
> avoid that, but it is more of a hassle currently (ie. most drivers
> that need to do this, including a few that I've written, end up
> needing some form of
> stuff-devices-in-global-variables-that-main-driver-checks-for).

I must have misunderstood then. I don't think adding hotplug of DRM
subdevices is something we would want. And I don't think there's a
requirement for that, either. Embedded devices usually have well-defined
use-cases, so the configuration is rather static at runtime.

As for the global variables, you can do it properly. Granted, it might
be more work than global variables, but keeping drivers separated does
have advantages. Especially when the devices have completely separated
register ranges or clocks or other resources, it's very natural to use
one driver per device and glue them together with a composite device
construct.

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 11:30                                                             ` Inki Dae
@ 2013-11-04 15:44                                                               ` Sean Paul
  2013-11-05  7:38                                                                 ` Inki Dae
  0 siblings, 1 reply; 93+ messages in thread
From: Sean Paul @ 2013-11-04 15:44 UTC (permalink / raw)
  To: Inki Dae
  Cc: Stéphane Marchesin, Sylwester Nawrocki, Laurent Pinchart, dri-devel

On Mon, Nov 4, 2013 at 6:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
> 2013/11/4 Thierry Reding <thierry.reding@gmail.com>:
>> On Tue, Oct 29, 2013 at 08:46:03PM -0700, Stéphane Marchesin wrote:
>>> On Tue, Oct 29, 2013 at 1:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
>>>
>>> > Hi Sean,
>>> >
>>> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
>>> > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa <tomasz.figa@gmail.com>
>>> > wrote:
>>> > > > Hi,
>>> > > >
>>> > > > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
>>> > > >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie <airlied@gmail.com>
>>> > wrote:
>>> > > >> >>>>> I think we need to start considering a framework where
>>> > > >> >>>>> subdrivers
>>> > > >> >>>>> just
>>> > > >> >>>>> add drm objects themselves, then the toplevel node is
>>> > > >> >>>>> responsible
>>> > > >> >>>>> for
>>> > > >> >>>>> knowing that everything for the current configuration is
>>> > > >> >>>>> loaded.
>>> > > >> >>>>
>>> > > >> >>>> It would be nice to specify the various pieces in dt, then have
>>> > > >> >>>> some
>>> > > >> >>>> type of drm notifier to the toplevel node when everything has
>>> > > >> >>>> been
>>> > > >> >>>> probed. Doing it in the dt would allow standalone
>>> > > >> >>>> drm_bridge/drm_panel
>>> > > >> >>>> drivers to be transparent as far as the device's drm driver is
>>> > > >> >>>> concerned.
>>> > > >> >>>>
>>> > > >> >>>> Sean
>>> > > >> >>>>
>>> > > >> >>>>> I realise we may need to make changes to the core drm to allow
>>> > > >> >>>>> this
>>> > > >> >>>>> but we should probably start to create a strategy for fixing
>>> > > >> >>>>> the
>>> > > >> >>>>> API
>>> > > >> >>>>> issues that this throws up.
>>> > > >> >>>>>
>>> > > >> >>>>> Note I'm not yet advocating for dynamic addition of nodes once
>>> > > >> >>>>> the
>>> > > >> >>>>> device is in use, or removing them.
>>> > > >> >>>
>>> > > >> >>> I do wonder if we had some sort of tag in the device tree for any
>>> > > >> >>> nodes
>>> > > >> >>> involved in the display, and the core drm layer would read that
>>> > > >> >>> list,
>>> > > >> >>> and when every driver registers tick things off, and when the
>>> > > >> >>> last
>>> > > >> >>> one
>>> > > >> >>> joins we get a callback and init the drm layer, we'd of course
>>> > > >> >>> have
>>> > > >> >>> the
>>> > > >> >>> basic drm layer setup prior to that so we can add the objects as
>>> > > >> >>> the
>>> > > >> >>> drivers load. It might make development a bit trickier as you'd
>>> > > >> >>> need
>>> > > >> >>> to make sure someone claimed ownership of all the bits for init
>>> > > >> >>> to
>>> > > >> >>> proceed.>>
>>> > > >> >>
>>> > > >> >> Yeah, that's basically what the strawman looked like in my head.
>>> > > >> >>
>>> > > >> >> Instead of a property in each node, I was thinking of having a
>>> > > >> >> separate gfx pipe nodes that would have dt pointers to the various
>>> > > >> >> pieces involved in that pipe. This would allow us to associate
>>> > > >> >> standalone entities like bridges and panels with encoders in dt
>>> > > >> >> w/o
>>> > > >> >> doing it in the drm code. I *think* this should be Ok with the dt
>>> > > >> >> guys
>>> > > >> >> since it is still describing the hardware, but I think we'd have
>>> > > >> >> to
>>> > > >> >> make sure it wasn't drm-specific.
>>> > > >> >
>>> > > >> > I suppose the question is how much dynamic pipeline construction
>>> > > >> > there
>>> > > >> > is,
>>> > > >> >
>>> > > >> > even on things like radeon and i915 we have dynamic clock generator
>>> > > >> > to
>>> > > >> > crtc to encoder setups, so I worry about static lists per-pipe, so
>>> > > >> > I
>>> > > >> > still think just stating all these devices are needed for display
>>> > > >> > and
>>> > > >> > a list of valid interconnections between them, then we can have the
>>> > > >> > generic code model drm crtc/encoders/connectors on that list, and
>>> > > >> > construct the possible_crtcs /possible_clones etc at that stage.
>>> > > >>
>>> > > >> I'm, without excuse, hopeless at devicetree, so there are probably
>>> > > >> some violations, but something like:
>>> > > >>
>>> > > >> display-pipelines {
>>> > > >>
>>> > > >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
>>> > > >>
>>> > > >> &crtc-x &crtc-y>;
>>> > > >>
>>> > > >>   pipe1 {
>>> > > >>
>>> > > >>     bridge = <&bridge-a>;
>>> > > >>     encoder = <&encoder-x>;
>>> > > >>     crtc = <&crtc-y>;
>>> > > >>
>>> > > >>   };
>>> > > >>   pipe2 {
>>> > > >>
>>> > > >>     encoder = <&encoder-x>;
>>> > > >>     crtc = <&crtc-x>;
>>> > > >>
>>> > > >>   };
>>> > > >>   pipe3 {
>>> > > >>
>>> > > >>     panel = <&panel-a>;
>>> > > >>     encoder = <&encoder-y>;
>>> > > >>     crtc = <&crtc-y>;
>>> > > >>
>>> > > >>   };
>>> > > >>
>>> > > >> };
>>> > > >>
>>> > > >> I'm tempted to add connector to the pipe nodes as well, so it's
>>> > > >> obvious which connector should be used in cases where multiple
>>> > > >> entities in the pipe implement drm_connector. However, I'm not sure
>>> > > >> if
>>> > > >> that would be NACKed by dt people.
>>> > > >>
>>> > > >> I'm also not sure if there are too many combinations for i915 and
>>> > > >> radeon to make this unreasonable. I suppose those devices could just
>>> > > >> use required-elements and leave the pipe nodes out.
>>> > > >
>>> > > > Just to put my two cents in, as one of the people involved into "the
>>> > > > device tree movement", I'd say that instead of creating artifical
>>> > > > entities, such as display-pipelines and all of the pipeX'es, device
>>> > > > tree should represent relations between nodes.
>>> > > >
>>> > > > According to the generic DT bindings we already have for
>>> > > > video-interfaces
>>> > > > [1] your example connection layout would look as follows:
>>> > > Hi Tomasz
>>> > > Thanks for sending this along.
>>> > >
>>> > > I think the general consensus is that each drm driver should be
>>> > > implemented as a singular driver. That is, N:1 binding to driver
>>> > > mapping, where there are N IP blocks. Optional devices (such as
>>> > > bridges, panels) probably make sense to spin off as standalone
>>> > > drivers.
>>> >
>>> > I believe this is a huge step backwards from current kernel design
>>> > standards, which prefer modularity.
>>> >
>>> > Having multiple IPs being part of the DRM subsystem in a SoC, it would be
>>> > nice to have the possibility to compile just a subset of support for them
>>> > into the kernel and load rest of them as modules. (e.g. basic LCD
>>> > controller on a mobile phone compiled in and external connectors, like
>>> > HDMI as modules)
>>> >
>>> > Not even saying that from development perspective, a huge single driver
>>> > would be much more difficult to test and debug, than several smaller
>>> > drivers, which could be developed separately.
>>> >
>>>
>>> This is the opposite of our experience, though. A series of small drivers
>>> like what's in drm/exynos can become really tedious/difficult to
>>> coordinate. If you have separate drivers, everything needs to be
>>> synchronized, but also has to account for potentially different loading
>>> order.
>>>
>>> It seems you're only thinking about the basic case, where you only support
>>> a single resolution, no dpms, no suspend to ram... But when you want full
>>> fledged functionality, then the issues I described become much more
>>> prevalent.
>>
>> I fail to see how this is relevant here. It's fairly clear that even if
>> a DRM driver is composed of more than a single platform driver, there's
>> still a single point of coordination (the DRM driver). How does that
>> have any impact on what features the driver can support? All of the
>> features will be exposed via DRM, whether you use multiple drivers or a
>> single monolithic one underneath is completely irrelevant.
>>
>
> +1
>
> I think a single drm driver - all sub drivers are controlled by dpms
> of top level - is definitely what we should go to but it's not clear
> that a single drm driver should necessary be a huge single driver yet.
> Even if we use one more sub drivers based on driver model, we can
> avoid the issues, the loading and power ordering issues.
>
> So I'd like to ask question to Google people. Are there really any
> cases that the loading and power ordering issues can be incurred in
> case that a drm driver uses one more sub drivers based on driver
> model?

I think it makes the code simpler, and more explicit. If you don't
support dynamic module loading, what's the point in creating modules?

To avoid the init and suspend/resume ordering issues, one must
register the subdrivers from the main drm driver, and you must not use
pm_ops. So why incur the extra complexity of modules when we only use
the probe and that could easily be converted to

#ifdef CONFIG_SOME_GFX_BLOCK
init_some_gfx_block()
#endif

Sean


> With the re-factoring patch from Sean, I think Exynos drm
> driver also has no these issues anymore even through Exynos drm driver
> uses one more sub drivers based on driver model. That is why it's not
> clear to me yet.
>
> Thanks,
> Inki Dae
>
>> Thierry
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel@lists.freedesktop.org
>> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 12:52                                                               ` Thierry Reding
@ 2013-11-04 16:12                                                                 ` Daniel Vetter
  0 siblings, 0 replies; 93+ messages in thread
From: Daniel Vetter @ 2013-11-04 16:12 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Stéphane Marchesin, dri-devel, Sylwester Nawrocki, Laurent Pinchart

On Mon, Nov 04, 2013 at 01:52:33PM +0100, Thierry Reding wrote:
> On Mon, Nov 04, 2013 at 07:14:27AM -0500, Rob Clark wrote:
> > On Mon, Nov 4, 2013 at 5:10 AM, Thierry Reding <thierry.reding@gmail.com> wrote:
> > > On Tue, Oct 29, 2013 at 05:29:55PM -0400, Rob Clark wrote:
> > >> On Tue, Oct 29, 2013 at 4:50 PM, Tomasz Figa <tomasz.figa@gmail.com> wrote:
> > > [...]
> > >> > I believe this is a huge step backwards from current kernel design
> > >> > standards, which prefer modularity.
> > >>
> > >> But it makes things behave in the way that userspace expects, which is
> > >> more important.
> > >
> > > Why would userspace care about the modularity of kernel drivers? The
> > > only thing that userspace should care about is whether there's a DRM
> > > device or not. How the kernel makes that happen should be completely
> > > irrelevant to userspace.
> > 
> > What I was referring to was userspace not expecting parts of the drm
> > (crtcs/encoders/connectors) driver to show up incrementally. You can
> > avoid that, but it is more of a hassle currently (ie. most drivers
> > that need to do this, including a few that I've written, end up
> > needing some form of
> > stuff-devices-in-global-variables-that-main-driver-checks-for).
> 
> I must have misunderstood then. I don't think adding hotplug of DRM
> subdevices is something we would want. And I don't think there's a
> requirement for that, either. Embedded devices usually have well-defined
> use-cases, so the configuration is rather static at runtime.
> 
> As for the global variables, you can do it properly. Granted, it might
> be more work than global variables, but keeping drivers separated does
> have advantages. Especially when the devices have completely separated
> register ranges or clocks or other resources, it's very natural to use
> one driver per device and glue them together with a composite device
> construct.

I'm pretty short of ripping out all the midlayer disasters in the drm
driver load path. As soon as that's done drivers can defer probing and do
all kinds of trick until everything is set up, and then as the very last
step register the drm device. Current wip stuff is at

http://cgit.freedesktop.org/~danvet/drm/log/?h=drm-init-cleanup

Leftover todo items:
- rip out bus->set_busid and block the setversion ioctl from doing stupid
  things on kms drivers. That's the last nail on the drm_bus coffin.
- Convert udl over to embedding drm_device and driver-controlled setup
  sequence and rip out drm_dev->usbdevice as a proof of concept. That
  should be the death-spell to drm_usb.c

I'll let you arm guys figure out how to the same for drm_platform.c ;-) On
a quick look there's only very few drivers that use
drm_dev->platform_device, which is the last piece to kill really.

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

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

* RE: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
  2013-11-04 15:44                                                               ` Sean Paul
@ 2013-11-05  7:38                                                                 ` Inki Dae
  0 siblings, 0 replies; 93+ messages in thread
From: Inki Dae @ 2013-11-05  7:38 UTC (permalink / raw)
  To: 'Sean Paul'
  Cc: 'Stéphane Marchesin', 'Sylwester Nawrocki',
	'Laurent Pinchart', 'dri-devel'



> -----Original Message-----
> From: Sean Paul [mailto:seanpaul@chromium.org]
> Sent: Tuesday, November 05, 2013 12:44 AM
> To: Inki Dae
> Cc: Thierry Reding; Laurent Pinchart; dri-devel; Sylwester Nawrocki;
> Stéphane Marchesin
> Subject: Re: [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv
> 
> On Mon, Nov 4, 2013 at 6:30 AM, Inki Dae <inki.dae@samsung.com> wrote:
> > 2013/11/4 Thierry Reding <thierry.reding@gmail.com>:
> >> On Tue, Oct 29, 2013 at 08:46:03PM -0700, Stéphane Marchesin wrote:
> >>> On Tue, Oct 29, 2013 at 1:50 PM, Tomasz Figa <tomasz.figa@gmail.com>
> wrote:
> >>>
> >>> > Hi Sean,
> >>> >
> >>> > On Tuesday 29 of October 2013 16:36:47 Sean Paul wrote:
> >>> > > On Mon, Oct 28, 2013 at 7:13 PM, Tomasz Figa
> <tomasz.figa@gmail.com>
> >>> > wrote:
> >>> > > > Hi,
> >>> > > >
> >>> > > > On Wednesday 23 of October 2013 12:09:06 Sean Paul wrote:
> >>> > > >> On Wed, Oct 23, 2013 at 11:53 AM, Dave Airlie
> <airlied@gmail.com>
> >>> > wrote:
> >>> > > >> >>>>> I think we need to start considering a framework where
> >>> > > >> >>>>> subdrivers
> >>> > > >> >>>>> just
> >>> > > >> >>>>> add drm objects themselves, then the toplevel node is
> >>> > > >> >>>>> responsible
> >>> > > >> >>>>> for
> >>> > > >> >>>>> knowing that everything for the current configuration is
> >>> > > >> >>>>> loaded.
> >>> > > >> >>>>
> >>> > > >> >>>> It would be nice to specify the various pieces in dt, then
> have
> >>> > > >> >>>> some
> >>> > > >> >>>> type of drm notifier to the toplevel node when everything
> has
> >>> > > >> >>>> been
> >>> > > >> >>>> probed. Doing it in the dt would allow standalone
> >>> > > >> >>>> drm_bridge/drm_panel
> >>> > > >> >>>> drivers to be transparent as far as the device's drm
> driver is
> >>> > > >> >>>> concerned.
> >>> > > >> >>>>
> >>> > > >> >>>> Sean
> >>> > > >> >>>>
> >>> > > >> >>>>> I realise we may need to make changes to the core drm to
> allow
> >>> > > >> >>>>> this
> >>> > > >> >>>>> but we should probably start to create a strategy for
> fixing
> >>> > > >> >>>>> the
> >>> > > >> >>>>> API
> >>> > > >> >>>>> issues that this throws up.
> >>> > > >> >>>>>
> >>> > > >> >>>>> Note I'm not yet advocating for dynamic addition of nodes
> once
> >>> > > >> >>>>> the
> >>> > > >> >>>>> device is in use, or removing them.
> >>> > > >> >>>
> >>> > > >> >>> I do wonder if we had some sort of tag in the device tree
> for any
> >>> > > >> >>> nodes
> >>> > > >> >>> involved in the display, and the core drm layer would read
> that
> >>> > > >> >>> list,
> >>> > > >> >>> and when every driver registers tick things off, and when
> the
> >>> > > >> >>> last
> >>> > > >> >>> one
> >>> > > >> >>> joins we get a callback and init the drm layer, we'd of
> course
> >>> > > >> >>> have
> >>> > > >> >>> the
> >>> > > >> >>> basic drm layer setup prior to that so we can add the
> objects as
> >>> > > >> >>> the
> >>> > > >> >>> drivers load. It might make development a bit trickier as
> you'd
> >>> > > >> >>> need
> >>> > > >> >>> to make sure someone claimed ownership of all the bits for
> init
> >>> > > >> >>> to
> >>> > > >> >>> proceed.>>
> >>> > > >> >>
> >>> > > >> >> Yeah, that's basically what the strawman looked like in my
> head.
> >>> > > >> >>
> >>> > > >> >> Instead of a property in each node, I was thinking of having
> a
> >>> > > >> >> separate gfx pipe nodes that would have dt pointers to the
> various
> >>> > > >> >> pieces involved in that pipe. This would allow us to
> associate
> >>> > > >> >> standalone entities like bridges and panels with encoders in
> dt
> >>> > > >> >> w/o
> >>> > > >> >> doing it in the drm code. I *think* this should be Ok with
> the dt
> >>> > > >> >> guys
> >>> > > >> >> since it is still describing the hardware, but I think we'd
> have
> >>> > > >> >> to
> >>> > > >> >> make sure it wasn't drm-specific.
> >>> > > >> >
> >>> > > >> > I suppose the question is how much dynamic pipeline
> construction
> >>> > > >> > there
> >>> > > >> > is,
> >>> > > >> >
> >>> > > >> > even on things like radeon and i915 we have dynamic clock
> generator
> >>> > > >> > to
> >>> > > >> > crtc to encoder setups, so I worry about static lists per-
> pipe, so
> >>> > > >> > I
> >>> > > >> > still think just stating all these devices are needed for
> display
> >>> > > >> > and
> >>> > > >> > a list of valid interconnections between them, then we can
> have the
> >>> > > >> > generic code model drm crtc/encoders/connectors on that list,
> and
> >>> > > >> > construct the possible_crtcs /possible_clones etc at that
> stage.
> >>> > > >>
> >>> > > >> I'm, without excuse, hopeless at devicetree, so there are
> probably
> >>> > > >> some violations, but something like:
> >>> > > >>
> >>> > > >> display-pipelines {
> >>> > > >>
> >>> > > >>   required-elements = <&bridge-a &panel-a &encoder-x &encoder-y
> >>> > > >>
> >>> > > >> &crtc-x &crtc-y>;
> >>> > > >>
> >>> > > >>   pipe1 {
> >>> > > >>
> >>> > > >>     bridge = <&bridge-a>;
> >>> > > >>     encoder = <&encoder-x>;
> >>> > > >>     crtc = <&crtc-y>;
> >>> > > >>
> >>> > > >>   };
> >>> > > >>   pipe2 {
> >>> > > >>
> >>> > > >>     encoder = <&encoder-x>;
> >>> > > >>     crtc = <&crtc-x>;
> >>> > > >>
> >>> > > >>   };
> >>> > > >>   pipe3 {
> >>> > > >>
> >>> > > >>     panel = <&panel-a>;
> >>> > > >>     encoder = <&encoder-y>;
> >>> > > >>     crtc = <&crtc-y>;
> >>> > > >>
> >>> > > >>   };
> >>> > > >>
> >>> > > >> };
> >>> > > >>
> >>> > > >> I'm tempted to add connector to the pipe nodes as well, so it's
> >>> > > >> obvious which connector should be used in cases where multiple
> >>> > > >> entities in the pipe implement drm_connector. However, I'm not
> sure
> >>> > > >> if
> >>> > > >> that would be NACKed by dt people.
> >>> > > >>
> >>> > > >> I'm also not sure if there are too many combinations for i915
> and
> >>> > > >> radeon to make this unreasonable. I suppose those devices could
> just
> >>> > > >> use required-elements and leave the pipe nodes out.
> >>> > > >
> >>> > > > Just to put my two cents in, as one of the people involved into
> "the
> >>> > > > device tree movement", I'd say that instead of creating
> artifical
> >>> > > > entities, such as display-pipelines and all of the pipeX'es,
> device
> >>> > > > tree should represent relations between nodes.
> >>> > > >
> >>> > > > According to the generic DT bindings we already have for
> >>> > > > video-interfaces
> >>> > > > [1] your example connection layout would look as follows:
> >>> > > Hi Tomasz
> >>> > > Thanks for sending this along.
> >>> > >
> >>> > > I think the general consensus is that each drm driver should be
> >>> > > implemented as a singular driver. That is, N:1 binding to driver
> >>> > > mapping, where there are N IP blocks. Optional devices (such as
> >>> > > bridges, panels) probably make sense to spin off as standalone
> >>> > > drivers.
> >>> >
> >>> > I believe this is a huge step backwards from current kernel design
> >>> > standards, which prefer modularity.
> >>> >
> >>> > Having multiple IPs being part of the DRM subsystem in a SoC, it
> would be
> >>> > nice to have the possibility to compile just a subset of support for
> them
> >>> > into the kernel and load rest of them as modules. (e.g. basic LCD
> >>> > controller on a mobile phone compiled in and external connectors,
> like
> >>> > HDMI as modules)
> >>> >
> >>> > Not even saying that from development perspective, a huge single
> driver
> >>> > would be much more difficult to test and debug, than several smaller
> >>> > drivers, which could be developed separately.
> >>> >
> >>>
> >>> This is the opposite of our experience, though. A series of small
> drivers
> >>> like what's in drm/exynos can become really tedious/difficult to
> >>> coordinate. If you have separate drivers, everything needs to be
> >>> synchronized, but also has to account for potentially different
> loading
> >>> order.
> >>>
> >>> It seems you're only thinking about the basic case, where you only
> support
> >>> a single resolution, no dpms, no suspend to ram... But when you want
> full
> >>> fledged functionality, then the issues I described become much more
> >>> prevalent.
> >>
> >> I fail to see how this is relevant here. It's fairly clear that even if
> >> a DRM driver is composed of more than a single platform driver, there's
> >> still a single point of coordination (the DRM driver). How does that
> >> have any impact on what features the driver can support? All of the
> >> features will be exposed via DRM, whether you use multiple drivers or a
> >> single monolithic one underneath is completely irrelevant.
> >>
> >
> > +1
> >
> > I think a single drm driver - all sub drivers are controlled by dpms
> > of top level - is definitely what we should go to but it's not clear
> > that a single drm driver should necessary be a huge single driver yet.
> > Even if we use one more sub drivers based on driver model, we can
> > avoid the issues, the loading and power ordering issues.
> >
> > So I'd like to ask question to Google people. Are there really any
> > cases that the loading and power ordering issues can be incurred in
> > case that a drm driver uses one more sub drivers based on driver
> > model?
> 
> I think it makes the code simpler, and more explicit. If you don't
> support dynamic module loading, what's the point in creating modules?
> 

I think we support dynamic module loading. And please know that Exynos drm
has only one integrated module.

> To avoid the init and suspend/resume ordering issues, one must
> register the subdrivers from the main drm driver, and you must not use
> pm_ops. So why incur the extra complexity of modules when we only use
> the probe and that could easily be converted to

The main reason we must register the sub-drivers is the probing order issue.
And I think that we can mitigate the extra complexity of module if we have a
helper that it makes a crtc and a encoder/connector to be connected each
other regardless of the probing order.
For this, you can refer to the below link,
https://git.kernel.org/cgit/linux/kernel/git/daeinki/drm-exynos.git/commit/?
h=exynos-bridge-test

First, I have just quick implemented this feature to show you and to test.
So there would definitely be some problems and ugly codes.

The reason I implemented this feature is that composing the display pipe
line node to be considered for all crtc, encoder/connector drivers and
related ip such as mipi and lvds, would make other side more complex instead
of sub drivers. Actually, is there specific something to apply right now?
how long we should draw the display pipe line node in our head?

So my opinion is let's use non-driver-model based crtc driver and
driver-model based a encoder/connector driver. With the helper or similar
thing, if we don't need to care the probing order, the DT binding of CRTC
devices could be done at top level of drm, and the DT binding of
encoder/connector and related devices could be done at separated drivers. So
this way I think we could simplify more what we want.

And, why I prefer to use encoder/connector driver based on driver-model is
these drivers could be based on i2c and spi busses. I don’t see it's
reasonable that i2c or spi based driver should be non-driver mode.

However, in case using driver-model based drivers, one thing it’s not clear
to me is that we should force the drivers not to use their own pm_ops to
avoid the power ordering issue.

Thanks,
Inki Dae

> 
> #ifdef CONFIG_SOME_GFX_BLOCK
> init_some_gfx_block()
> #endif
> 
> Sean
> 
> 
> > With the re-factoring patch from Sean, I think Exynos drm
> > driver also has no these issues anymore even through Exynos drm driver
> > uses one more sub drivers based on driver model. That is why it's not
> > clear to me yet.
> >
> > Thanks,
> > Inki Dae
> >
> >> Thierry
> >>
> >> _______________________________________________
> >> dri-devel mailing list
> >> dri-devel@lists.freedesktop.org
> >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
> >>
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel@lists.freedesktop.org
> > http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

end of thread, other threads:[~2013-11-05  7:39 UTC | newest]

Thread overview: 93+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-16 19:26 [PATCH v2 00/26] drm/exynos: Refactor parts of the exynos driver Sean Paul
2013-10-16 19:26 ` [PATCH v2 01/26] drm/exynos: Remove useless slab.h include Sean Paul
2013-10-16 19:26 ` [PATCH v2 02/26] drm/exynos: Merge overlay_ops into manager_ops Sean Paul
2013-10-16 19:26 ` [PATCH v2 03/26] drm/exynos: Add an initialize function to manager and display Sean Paul
2013-10-16 19:26 ` [PATCH v2 04/26] drm/exynos: Use manager_op initialize in fimd Sean Paul
2013-10-16 19:26 ` [PATCH v2 05/26] drm/exynos: hdmi: Implement initialize op for hdmi Sean Paul
2013-10-16 19:26 ` [PATCH v2 06/26] drm/exynos: Pass exynos_drm_manager in manager ops instead of dev Sean Paul
2013-10-16 19:26 ` [PATCH v2 07/26] drm/exynos: Remove apply manager callback Sean Paul
2013-10-16 19:26 ` [PATCH v2 08/26] drm/exynos: Remove dpms link between encoder/connector Sean Paul
2013-10-16 19:26 ` [PATCH v2 09/26] drm/exynos: Rename display_op power_on to dpms Sean Paul
2013-10-16 19:26 ` [PATCH v2 10/26] drm/exynos: Don't keep dpms state in encoder Sean Paul
2013-10-16 19:26 ` [PATCH v2 11/26] drm/exynos: Use unsigned long for possible_crtcs Sean Paul
2013-10-16 19:26 ` [PATCH v2 12/26] drm/exynos: Split manager/display/subdrv Sean Paul
2013-10-17  8:21   ` Inki Dae
2013-10-17 14:37     ` Sean Paul
2013-10-18  2:31       ` Inki Dae
2013-10-21 14:46         ` Sean Paul
2013-10-21 21:17           ` Sean Paul
2013-10-22  5:30             ` Inki Dae
2013-10-22 13:45               ` Sean Paul
2013-10-23  2:28                 ` Inki Dae
2013-10-23  2:40                   ` Stéphane Marchesin
2013-10-23  3:38                     ` Inki Dae
2013-10-23  4:03                       ` Stéphane Marchesin
2013-10-23  4:15                         ` Inki Dae
2013-10-23  4:28                           ` Stéphane Marchesin
2013-10-23  4:48                             ` Inki Dae
2013-10-23  5:19                               ` Sean Paul
2013-10-23  5:42                                 ` Inki Dae
2013-10-23 12:20                                   ` Sean Paul
2013-10-23 13:18                                     ` Inki Dae
2013-10-23 14:29                                       ` Dave Airlie
2013-10-23 14:45                                         ` Sean Paul
2013-10-23 15:22                                           ` Dave Airlie
2013-10-23 15:27                                             ` Rob Clark
2013-10-23 15:27                                             ` Sean Paul
2013-10-23 15:28                                               ` Sean Paul
2013-10-23 15:53                                               ` Dave Airlie
2013-10-23 16:09                                                 ` Sean Paul
2013-10-28 16:49                                                   ` Olof Johansson
2013-10-28 17:39                                                     ` Sean Paul
2013-10-28 23:13                                                   ` Tomasz Figa
2013-10-29 19:19                                                     ` Olof Johansson
2013-10-29 19:23                                                       ` Tomasz Figa
2013-10-29 19:47                                                         ` Sylwester Nawrocki
2013-10-29 23:08                                                           ` Laurent Pinchart
2013-10-29 20:36                                                     ` Sean Paul
2013-10-29 20:50                                                       ` Tomasz Figa
2013-10-29 21:29                                                         ` Rob Clark
2013-10-29 23:32                                                           ` Laurent Pinchart
2013-11-04 10:21                                                             ` Thierry Reding
2013-11-04 10:10                                                           ` Thierry Reding
2013-11-04 12:14                                                             ` Rob Clark
2013-11-04 12:52                                                               ` Thierry Reding
2013-11-04 16:12                                                                 ` Daniel Vetter
2013-10-30  3:46                                                         ` Stéphane Marchesin
2013-11-04 10:25                                                           ` Thierry Reding
2013-11-04 11:30                                                             ` Inki Dae
2013-11-04 15:44                                                               ` Sean Paul
2013-11-05  7:38                                                                 ` Inki Dae
2013-10-30 15:32                                                         ` Sean Paul
2013-10-30 15:45                                                           ` Laurent Pinchart
2013-10-30 15:56                                                             ` Sean Paul
2013-11-04 10:12                                                               ` Laurent Pinchart
2013-10-30 15:53                                                           ` Daniel Vetter
2013-11-04 10:13                                                             ` Laurent Pinchart
2013-11-04 10:36                                                           ` Thierry Reding
2013-11-04 10:08                                             ` Thierry Reding
2013-10-24  6:47                                           ` Inki Dae
2013-10-23 14:51                                       ` Rob Clark
2013-10-24  7:46                                         ` Inki Dae
2013-10-25  5:15                                           ` Inki Dae
2013-10-28 20:43                                           ` Rob Clark
2013-10-23  3:39                   ` Sean Paul
2013-10-22  4:55           ` Inki Dae
2013-10-22 10:30   ` Inki Dae
2013-10-23  5:18     ` Inki Dae
2013-10-16 19:26 ` [PATCH v2 13/26] drm/exynos: hdmi: remove the i2c drivers and use devtree Sean Paul
2013-10-16 19:26 ` [PATCH v2 14/26] drm/exynos: Remove exynos_drm_hdmi shim Sean Paul
2013-10-16 19:26 ` [PATCH v2 15/26] drm/exynos: Use drm_mode_copy to copy modes Sean Paul
2013-10-16 19:26 ` [PATCH v2 16/26] drm/exynos: Disable unused crtc planes from crtc Sean Paul
2013-10-16 19:26 ` [PATCH v2 17/26] drm/exynos: Add mode_set manager operation Sean Paul
2013-10-16 19:26 ` [PATCH v2 18/26] drm/exynos: Implement mode_fixup " Sean Paul
2013-10-16 19:26 ` [PATCH v2 19/26] drm/exynos: Use mode_set to configure fimd Sean Paul
2013-10-16 19:26 ` [PATCH v2 20/26] drm/exynos: Remove unused/useless fimd_context members Sean Paul
2013-10-16 19:26 ` [PATCH v2 21/26] drm/exynos: Move dp driver from video/ to drm/ Sean Paul
2013-10-16 19:26 ` [PATCH v2 22/26] drm/exynos: Move display implementation into dp Sean Paul
2013-10-16 19:26 ` [PATCH v2 23/26] ARM: dts: Move display-timings node from fimd to dp Sean Paul
2013-10-16 19:26 ` [PATCH v2 24/26] drm/exynos: Implement dpms display callback in DP Sean Paul
2013-10-16 19:26 ` [PATCH v2 25/26] drm/exynos: Clean up FIMD power on/off routines Sean Paul
2013-10-16 19:26 ` [PATCH v2 26/26] drm/exynos: Consolidate suspend/resume in drm_drv Sean Paul
2013-10-16 20:40   ` Sean Paul
2013-10-17  5:10     ` Inki Dae

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.