All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC 00/46] Preview of imx-drm cleanup series
@ 2014-01-02 21:25 ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-02 21:25 UTC (permalink / raw)
  To: linux-arm-kernel

Here is my large patch series which cleans up imx-drm, and gets it ready
to move out of drivers/staging.  This is a preview only.

One of these patches introduces a generic helper in drivers/base which
can be used by any subsystem to assemble a sub-devices together and
complete the probe of a subsystem when all devices are present - and
tear it down when any of those devices go away - this is patch 26.

Example usage (with imx-drm) is illustrated in patches 27 through to
41.

Some of this duplicates Fabio's imx-drm HDMI patch; indeed some of
the changes which were fed back to Fabio are here as their individual
patches.  I've not updated Fabio's patch in this series since he sent
an updated version to Greg for merging.

I've also included here support for ALSA based HDMI audio - if you
omit the new HDMI drivers from this, it gives a net reduction in LoC.

Finally, the last patch attempts to resolve a problem with the way
imx-drm works - but this is fundamentally unsolvable without
introducing new DT properties to properly specify the mux IDs.

I'm only sending this to a limited number of people for comments at
present since it's a large series, and the selection of people from
maintainers is rather large.

 arch/arm/boot/dts/imx51-babbage.dts         |   10 +-
 arch/arm/boot/dts/imx53-m53evk.dts          |    8 +-
 arch/arm/boot/dts/imx53-mba53.dts           |    6 +
 arch/arm/boot/dts/imx53-qsb.dts             |    8 +-
 arch/arm/boot/dts/imx6dl.dtsi               |    5 +
 arch/arm/boot/dts/imx6q.dtsi                |    5 +
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi      |    6 +
 arch/arm/boot/dts/imx6qdl.dtsi              |    9 +
 drivers/base/Makefile                       |    2 +-
 drivers/base/component.c                    |  379 ++++++
 drivers/gpu/drm/drm_crtc_helper.c           |   39 +-
 drivers/staging/imx-drm/Kconfig             |    6 +
 drivers/staging/imx-drm/Makefile            |    5 +-
 drivers/staging/imx-drm/dw-hdmi-audio.c     |  550 ++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h     |   13 +
 drivers/staging/imx-drm/imx-drm-core.c      |  827 ++++---------
 drivers/staging/imx-drm/imx-drm.h           |   38 +-
 drivers/staging/imx-drm/imx-fb.c            |   47 -
 drivers/staging/imx-drm/imx-fbdev.c         |   74 --
 drivers/staging/imx-drm/imx-hdmi.c          | 1796 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.h          | 1037 ++++++++++++++++
 drivers/staging/imx-drm/imx-ldb.c           |  125 +--
 drivers/staging/imx-drm/imx-tve.c           |  134 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |    1 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   15 +-
 drivers/staging/imx-drm/ipu-v3/ipu-di.c     |  317 ++---
 drivers/staging/imx-drm/ipuv3-crtc.c        |   59 +-
 drivers/staging/imx-drm/parallel-display.c  |  100 +-
 include/drm/drm_crtc_helper.h               |    1 +
 include/linux/component.h                   |   31 +
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |    1 +
 31 files changed, 4519 insertions(+), 1135 deletions(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h
 delete mode 100644 drivers/staging/imx-drm/imx-fb.c
 delete mode 100644 drivers/staging/imx-drm/imx-fbdev.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.h
 create mode 100644 include/linux/component.h

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 00/46] Preview of imx-drm cleanup series
@ 2014-01-02 21:25 ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-02 21:25 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, linux-arm-kernel, dri-devel

Here is my large patch series which cleans up imx-drm, and gets it ready
to move out of drivers/staging.  This is a preview only.

One of these patches introduces a generic helper in drivers/base which
can be used by any subsystem to assemble a sub-devices together and
complete the probe of a subsystem when all devices are present - and
tear it down when any of those devices go away - this is patch 26.

Example usage (with imx-drm) is illustrated in patches 27 through to
41.

Some of this duplicates Fabio's imx-drm HDMI patch; indeed some of
the changes which were fed back to Fabio are here as their individual
patches.  I've not updated Fabio's patch in this series since he sent
an updated version to Greg for merging.

I've also included here support for ALSA based HDMI audio - if you
omit the new HDMI drivers from this, it gives a net reduction in LoC.

Finally, the last patch attempts to resolve a problem with the way
imx-drm works - but this is fundamentally unsolvable without
introducing new DT properties to properly specify the mux IDs.

I'm only sending this to a limited number of people for comments at
present since it's a large series, and the selection of people from
maintainers is rather large.

 arch/arm/boot/dts/imx51-babbage.dts         |   10 +-
 arch/arm/boot/dts/imx53-m53evk.dts          |    8 +-
 arch/arm/boot/dts/imx53-mba53.dts           |    6 +
 arch/arm/boot/dts/imx53-qsb.dts             |    8 +-
 arch/arm/boot/dts/imx6dl.dtsi               |    5 +
 arch/arm/boot/dts/imx6q.dtsi                |    5 +
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi      |    6 +
 arch/arm/boot/dts/imx6qdl.dtsi              |    9 +
 drivers/base/Makefile                       |    2 +-
 drivers/base/component.c                    |  379 ++++++
 drivers/gpu/drm/drm_crtc_helper.c           |   39 +-
 drivers/staging/imx-drm/Kconfig             |    6 +
 drivers/staging/imx-drm/Makefile            |    5 +-
 drivers/staging/imx-drm/dw-hdmi-audio.c     |  550 ++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h     |   13 +
 drivers/staging/imx-drm/imx-drm-core.c      |  827 ++++---------
 drivers/staging/imx-drm/imx-drm.h           |   38 +-
 drivers/staging/imx-drm/imx-fb.c            |   47 -
 drivers/staging/imx-drm/imx-fbdev.c         |   74 --
 drivers/staging/imx-drm/imx-hdmi.c          | 1796 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.h          | 1037 ++++++++++++++++
 drivers/staging/imx-drm/imx-ldb.c           |  125 +--
 drivers/staging/imx-drm/imx-tve.c           |  134 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |    1 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   15 +-
 drivers/staging/imx-drm/ipu-v3/ipu-di.c     |  317 ++---
 drivers/staging/imx-drm/ipuv3-crtc.c        |   59 +-
 drivers/staging/imx-drm/parallel-display.c  |  100 +-
 include/drm/drm_crtc_helper.h               |    1 +
 include/linux/component.h                   |   31 +
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |    1 +
 31 files changed, 4519 insertions(+), 1135 deletions(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h
 delete mode 100644 drivers/staging/imx-drm/imx-fb.c
 delete mode 100644 drivers/staging/imx-drm/imx-fbdev.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.h
 create mode 100644 include/linux/component.h

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 01/46] imx-drm: imx-drm-core: use the crtc drm device for vblank
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:25   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:25 UTC (permalink / raw)
  To: linux-arm-kernel

There are a couple of ways to get at the drm_device for the vblank
operations.  One of them is via the private imxdrm structure, the
other is via the DRM crtc structure, which also stores a pointer.
Use the DRM method instead of our own method.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 96e4eee344ef..9aa5eaab6539 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -142,19 +142,19 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
-	return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
 
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
 {
-	drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
 
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
 {
-	drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 
-- 
1.7.4.4

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

* [PATCH RFC 01/46] imx-drm: imx-drm-core: use the crtc drm device for vblank
@ 2014-01-02 21:25   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:25 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

There are a couple of ways to get at the drm_device for the vblank
operations.  One of them is via the private imxdrm structure, the
other is via the DRM crtc structure, which also stores a pointer.
Use the DRM method instead of our own method.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 96e4eee344ef..9aa5eaab6539 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -142,19 +142,19 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
-	return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
 
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
 {
-	drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
 
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
 {
-	drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+	drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 
-- 
1.7.4.4

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

* [PATCH RFC 02/46] imx-drm: imx-drm-core: avoid going the long route round for drm_device
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:25   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:25 UTC (permalink / raw)
  To: linux-arm-kernel

We have the drm_device available, so rather than storing it and then
using the stored version, us the one we already have available to us.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 9aa5eaab6539..242e8db218ac 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -88,9 +88,9 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 	imx_drm_device_put();
 
-	drm_vblank_cleanup(imxdrm->drm);
-	drm_kms_helper_poll_fini(imxdrm->drm);
-	drm_mode_config_cleanup(imxdrm->drm);
+	drm_vblank_cleanup(drm);
+	drm_kms_helper_poll_fini(drm);
+	drm_mode_config_cleanup(drm);
 
 	return 0;
 }
@@ -424,15 +424,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	mutex_lock(&imxdrm->mutex);
 
-	drm_kms_helper_poll_init(imxdrm->drm);
+	drm_kms_helper_poll_init(drm);
 
 	/* setup the grouping for the legacy output */
-	ret = drm_mode_group_init_legacy_group(imxdrm->drm,
-			&imxdrm->drm->primary->mode_group);
+	ret = drm_mode_group_init_legacy_group(drm,
+			&drm->primary->mode_group);
 	if (ret)
 		goto err_kms;
 
-	ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
 
@@ -441,7 +441,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 * by drm timer once a current process gives up ownership of
 	 * vblank event.(after drm_vblank_put function is called)
 	 */
-	imxdrm->drm->vblank_disable_allowed = true;
+	drm->vblank_disable_allowed = true;
 
 	if (!imx_drm_device_get()) {
 		ret = -EINVAL;
-- 
1.7.4.4

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

* [PATCH RFC 02/46] imx-drm: imx-drm-core: avoid going the long route round for drm_device
@ 2014-01-02 21:25   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:25 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

We have the drm_device available, so rather than storing it and then
using the stored version, us the one we already have available to us.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 9aa5eaab6539..242e8db218ac 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -88,9 +88,9 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 	imx_drm_device_put();
 
-	drm_vblank_cleanup(imxdrm->drm);
-	drm_kms_helper_poll_fini(imxdrm->drm);
-	drm_mode_config_cleanup(imxdrm->drm);
+	drm_vblank_cleanup(drm);
+	drm_kms_helper_poll_fini(drm);
+	drm_mode_config_cleanup(drm);
 
 	return 0;
 }
@@ -424,15 +424,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	mutex_lock(&imxdrm->mutex);
 
-	drm_kms_helper_poll_init(imxdrm->drm);
+	drm_kms_helper_poll_init(drm);
 
 	/* setup the grouping for the legacy output */
-	ret = drm_mode_group_init_legacy_group(imxdrm->drm,
-			&imxdrm->drm->primary->mode_group);
+	ret = drm_mode_group_init_legacy_group(drm,
+			&drm->primary->mode_group);
 	if (ret)
 		goto err_kms;
 
-	ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
 
@@ -441,7 +441,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 * by drm timer once a current process gives up ownership of
 	 * vblank event.(after drm_vblank_put function is called)
 	 */
-	imxdrm->drm->vblank_disable_allowed = true;
+	drm->vblank_disable_allowed = true;
 
 	if (!imx_drm_device_get()) {
 		ret = -EINVAL;
-- 
1.7.4.4

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

* [PATCH RFC 03/46] imx-drm: imx-drm-core: merge imx_drm_crtc_register() into imx_drm_add_crtc()
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

There's no reason for this to be a separate function; merge the
two together.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   33 ++++++++-----------------------
 1 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 242e8db218ac..05dd24ee80dd 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -370,29 +370,6 @@ static void imx_drm_connector_unregister(
 }
 
 /*
- * register a crtc to the drm core
- */
-static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	int ret;
-
-	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
-	if (ret)
-		return ret;
-
-	drm_crtc_helper_add(imx_drm_crtc->crtc,
-			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
-	drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
-			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
  * Called by the CRTC driver when all CRTCs are registered. This
  * puts all the pieces together and initializes the driver.
  * Once this is called no more CRTCs can be registered since
@@ -535,10 +512,18 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
 	*new_crtc = imx_drm_crtc;
 
-	ret = imx_drm_crtc_register(imx_drm_crtc);
+	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
 	if (ret)
 		goto err_register;
 
+	drm_crtc_helper_add(crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+	drm_crtc_init(imxdrm->drm, crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+
+	drm_mode_group_reinit(imxdrm->drm);
+
 	imx_drm_update_possible_crtcs();
 
 	mutex_unlock(&imxdrm->mutex);
-- 
1.7.4.4

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

* [PATCH RFC 03/46] imx-drm: imx-drm-core: merge imx_drm_crtc_register() into imx_drm_add_crtc()
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

There's no reason for this to be a separate function; merge the
two together.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   33 ++++++++-----------------------
 1 files changed, 9 insertions(+), 24 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 242e8db218ac..05dd24ee80dd 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -370,29 +370,6 @@ static void imx_drm_connector_unregister(
 }
 
 /*
- * register a crtc to the drm core
- */
-static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	int ret;
-
-	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
-	if (ret)
-		return ret;
-
-	drm_crtc_helper_add(imx_drm_crtc->crtc,
-			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
-	drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
-			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
  * Called by the CRTC driver when all CRTCs are registered. This
  * puts all the pieces together and initializes the driver.
  * Once this is called no more CRTCs can be registered since
@@ -535,10 +512,18 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
 	*new_crtc = imx_drm_crtc;
 
-	ret = imx_drm_crtc_register(imx_drm_crtc);
+	ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
 	if (ret)
 		goto err_register;
 
+	drm_crtc_helper_add(crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+	drm_crtc_init(imxdrm->drm, crtc,
+			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+
+	drm_mode_group_reinit(imxdrm->drm);
+
 	imx_drm_update_possible_crtcs();
 
 	mutex_unlock(&imxdrm->mutex);
-- 
1.7.4.4

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

* [PATCH RFC 04/46] imx-drm: ipu-v3: more inteligent DI clock selection
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

The DI clock selection was very rudimentary: it would statically use
either the IPU internal clock or the DI external clock depending on
which "encoder" was being used.  In the case of HDMI, it would always
use the IPU clock.

Moreover, using the IPU clock resulted in fractional divisors, which
are achieved by skipping clock pulses.  This can result in the HDMI
PHY PLL being frequency modulated, and the attached device is then
unable to properly lock on to the TMDS clock.

We need at least 1% accurate and stable clocks for HDMI.

Arrange for the DI clock to be sourced from the IPU internal clock
if it can satisfy our requirements, otherwise switch to the DI
external clock and try and set the external clock to our desired
pixel clock rate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |   54 +++++++++++++++++++++++++++++-
 1 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 948a49b289ef..8c7241bb435c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -544,10 +544,48 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
 		return -EINVAL;
 
+	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		sig->pixelclock);
+
+	/*
+	 * CLKMODE_EXT means we must use the DI clock: this is needed
+	 * for things like LVDS which needs to feed the DI and LDB with
+	 * the same pixel clock.
+	 *
+	 * For other interfaces, we can arbitarily select between the DI
+	 * specific clock and the internal IPU clock.  See DI_GENERAL
+	 * bit 20.  We select the IPU clock if it can give us a clock
+	 * rate within 1% of the requested frequency, otherwise we use
+	 * the DI clock.
+	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_EXT)
 		parent = di->clk_di;
-	else
-		parent = di->clk_ipu;
+	else {
+		unsigned long rate, clkrate;
+		unsigned div, error;
+
+		clkrate = clk_get_rate(di->clk_ipu);
+		div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+		rate = clkrate / div;
+
+		error = rate / (sig->pixelclock / 1000);
+
+		dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
+			rate, div, (signed)(error - 1000) / 10, error % 10);
+
+		/* Allow a 1% error */
+		if (error < 1010 && error >= 990) {
+			parent = di->clk_ipu;
+		} else {
+			parent = di->clk_di;
+
+			ret = clk_set_rate(parent, sig->pixelclock);
+			if (ret)
+				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+		}
+	}
 
 	ret = clk_set_parent(di->clk_di_pixel, parent);
 	if (ret) {
@@ -557,6 +595,11 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 		return ret;
 	}
 
+	/*
+	 * CLKMODE_SYNC means that we want the DI to be clocked at the
+	 * same rate as the parent clock.  This is needed (eg) for LDB
+	 * which needs to be fed with the same pixel clock.
+	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
 		round = clk_get_rate(parent);
 	else
@@ -564,6 +607,13 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 
 	ret = clk_set_rate(di->clk_di_pixel, round);
 
+	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+		sig->pixelclock,
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		parent == di->clk_di ? "DI" : "IPU",
+		clk_get_rate(di->clk_di_pixel));
+
 	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
 		sig->h_end_width;
 	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
-- 
1.7.4.4

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

* [PATCH RFC 04/46] imx-drm: ipu-v3: more inteligent DI clock selection
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The DI clock selection was very rudimentary: it would statically use
either the IPU internal clock or the DI external clock depending on
which "encoder" was being used.  In the case of HDMI, it would always
use the IPU clock.

Moreover, using the IPU clock resulted in fractional divisors, which
are achieved by skipping clock pulses.  This can result in the HDMI
PHY PLL being frequency modulated, and the attached device is then
unable to properly lock on to the TMDS clock.

We need at least 1% accurate and stable clocks for HDMI.

Arrange for the DI clock to be sourced from the IPU internal clock
if it can satisfy our requirements, otherwise switch to the DI
external clock and try and set the external clock to our desired
pixel clock rate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |   54 +++++++++++++++++++++++++++++-
 1 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 948a49b289ef..8c7241bb435c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -544,10 +544,48 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
 		return -EINVAL;
 
+	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		sig->pixelclock);
+
+	/*
+	 * CLKMODE_EXT means we must use the DI clock: this is needed
+	 * for things like LVDS which needs to feed the DI and LDB with
+	 * the same pixel clock.
+	 *
+	 * For other interfaces, we can arbitarily select between the DI
+	 * specific clock and the internal IPU clock.  See DI_GENERAL
+	 * bit 20.  We select the IPU clock if it can give us a clock
+	 * rate within 1% of the requested frequency, otherwise we use
+	 * the DI clock.
+	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_EXT)
 		parent = di->clk_di;
-	else
-		parent = di->clk_ipu;
+	else {
+		unsigned long rate, clkrate;
+		unsigned div, error;
+
+		clkrate = clk_get_rate(di->clk_ipu);
+		div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+		rate = clkrate / div;
+
+		error = rate / (sig->pixelclock / 1000);
+
+		dev_dbg(di->ipu->dev, "  IPU clock can give %lu with divider %u, error %d.%u%%\n",
+			rate, div, (signed)(error - 1000) / 10, error % 10);
+
+		/* Allow a 1% error */
+		if (error < 1010 && error >= 990) {
+			parent = di->clk_ipu;
+		} else {
+			parent = di->clk_di;
+
+			ret = clk_set_rate(parent, sig->pixelclock);
+			if (ret)
+				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+		}
+	}
 
 	ret = clk_set_parent(di->clk_di_pixel, parent);
 	if (ret) {
@@ -557,6 +595,11 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 		return ret;
 	}
 
+	/*
+	 * CLKMODE_SYNC means that we want the DI to be clocked at the
+	 * same rate as the parent clock.  This is needed (eg) for LDB
+	 * which needs to be fed with the same pixel clock.
+	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
 		round = clk_get_rate(parent);
 	else
@@ -564,6 +607,13 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 
 	ret = clk_set_rate(di->clk_di_pixel, round);
 
+	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+		sig->pixelclock,
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		parent == di->clk_di ? "DI" : "IPU",
+		clk_get_rate(di->clk_di_pixel));
+
 	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
 		sig->h_end_width;
 	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
-- 
1.7.4.4

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

* [PATCH RFC 05/46] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate()
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

This is nonsense; clk_round_rate() is just clk_set_rate() without the
side effect of changing the hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 8c7241bb435c..d766e18bfca0 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -560,9 +560,10 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	 * rate within 1% of the requested frequency, otherwise we use
 	 * the DI clock.
 	 */
-	if (sig->clkflags & IPU_DI_CLKMODE_EXT)
+	round = sig->pixelclock;
+	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
 		parent = di->clk_di;
-	else {
+	} else {
 		unsigned long rate, clkrate;
 		unsigned div, error;
 
@@ -584,6 +585,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 			ret = clk_set_rate(parent, sig->pixelclock);
 			if (ret)
 				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+
+			/* Use the integer divisor rate - avoid fractional dividers */
+			round = rate;
 		}
 	}
 
@@ -599,11 +603,12 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	 * CLKMODE_SYNC means that we want the DI to be clocked at the
 	 * same rate as the parent clock.  This is needed (eg) for LDB
 	 * which needs to be fed with the same pixel clock.
+	 *
+	 * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
+	 * same as clk_set_rate(clk, rate);
 	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
 		round = clk_get_rate(parent);
-	else
-		round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
 
 	ret = clk_set_rate(di->clk_di_pixel, round);
 
-- 
1.7.4.4

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

* [PATCH RFC 05/46] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate()
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

This is nonsense; clk_round_rate() is just clk_set_rate() without the
side effect of changing the hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index 8c7241bb435c..d766e18bfca0 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -560,9 +560,10 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	 * rate within 1% of the requested frequency, otherwise we use
 	 * the DI clock.
 	 */
-	if (sig->clkflags & IPU_DI_CLKMODE_EXT)
+	round = sig->pixelclock;
+	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
 		parent = di->clk_di;
-	else {
+	} else {
 		unsigned long rate, clkrate;
 		unsigned div, error;
 
@@ -584,6 +585,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 			ret = clk_set_rate(parent, sig->pixelclock);
 			if (ret)
 				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+
+			/* Use the integer divisor rate - avoid fractional dividers */
+			round = rate;
 		}
 	}
 
@@ -599,11 +603,12 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 	 * CLKMODE_SYNC means that we want the DI to be clocked at the
 	 * same rate as the parent clock.  This is needed (eg) for LDB
 	 * which needs to be fed with the same pixel clock.
+	 *
+	 * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
+	 * same as clk_set_rate(clk, rate);
 	 */
 	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
 		round = clk_get_rate(parent);
-	else
-		round = clk_round_rate(di->clk_di_pixel, sig->pixelclock);
 
 	ret = clk_set_rate(di->clk_di_pixel, round);
 
-- 
1.7.4.4

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

* [PATCH RFC 06/46] imx-drm: ipu-v3: more clocking fixes
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

There's no point in using the clk API for this; we end up having to
violate the layering this provides.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |  328 ++++++++++---------------------
 1 files changed, 105 insertions(+), 223 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index d766e18bfca0..82a9ebad697c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -19,9 +19,6 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
 
 #include "imx-ipu-v3.h"
 #include "ipu-prv.h"
@@ -33,10 +30,7 @@ struct ipu_di {
 	struct clk *clk_di;	/* display input clock */
 	struct clk *clk_ipu;	/* IPU bus clock */
 	struct clk *clk_di_pixel; /* resulting pixel clock */
-	struct clk_hw clk_hw_out;
-	char *clk_name;
 	bool inuse;
-	unsigned long clkflags;
 	struct ipu_soc *ipu;
 };
 
@@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
 	writel(value, di->base + offset);
 }
 
-static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
-{
-	u64 tmp = inrate;
-	int div;
-
-	tmp *= 16;
-
-	do_div(tmp, outrate);
-
-	div = tmp;
-
-	if (div < 0x10)
-		div = 0x10;
-
-#ifdef WTF_IS_THIS
-	/*
-	 * Freescale has this in their Kernel. It is neither clear what
-	 * it does nor why it does it
-	 */
-	if (div & 0x10)
-		div &= ~0x7;
-	else {
-		/* Round up divider if it gets us closer to desired pix clk */
-		if ((div & 0xC) == 0xC) {
-			div += 0x10;
-			div &= ~0xF;
-		}
-	}
-#endif
-	return div;
-}
-
-static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	unsigned long outrate;
-	u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
-
-	if (div < 0x10)
-		div = 0x10;
-
-	outrate = (parent_rate / div) * 16;
-
-	return outrate;
-}
-
-static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long *prate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	unsigned long outrate;
-	int div;
-	u32 val;
-
-	div = ipu_di_clk_calc_div(*prate, rate);
-
-	outrate = (*prate / div) * 16;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
-		outrate = *prate / 2;
-
-	dev_dbg(di->ipu->dev,
-		"%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
-			__func__, *prate, div, outrate, rate);
-
-	return outrate;
-}
-
-static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long parent_rate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	int div;
-	u32 clkgen0;
-
-	clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
-
-	div = ipu_di_clk_calc_div(parent_rate, rate);
-
-	ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
-
-	dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
-			__func__, parent_rate, rate, div);
-	return 0;
-}
-
-static u8 clk_di_get_parent(struct clk_hw *hw)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	u32 val;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
-}
-
-static int clk_di_set_parent(struct clk_hw *hw, u8 index)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	u32 val;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	if (index)
-		val |= DI_GEN_DI_CLK_EXT;
-	else
-		val &= ~DI_GEN_DI_CLK_EXT;
-
-	ipu_di_write(di, val, DI_GENERAL);
-
-	return 0;
-}
-
-static struct clk_ops clk_di_ops = {
-	.round_rate = clk_di_round_rate,
-	.set_rate = clk_di_set_rate,
-	.recalc_rate = clk_di_recalc_rate,
-	.set_parent = clk_di_set_parent,
-	.get_parent = clk_di_get_parent,
-};
-
 static void ipu_di_data_wave_config(struct ipu_di *di,
 				     int wave_gen,
 				     int access_size, int component_size)
@@ -528,42 +398,58 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
 		ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
 }
 
-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+static void ipu_di_config_clock(struct ipu_di *di,
+	const struct ipu_di_signal_cfg *sig)
 {
-	u32 reg;
-	u32 di_gen, vsync_cnt;
-	u32 div;
-	u32 h_total, v_total;
-	int ret;
-	unsigned long round;
-	struct clk *parent;
+	struct clk *clk;
+	unsigned clkgen0;
+	uint32_t val;
 
-	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
-		di->id, sig->width, sig->height);
+	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+		/*
+		 * CLKMODE_EXT means we must use the DI clock: this is
+		 * needed for things like LVDS which needs to feed the
+		 * DI and LDB with the same pixel clock.
+		 */
+		clk = di->clk_di;
+
+		if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+			/*
+			 * CLKMODE_SYNC means that we want the DI to be
+			 * clocked at the same rate as the parent clock.
+			 * This is needed (eg) for LDB which needs to be
+			 * fed with the same pixel clock.  We assume that
+			 * the LDB clock has already been set correctly.
+			 */
+			clkgen0 = 1 << 4;
+		} else {
+			/*
+			 * We can use the divider.  We should really have
+			 * a flag here indicating whether the bridge can
+			 * cope with a fractional divider or not.  For the
+			 * time being, let's go for simplicitly and
+			 * reliability.
+			 */
+			unsigned long in_rate;
+			unsigned div;
 
-	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
-		return -EINVAL;
+			clk_set_rate(clk, sig->pixelclock);
 
-	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
-		clk_get_rate(di->clk_ipu),
-		clk_get_rate(di->clk_di),
-		sig->pixelclock);
+			in_rate = clk_get_rate(clk);
+			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			if (div == 0)
+				div = 1;
 
-	/*
-	 * CLKMODE_EXT means we must use the DI clock: this is needed
-	 * for things like LVDS which needs to feed the DI and LDB with
-	 * the same pixel clock.
-	 *
-	 * For other interfaces, we can arbitarily select between the DI
-	 * specific clock and the internal IPU clock.  See DI_GENERAL
-	 * bit 20.  We select the IPU clock if it can give us a clock
-	 * rate within 1% of the requested frequency, otherwise we use
-	 * the DI clock.
-	 */
-	round = sig->pixelclock;
-	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
-		parent = di->clk_di;
+			clkgen0 = div << 4;
+		}
 	} else {
+		/*
+		 * For other interfaces, we can arbitarily select between
+		 * the DI specific clock and the internal IPU clock.  See
+		 * DI_GENERAL bit 20.  We select the IPU clock if it can
+		 * give us a clock rate within 1% of the requested frequency,
+		 * otherwise we use the DI clock.
+		 */
 		unsigned long rate, clkrate;
 		unsigned div, error;
 
@@ -578,54 +464,80 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 
 		/* Allow a 1% error */
 		if (error < 1010 && error >= 990) {
-			parent = di->clk_ipu;
+			clk = di->clk_ipu;
+
+			clkgen0 = div << 4;
 		} else {
-			parent = di->clk_di;
+			unsigned long in_rate;
+			unsigned div;
+
+			clk = di->clk_di;
 
-			ret = clk_set_rate(parent, sig->pixelclock);
-			if (ret)
-				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+			clk_set_rate(clk, sig->pixelclock);
 
-			/* Use the integer divisor rate - avoid fractional dividers */
-			round = rate;
+			in_rate = clk_get_rate(clk);
+			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			if (div == 0)
+				div = 1;
+
+			clkgen0 = div << 4;
 		}
 	}
 
-	ret = clk_set_parent(di->clk_di_pixel, parent);
-	if (ret) {
-		dev_err(di->ipu->dev,
-			"setting pixel clock to parent %s failed with %d\n",
-				__clk_get_name(parent), ret);
-		return ret;
-	}
+	di->clk_di_pixel = clk;
+
+	/* Set the divider */
+	ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
 
 	/*
-	 * CLKMODE_SYNC means that we want the DI to be clocked at the
-	 * same rate as the parent clock.  This is needed (eg) for LDB
-	 * which needs to be fed with the same pixel clock.
-	 *
-	 * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
-	 * same as clk_set_rate(clk, rate);
+	 * Set the high/low periods.  Bits 24:16 give us the falling edge,
+	 * and bits 8:0 give the rising edge.  LSB is fraction, and is
+	 * based on the divider above.  We want a 50% duty cycle, so set
+	 * the falling edge to be half the divider.
 	 */
-	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
-		round = clk_get_rate(parent);
+	ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
 
-	ret = clk_set_rate(di->clk_di_pixel, round);
+	/* Finally select the input clock */
+	val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+	if (clk == di->clk_di)
+		val |= DI_GEN_DI_CLK_EXT;
+	ipu_di_write(di, val, DI_GENERAL);
 
-	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
 		sig->pixelclock,
 		clk_get_rate(di->clk_ipu),
 		clk_get_rate(di->clk_di),
-		parent == di->clk_di ? "DI" : "IPU",
-		clk_get_rate(di->clk_di_pixel));
+		clk == di->clk_di ? "DI" : "IPU",
+		clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 reg;
+	u32 di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+
+	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+		di->id, sig->width, sig->height);
+
+	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+		return -EINVAL;
 
 	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
 		sig->h_end_width;
 	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
 		sig->v_end_width;
 
+	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		sig->pixelclock);
+
 	mutex_lock(&di_mutex);
 
+	ipu_di_config_clock(di, sig);
+
 	div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
 	div = div / 16;		/* Now divider is integer portion */
 
@@ -709,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
 
 int ipu_di_enable(struct ipu_di *di)
 {
-	int ret = clk_prepare_enable(di->clk_di_pixel);
+	int ret;
+
+	WARN_ON(IS_ERR(di->clk_di_pixel));
+
+	ret = clk_prepare_enable(di->clk_di_pixel);
 	if (ret)
 		return ret;
 
@@ -721,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable);
 
 int ipu_di_disable(struct ipu_di *di)
 {
+	WARN_ON(IS_ERR(di->clk_di_pixel));
+
 	ipu_module_disable(di->ipu, di->module);
 
 	clk_disable_unprepare(di->clk_di_pixel);
@@ -776,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 		u32 module, struct clk *clk_ipu)
 {
 	struct ipu_di *di;
-	int ret;
-	const char *di_parent[2];
-	struct clk_init_data init = {
-		.ops = &clk_di_ops,
-		.num_parents = 2,
-		.flags = 0,
-	};
 
 	if (id > 1)
 		return -ENODEV;
@@ -804,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 	if (!di->base)
 		return -ENOMEM;
 
-	di_parent[0] = __clk_get_name(di->clk_ipu);
-	di_parent[1] = __clk_get_name(di->clk_di);
-
 	ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
 
-	init.parent_names = (const char **)&di_parent;
-	di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
-			dev_name(dev), id);
-	if (!di->clk_name)
-		return -ENOMEM;
-
-	init.name = di->clk_name;
-
-	di->clk_hw_out.init = &init;
-	di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
-
-	if (IS_ERR(di->clk_di_pixel)) {
-		ret = PTR_ERR(di->clk_di_pixel);
-		goto failed_clk_register;
-	}
-
 	dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
 			id, base, di->base);
 	di->inuse = false;
 	di->ipu = ipu;
 
 	return 0;
-
-failed_clk_register:
-
-	kfree(di->clk_name);
-
-	return ret;
 }
 
 void ipu_di_exit(struct ipu_soc *ipu, int id)
 {
-	struct ipu_di *di = ipu->di_priv[id];
-
-	clk_unregister(di->clk_di_pixel);
-	kfree(di->clk_name);
 }
-- 
1.7.4.4

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

* [PATCH RFC 06/46] imx-drm: ipu-v3: more clocking fixes
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

There's no point in using the clk API for this; we end up having to
violate the layering this provides.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/ipu-v3/ipu-di.c |  328 ++++++++++---------------------
 1 files changed, 105 insertions(+), 223 deletions(-)

diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
index d766e18bfca0..82a9ebad697c 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c
@@ -19,9 +19,6 @@
 #include <linux/io.h>
 #include <linux/err.h>
 #include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/clk-provider.h>
-#include <linux/clkdev.h>
 
 #include "imx-ipu-v3.h"
 #include "ipu-prv.h"
@@ -33,10 +30,7 @@ struct ipu_di {
 	struct clk *clk_di;	/* display input clock */
 	struct clk *clk_ipu;	/* IPU bus clock */
 	struct clk *clk_di_pixel; /* resulting pixel clock */
-	struct clk_hw clk_hw_out;
-	char *clk_name;
 	bool inuse;
-	unsigned long clkflags;
 	struct ipu_soc *ipu;
 };
 
@@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
 	writel(value, di->base + offset);
 }
 
-static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate)
-{
-	u64 tmp = inrate;
-	int div;
-
-	tmp *= 16;
-
-	do_div(tmp, outrate);
-
-	div = tmp;
-
-	if (div < 0x10)
-		div = 0x10;
-
-#ifdef WTF_IS_THIS
-	/*
-	 * Freescale has this in their Kernel. It is neither clear what
-	 * it does nor why it does it
-	 */
-	if (div & 0x10)
-		div &= ~0x7;
-	else {
-		/* Round up divider if it gets us closer to desired pix clk */
-		if ((div & 0xC) == 0xC) {
-			div += 0x10;
-			div &= ~0xF;
-		}
-	}
-#endif
-	return div;
-}
-
-static unsigned long clk_di_recalc_rate(struct clk_hw *hw,
-		unsigned long parent_rate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	unsigned long outrate;
-	u32 div = ipu_di_read(di, DI_BS_CLKGEN0);
-
-	if (div < 0x10)
-		div = 0x10;
-
-	outrate = (parent_rate / div) * 16;
-
-	return outrate;
-}
-
-static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long *prate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	unsigned long outrate;
-	int div;
-	u32 val;
-
-	div = ipu_di_clk_calc_div(*prate, rate);
-
-	outrate = (*prate / div) * 16;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2)
-		outrate = *prate / 2;
-
-	dev_dbg(di->ipu->dev,
-		"%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n",
-			__func__, *prate, div, outrate, rate);
-
-	return outrate;
-}
-
-static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate,
-				unsigned long parent_rate)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	int div;
-	u32 clkgen0;
-
-	clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff;
-
-	div = ipu_di_clk_calc_div(parent_rate, rate);
-
-	ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0);
-
-	dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n",
-			__func__, parent_rate, rate, div);
-	return 0;
-}
-
-static u8 clk_di_get_parent(struct clk_hw *hw)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	u32 val;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	return val & DI_GEN_DI_CLK_EXT ? 1 : 0;
-}
-
-static int clk_di_set_parent(struct clk_hw *hw, u8 index)
-{
-	struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out);
-	u32 val;
-
-	val = ipu_di_read(di, DI_GENERAL);
-
-	if (index)
-		val |= DI_GEN_DI_CLK_EXT;
-	else
-		val &= ~DI_GEN_DI_CLK_EXT;
-
-	ipu_di_write(di, val, DI_GENERAL);
-
-	return 0;
-}
-
-static struct clk_ops clk_di_ops = {
-	.round_rate = clk_di_round_rate,
-	.set_rate = clk_di_set_rate,
-	.recalc_rate = clk_di_recalc_rate,
-	.set_parent = clk_di_set_parent,
-	.get_parent = clk_di_get_parent,
-};
-
 static void ipu_di_data_wave_config(struct ipu_di *di,
 				     int wave_gen,
 				     int access_size, int component_size)
@@ -528,42 +398,58 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
 		ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga));
 }
 
-int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+static void ipu_di_config_clock(struct ipu_di *di,
+	const struct ipu_di_signal_cfg *sig)
 {
-	u32 reg;
-	u32 di_gen, vsync_cnt;
-	u32 div;
-	u32 h_total, v_total;
-	int ret;
-	unsigned long round;
-	struct clk *parent;
+	struct clk *clk;
+	unsigned clkgen0;
+	uint32_t val;
 
-	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
-		di->id, sig->width, sig->height);
+	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
+		/*
+		 * CLKMODE_EXT means we must use the DI clock: this is
+		 * needed for things like LVDS which needs to feed the
+		 * DI and LDB with the same pixel clock.
+		 */
+		clk = di->clk_di;
+
+		if (sig->clkflags & IPU_DI_CLKMODE_SYNC) {
+			/*
+			 * CLKMODE_SYNC means that we want the DI to be
+			 * clocked at the same rate as the parent clock.
+			 * This is needed (eg) for LDB which needs to be
+			 * fed with the same pixel clock.  We assume that
+			 * the LDB clock has already been set correctly.
+			 */
+			clkgen0 = 1 << 4;
+		} else {
+			/*
+			 * We can use the divider.  We should really have
+			 * a flag here indicating whether the bridge can
+			 * cope with a fractional divider or not.  For the
+			 * time being, let's go for simplicitly and
+			 * reliability.
+			 */
+			unsigned long in_rate;
+			unsigned div;
 
-	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
-		return -EINVAL;
+			clk_set_rate(clk, sig->pixelclock);
 
-	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
-		clk_get_rate(di->clk_ipu),
-		clk_get_rate(di->clk_di),
-		sig->pixelclock);
+			in_rate = clk_get_rate(clk);
+			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			if (div == 0)
+				div = 1;
 
-	/*
-	 * CLKMODE_EXT means we must use the DI clock: this is needed
-	 * for things like LVDS which needs to feed the DI and LDB with
-	 * the same pixel clock.
-	 *
-	 * For other interfaces, we can arbitarily select between the DI
-	 * specific clock and the internal IPU clock.  See DI_GENERAL
-	 * bit 20.  We select the IPU clock if it can give us a clock
-	 * rate within 1% of the requested frequency, otherwise we use
-	 * the DI clock.
-	 */
-	round = sig->pixelclock;
-	if (sig->clkflags & IPU_DI_CLKMODE_EXT) {
-		parent = di->clk_di;
+			clkgen0 = div << 4;
+		}
 	} else {
+		/*
+		 * For other interfaces, we can arbitarily select between
+		 * the DI specific clock and the internal IPU clock.  See
+		 * DI_GENERAL bit 20.  We select the IPU clock if it can
+		 * give us a clock rate within 1% of the requested frequency,
+		 * otherwise we use the DI clock.
+		 */
 		unsigned long rate, clkrate;
 		unsigned div, error;
 
@@ -578,54 +464,80 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
 
 		/* Allow a 1% error */
 		if (error < 1010 && error >= 990) {
-			parent = di->clk_ipu;
+			clk = di->clk_ipu;
+
+			clkgen0 = div << 4;
 		} else {
-			parent = di->clk_di;
+			unsigned long in_rate;
+			unsigned div;
+
+			clk = di->clk_di;
 
-			ret = clk_set_rate(parent, sig->pixelclock);
-			if (ret)
-				dev_err(di->ipu->dev, "Setting of DI clock failed: %d\n", ret);
+			clk_set_rate(clk, sig->pixelclock);
 
-			/* Use the integer divisor rate - avoid fractional dividers */
-			round = rate;
+			in_rate = clk_get_rate(clk);
+			div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+			if (div == 0)
+				div = 1;
+
+			clkgen0 = div << 4;
 		}
 	}
 
-	ret = clk_set_parent(di->clk_di_pixel, parent);
-	if (ret) {
-		dev_err(di->ipu->dev,
-			"setting pixel clock to parent %s failed with %d\n",
-				__clk_get_name(parent), ret);
-		return ret;
-	}
+	di->clk_di_pixel = clk;
+
+	/* Set the divider */
+	ipu_di_write(di, clkgen0, DI_BS_CLKGEN0);
 
 	/*
-	 * CLKMODE_SYNC means that we want the DI to be clocked at the
-	 * same rate as the parent clock.  This is needed (eg) for LDB
-	 * which needs to be fed with the same pixel clock.
-	 *
-	 * Note: clk_set_rate(clk, clk_round_rate(clk, rate)) is the
-	 * same as clk_set_rate(clk, rate);
+	 * Set the high/low periods.  Bits 24:16 give us the falling edge,
+	 * and bits 8:0 give the rising edge.  LSB is fraction, and is
+	 * based on the divider above.  We want a 50% duty cycle, so set
+	 * the falling edge to be half the divider.
 	 */
-	if (sig->clkflags & IPU_DI_CLKMODE_SYNC)
-		round = clk_get_rate(parent);
+	ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1);
 
-	ret = clk_set_rate(di->clk_di_pixel, round);
+	/* Finally select the input clock */
+	val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT;
+	if (clk == di->clk_di)
+		val |= DI_GEN_DI_CLK_EXT;
+	ipu_di_write(di, val, DI_GENERAL);
 
-	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, got %luHz\n",
+	dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
 		sig->pixelclock,
 		clk_get_rate(di->clk_ipu),
 		clk_get_rate(di->clk_di),
-		parent == di->clk_di ? "DI" : "IPU",
-		clk_get_rate(di->clk_di_pixel));
+		clk == di->clk_di ? "DI" : "IPU",
+		clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 reg;
+	u32 di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+
+	dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
+		di->id, sig->width, sig->height);
+
+	if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+		return -EINVAL;
 
 	h_total = sig->width + sig->h_sync_width + sig->h_start_width +
 		sig->h_end_width;
 	v_total = sig->height + sig->v_sync_width + sig->v_start_width +
 		sig->v_end_width;
 
+	dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
+		clk_get_rate(di->clk_ipu),
+		clk_get_rate(di->clk_di),
+		sig->pixelclock);
+
 	mutex_lock(&di_mutex);
 
+	ipu_di_config_clock(di, sig);
+
 	div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff;
 	div = div / 16;		/* Now divider is integer portion */
 
@@ -709,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
 
 int ipu_di_enable(struct ipu_di *di)
 {
-	int ret = clk_prepare_enable(di->clk_di_pixel);
+	int ret;
+
+	WARN_ON(IS_ERR(di->clk_di_pixel));
+
+	ret = clk_prepare_enable(di->clk_di_pixel);
 	if (ret)
 		return ret;
 
@@ -721,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable);
 
 int ipu_di_disable(struct ipu_di *di)
 {
+	WARN_ON(IS_ERR(di->clk_di_pixel));
+
 	ipu_module_disable(di->ipu, di->module);
 
 	clk_disable_unprepare(di->clk_di_pixel);
@@ -776,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 		u32 module, struct clk *clk_ipu)
 {
 	struct ipu_di *di;
-	int ret;
-	const char *di_parent[2];
-	struct clk_init_data init = {
-		.ops = &clk_di_ops,
-		.num_parents = 2,
-		.flags = 0,
-	};
 
 	if (id > 1)
 		return -ENODEV;
@@ -804,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id,
 	if (!di->base)
 		return -ENOMEM;
 
-	di_parent[0] = __clk_get_name(di->clk_ipu);
-	di_parent[1] = __clk_get_name(di->clk_di);
-
 	ipu_di_write(di, 0x10, DI_BS_CLKGEN0);
 
-	init.parent_names = (const char **)&di_parent;
-	di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel",
-			dev_name(dev), id);
-	if (!di->clk_name)
-		return -ENOMEM;
-
-	init.name = di->clk_name;
-
-	di->clk_hw_out.init = &init;
-	di->clk_di_pixel = clk_register(dev, &di->clk_hw_out);
-
-	if (IS_ERR(di->clk_di_pixel)) {
-		ret = PTR_ERR(di->clk_di_pixel);
-		goto failed_clk_register;
-	}
-
 	dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n",
 			id, base, di->base);
 	di->inuse = false;
 	di->ipu = ipu;
 
 	return 0;
-
-failed_clk_register:
-
-	kfree(di->clk_name);
-
-	return ret;
 }
 
 void ipu_di_exit(struct ipu_soc *ipu, int id)
 {
-	struct ipu_di *di = ipu->di_priv[id];
-
-	clk_unregister(di->clk_di_pixel);
-	kfree(di->clk_name);
 }
-- 
1.7.4.4

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

* [PATCH RFC 07/46] imx-drm: Add mx6 hdmi transmitter support
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:34   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

From: Fabio Estevam <fabio.estevam@freescale.com>
To: David Airlie <airlied@linux.ie>,Greg Kroah-Hartman <gregkh@linuxfoundation.org>,Sascha Hauer <kernel@pengutronix.de>,Shawn Guo <shawn.guo@linaro.org>

This is based on the initial work done by Sascha Hauer and Tony Prisk.

Tested on a mx6qsabresd.

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Kconfig             |    6 +
 drivers/staging/imx-drm/Makefile            |    1 +
 drivers/staging/imx-drm/imx-hdmi.c          | 1928 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.h          | 1032 ++++++++++++++
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |    1 +
 5 files changed, 2968 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.h

diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 5032ff7c2259..0faf52c4c5f1 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -53,3 +53,9 @@ config DRM_IMX_IPUV3
 	depends on DRM_IMX_IPUV3_CORE
 	help
 	  Choose this if you have a i.MX5 or i.MX6 processor.
+
+config DRM_IMX_HDMI
+	tristate "Freescale i.MX DRM HDMI "
+	depends on DRM_IMX
+	help
+	  Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 8742432d7b01..4677585b5ad5 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
new file mode 100644
index 000000000000..2022635fffdf
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -0,0 +1,1928 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
+ * for SLISHDMI13T and SLIPHDMIT IP cores
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ */
+
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+
+#include <linux/of_device.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "ipu-v3/imx-ipu-v3.h"
+#include "imx-hdmi.h"
+#include "imx-drm.h"
+
+#define HDMI_EDID_LEN		512
+
+#define RGB			0
+#define YCBCR444		1
+#define YCBCR422_16BITS		2
+#define YCBCR422_8BITS		3
+#define	XVYCC444		4
+
+enum hdmi_datamap {
+	RGB444_8B = 0x01,
+	RGB444_10B = 0x03,
+	RGB444_12B = 0x05,
+	RGB444_16B = 0x07,
+	YCbCr444_8B = 0x09,
+	YCbCr444_10B = 0x0B,
+	YCbCr444_12B = 0x0D,
+	YCbCr444_16B = 0x0F,
+	YCbCr422_8B = 0x16,
+	YCbCr422_10B = 0x14,
+	YCbCr422_12B = 0x12,
+};
+
+enum hdmi_colorimetry {
+	ITU601,
+	ITU709,
+};
+
+enum imx_hdmi_devtype {
+	IMX6Q_HDMI,
+	IMX6DL_HDMI,
+};
+
+static const u16 csc_coeff_default[3][4] = {
+	{ 0x2000, 0x0000, 0x0000, 0x0000 },
+	{ 0x0000, 0x2000, 0x0000, 0x0000 },
+	{ 0x0000, 0x0000, 0x2000, 0x0000 }
+};
+
+static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
+	{ 0x2000, 0x6926, 0x74fd, 0x010e },
+	{ 0x2000, 0x2cdd, 0x0000, 0x7e9a },
+	{ 0x2000, 0x0000, 0x38b4, 0x7e3b }
+};
+
+static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
+	{ 0x2000, 0x7106, 0x7a02, 0x00a7 },
+	{ 0x2000, 0x3264, 0x0000, 0x7e6d },
+	{ 0x2000, 0x0000, 0x3b61, 0x7e25 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
+	{ 0x2591, 0x1322, 0x074b, 0x0000 },
+	{ 0x6535, 0x2000, 0x7acc, 0x0200 },
+	{ 0x6acd, 0x7534, 0x2000, 0x0200 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
+	{ 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
+	{ 0x62f0, 0x2000, 0x7d11, 0x0200 },
+	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
+};
+
+struct hdmi_vmode {
+	bool mdvi;
+	bool mhsyncpolarity;
+	bool mvsyncpolarity;
+	bool minterlaced;
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct imx_hdmi {
+	struct drm_connector connector;
+	struct imx_drm_connector *imx_drm_connector;
+	struct drm_encoder encoder;
+	struct imx_drm_encoder *imx_drm_encoder;
+
+	enum imx_hdmi_devtype dev_type;
+	struct device *dev;
+	struct clk *isfr_clk;
+	struct clk *iahb_clk;
+
+	struct hdmi_data_info hdmi_data;
+	int vic;
+
+	u8 edid[HDMI_EDID_LEN];
+	bool fb_reg;
+	bool cable_plugin;
+
+	bool phy_enabled;
+	struct drm_display_mode previous_mode;
+
+	struct regmap *regmap;
+	struct i2c_adapter *ddc;
+	void __iomem *regs;
+
+	unsigned long pixel_clk_rate;
+	unsigned int sample_rate;
+	int ratio;
+};
+
+static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
+{
+	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
+			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+			   ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+}
+
+static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+{
+	writeb(val, hdmi->regs + offset);
+}
+
+static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+{
+	return readb(hdmi->regs + offset);
+}
+
+static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+		      u8 shift, u8 mask)
+{
+	u8 value = hdmi_readb(hdmi, reg) & ~mask;
+	value |= (data << shift) & mask;
+	hdmi_writeb(hdmi, value, reg);
+}
+
+static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+					 unsigned int value)
+{
+	u8 val;
+
+	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
+	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+
+	/* nshift factor = 0 */
+	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
+	val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
+	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+}
+
+static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+{
+	u8 val;
+
+	/* Must be set/cleared first */
+	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
+	val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
+	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+
+	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+	hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+		    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+				   unsigned int ratio)
+{
+	unsigned int n = (128 * freq) / 1000;
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 4576;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 4096;
+		else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+			n = 11648;
+		else
+			n = 4096;
+		break;
+
+	case 44100:
+		if (pixel_clk == 25170000)
+			n = 7007;
+		else if (pixel_clk == 74170000)
+			n = 17836;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 17836 : 8918;
+		else
+			n = 6272;
+		break;
+
+	case 48000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 6864;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 6144;
+		else if (pixel_clk == 74170000)
+			n = 11648;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 11648 : 5824;
+		else
+			n = 6144;
+		break;
+
+	case 88200:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+		break;
+
+	case 96000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+		break;
+
+	case 176400:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+		break;
+
+	case 192000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+		break;
+
+	default:
+		break;
+	}
+
+	return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+				     unsigned int ratio)
+{
+	unsigned int cts = 0;
+
+	pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
+		 pixel_clk, ratio);
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 297000000) {
+			cts = 222750;
+			break;
+		}
+	case 48000:
+	case 96000:
+	case 192000:
+		switch (pixel_clk) {
+		case 25200000:
+		case 27000000:
+		case 54000000:
+		case 74250000:
+		case 148500000:
+			cts = pixel_clk / 1000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		/*
+		 * All other TMDS clocks are not supported by
+		 * DWC_hdmi_tx. The TMDS clocks divided or
+		 * multiplied by 1,001 coefficients are not
+		 * supported.
+		 */
+		default:
+			break;
+		}
+		break;
+	case 44100:
+	case 88200:
+	case 176400:
+		switch (pixel_clk) {
+		case 25200000:
+			cts = 28000;
+			break;
+		case 27000000:
+			cts = 30000;
+			break;
+		case 54000000:
+			cts = 60000;
+			break;
+		case 74250000:
+			cts = 82500;
+			break;
+		case 148500000:
+			cts = 165000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	if (ratio == 100)
+		return cts;
+	else
+		return (cts * ratio) / 100;
+}
+
+static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
+{
+	unsigned long rate;
+
+	rate = 65000000; /* FIXME */
+
+	if (rate)
+		hdmi->pixel_clk_rate = rate;
+}
+
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+{
+	unsigned int clk_n, clk_cts;
+
+	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+			       hdmi->ratio);
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+				   hdmi->ratio);
+
+	if (!clk_cts) {
+		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+			 __func__, hdmi->pixel_clk_rate);
+		return;
+	}
+
+	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+		__func__, hdmi->sample_rate, hdmi->ratio,
+		hdmi->pixel_clk_rate, clk_n, clk_cts);
+
+	hdmi_set_clock_regenerator_n(hdmi, clk_n);
+	hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+{
+	unsigned int clk_n, clk_cts;
+
+	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+			       hdmi->ratio);
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+				   hdmi->ratio);
+
+	if (!clk_cts) {
+		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+			 __func__, hdmi->pixel_clk_rate);
+		return;
+	}
+
+	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+		__func__, hdmi->sample_rate, hdmi->ratio,
+		hdmi->pixel_clk_rate, clk_n, clk_cts);
+
+	hdmi_set_clock_regenerator_n(hdmi, clk_n);
+	hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+{
+	/* Get pixel clock from ipu */
+	hdmi_get_pixel_clk(hdmi);
+	hdmi_set_clk_regenerator(hdmi);
+}
+
+/*
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ *			pin{47~40} <==> R[7:0]
+ *			pin{31~24} <==> G[7:0]
+ *			pin{15~8}  <==> B[7:0]
+ */
+static void hdmi_video_sample(struct imx_hdmi *hdmi)
+{
+	int color_format = 0;
+	u8 val;
+
+	if (hdmi->hdmi_data.enc_in_format == RGB) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x01;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x03;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x05;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x07;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x09;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x0B;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x0D;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x0F;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x16;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x14;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x12;
+		else
+			return;
+	}
+
+	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+		((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+		HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+	hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+
+	/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+	hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+}
+
+static int is_color_space_conversion(struct imx_hdmi *hdmi)
+{
+	return (hdmi->hdmi_data.enc_in_format !=
+		hdmi->hdmi_data.enc_out_format);
+}
+
+static int is_color_space_decimation(struct imx_hdmi *hdmi)
+{
+	return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
+		(hdmi->hdmi_data.enc_in_format == RGB ||
+		hdmi->hdmi_data.enc_in_format == YCBCR444));
+}
+
+static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+{
+	return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
+		(hdmi->hdmi_data.enc_out_format == RGB ||
+		hdmi->hdmi_data.enc_out_format == YCBCR444));
+}
+
+static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+{
+	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+	u32 csc_scale = 1;
+	u8 val;
+
+	if (is_color_space_conversion(hdmi)) {
+		if (hdmi->hdmi_data.enc_out_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry == ITU601)
+				csc_coeff = &csc_coeff_rgb_out_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_out_eitu709;
+		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry == ITU601)
+				csc_coeff = &csc_coeff_rgb_in_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_in_eitu709;
+			csc_scale = 0;
+		}
+	}
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
+
+	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
+	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
+	val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
+	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct imx_hdmi *hdmi)
+{
+	int color_depth = 0;
+	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+	int decimation = 0;
+	u8 val;
+
+	/* YCC422 interpolation to 444 mode */
+	if (is_color_space_interpolation(hdmi))
+		interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+	else if (is_color_space_decimation(hdmi))
+		decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+	if (hdmi->hdmi_data.enc_color_depth == 8)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 10)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 12)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 16)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+	else
+		return;
+
+	/* Configure the CSC registers */
+	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
+	val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
+	val |= color_depth;
+	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+
+	imx_hdmi_update_csc_coeffs(hdmi);
+}
+
+/*
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+{
+	unsigned int color_depth = 0;
+	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+	u8 val;
+
+	if (hdmi_data->enc_out_format == RGB
+		|| hdmi_data->enc_out_format == YCBCR444) {
+		if (!hdmi_data->enc_color_depth)
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		else if (hdmi_data->enc_color_depth == 8) {
+			color_depth = 4;
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		} else if (hdmi_data->enc_color_depth == 10)
+			color_depth = 5;
+		else if (hdmi_data->enc_color_depth == 12)
+			color_depth = 6;
+		else if (hdmi_data->enc_color_depth == 16)
+			color_depth = 7;
+		else
+			return;
+	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+		if (!hdmi_data->enc_color_depth ||
+		    hdmi_data->enc_color_depth == 8)
+			remap_size = HDMI_VP_REMAP_YCC422_16bit;
+		else if (hdmi_data->enc_color_depth == 10)
+			remap_size = HDMI_VP_REMAP_YCC422_20bit;
+		else if (hdmi_data->enc_color_depth == 12)
+			remap_size = HDMI_VP_REMAP_YCC422_24bit;
+		else
+			return;
+		output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+	} else
+		return;
+
+	/* set the packetizer registers */
+	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+		((hdmi_data->pix_repet_factor <<
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
+	val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	/* Data from pixel repeater block */
+	if (hdmi_data->pix_repet_factor > 1) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+			HDMI_VP_CONF_BYPASS_SELECT_MASK);
+		val |= HDMI_VP_CONF_PR_EN_ENABLE |
+			HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else { /* data from packetizer block */
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+			HDMI_VP_CONF_BYPASS_SELECT_MASK);
+		val |= HDMI_VP_CONF_PR_EN_DISABLE |
+			HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	}
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
+	val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+
+	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			HDMI_VP_CONF_PP_EN_ENABLE |
+			HDMI_VP_CONF_YCC422_EN_DISABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			HDMI_VP_CONF_PP_EN_DISABLE |
+			HDMI_VP_CONF_YCC422_EN_ENABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
+			HDMI_VP_CONF_PP_EN_DISABLE |
+			HDMI_VP_CONF_YCC422_EN_DISABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else {
+		return;
+	}
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
+		HDMI_VP_STUFF_YCC422_STUFFING_MASK);
+	val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+		HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	val = hdmi_readb(hdmi, HDMI_VP_CONF);
+	val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
+	val |= output_select;
+	hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+}
+
+static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
+		HDMI_PHY_TST0_TSTCLR_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTEN_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
+		HDMI_PHY_TST0_TSTEN_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
+		HDMI_PHY_TST0_TSTCLK_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+{
+	unsigned char val = 0;
+	val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
+	while (!val) {
+		udelay(1000);
+		if (msec-- == 0)
+			return false;
+		val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
+	}
+	return true;
+}
+
+static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+			      unsigned char addr)
+{
+	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 8),
+		HDMI_PHY_I2CM_DATAO_1_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+		HDMI_PHY_I2CM_DATAO_0_ADDR);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+		HDMI_PHY_I2CM_OPERATION_ADDR);
+	hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+				     unsigned char addr)
+{
+	__hdmi_phy_i2c_write(hdmi, data, addr);
+	return 0;
+}
+
+static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_PDZ_OFFSET,
+			 HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_ENTMDS_OFFSET,
+			 HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+			 HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+			 HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+			      unsigned char res, int cscon)
+{
+	u8 val, msec;
+
+	/* color resolution 0 is 8 bit colour depth */
+	if (!res)
+		res = 8;
+
+	if (prep)
+		return -EINVAL;
+	else if (res != 8 && res != 12)
+		return -EINVAL;
+
+	/* Enable csc path */
+	if (cscon)
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+	else
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+	hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+
+	/* gen2 tx power off */
+	imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+	/* gen2 pddq */
+	imx_hdmi_phy_gen2_pddq(hdmi, 1);
+
+	/* PHY reset */
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+	hdmi_phy_test_clear(hdmi, 1);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+			HDMI_PHY_I2CM_SLAVE_ADDR);
+	hdmi_phy_test_clear(hdmi, 0);
+
+	if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
+		switch (res) {
+		case 8:
+			/* PLL/MPLL Cfg */
+			hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);  /* GMPCTRL */
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);  /* CURRCTRL */
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		dev_err(hdmi->dev,
+				"Pixel clock %d - unsupported by HDMI\n",
+				hdmi->hdmi_data.video_mode.mpixelclock);
+		return -EINVAL;
+	}
+
+	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
+	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+	/* RESISTANCE TERM 133Ohm Cfg */
+	hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);  /* TXTERM */
+	/* PREEMP Cgf 0.00 */
+	hdmi_phy_i2c_write(hdmi, 0x800d, 0x09);  /* CKSYMTXCTRL */
+	/* TX/CK LVL 10 */
+	hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
+	/* REMOVE CLK TERM */
+	hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+
+	imx_hdmi_phy_enable_power(hdmi, 1);
+
+	/* toggle TMDS enable */
+	imx_hdmi_phy_enable_tmds(hdmi, 0);
+	imx_hdmi_phy_enable_tmds(hdmi, 1);
+
+	/* gen2 tx power on */
+	imx_hdmi_phy_gen2_txpwron(hdmi, 1);
+	imx_hdmi_phy_gen2_pddq(hdmi, 0);
+
+	/*Wait for PHY PLL lock */
+	msec = 4;
+	val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+	while (!val) {
+		udelay(1000);
+		if (msec-- == 0) {
+			dev_dbg(hdmi->dev, "PHY PLL not locked\n");
+			return -EINVAL;
+		}
+		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+	}
+
+	return 0;
+}
+
+static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+{
+	int i, ret;
+	bool cscon = false;
+
+	/*check csc whether needed activated in HDMI mode */
+	cscon = (is_color_space_conversion(hdmi) &&
+			!hdmi->hdmi_data.video_mode.mdvi);
+
+	/* HDMI Phy spec says to do the phy initialization sequence twice */
+	for (i = 0; i < 2; i++) {
+		imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
+		imx_hdmi_phy_sel_interface_control(hdmi, 0);
+		imx_hdmi_phy_enable_tmds(hdmi, 0);
+		imx_hdmi_phy_enable_power(hdmi, 0);
+
+		/* Enable CSC */
+		ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+		if (ret)
+			return ret;
+	}
+
+	hdmi->phy_enabled = true;
+	return 0;
+}
+
+static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+{
+	u8 de, val;
+
+	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+	else
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+	/* disable rx detect */
+	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
+	val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
+	val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
+	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+
+	val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
+	val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
+	val |= de;
+	hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+
+	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
+	val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
+	val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
+	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+}
+
+static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+{
+	u8 val, pix_fmt, under_scan;
+	u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+	bool aspect_16_9;
+
+	aspect_16_9 = false; /* FIXME */
+
+	/* AVI Data Byte 1 */
+	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+	else
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+		under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+	/*
+	 * Active format identification data is present in the AVI InfoFrame.
+	 * Under scan info, no bar data
+	 */
+	val = pix_fmt | under_scan |
+		HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+		HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+
+	/* AVI Data Byte 2 -Set the Aspect Ratio */
+	if (aspect_16_9) {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+	} else {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+	}
+
+	/* Set up colorimetry */
+	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+		if (hdmi->hdmi_data.colorimetry == ITU601)
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+		else /* hdmi->hdmi_data.colorimetry == ITU709 */
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+		if (hdmi->hdmi_data.colorimetry == ITU601)
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+		else /* hdmi->hdmi_data.colorimetry == ITU709 */
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	} else { /* Carries no data */
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	}
+
+	val = colorimetry | coded_ratio | act_ratio;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+
+	/* AVI Data Byte 3 */
+	val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+		HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+		HDMI_FC_AVICONF2_SCALING_NONE;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+
+	/* AVI Data Byte 4 */
+	hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+
+	/* AVI Data Byte 5- set up input and output pixel repetition */
+	val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+		((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+
+	/* IT Content and quantization range = don't care */
+	val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+		HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+
+	/* AVI Data Bytes 6-13 */
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+}
+
+static void hdmi_av_composer(struct imx_hdmi *hdmi,
+			     const struct drm_display_mode *mode)
+{
+	u8 inv_val;
+	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+
+	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+	vmode->mpixelclock = mode->htotal * mode->vtotal *
+			     drm_mode_vrefresh(mode);
+
+	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+	/* Set up HDMI_FC_INVIDCONF */
+	inv_val = (hdmi->hdmi_data.hdcp_enable ?
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+	inv_val |= (vmode->mvsyncpolarity ?
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mhsyncpolarity ?
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mdataenablepolarity ?
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+	if (hdmi->vic == 39)
+		inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+	else
+		inv_val |= (vmode->minterlaced ?
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+	inv_val |= (vmode->minterlaced ?
+		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+	inv_val |= (vmode->mdvi ?
+		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
+	/* Set up horizontal active pixel width */
+	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+
+	/* Set up vertical active lines */
+	hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+	hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+
+	/* Set up horizontal blanking pixel region width */
+	hblank = mode->htotal - mode->hdisplay;
+	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+	/* Set up vertical blanking pixel region width */
+	vblank = mode->vtotal - mode->vdisplay;
+	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+	/* Set up HSYNC active edge delay width (in pixel clks) */
+	h_de_hs = mode->hsync_start - mode->hdisplay;
+	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+	/* Set up VSYNC active edge delay (in lines) */
+	v_de_vs = mode->vsync_start - mode->vdisplay;
+	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+	/* Set up HSYNC active pulse width (in pixel clks) */
+	hsync_len = mode->hsync_end - mode->hsync_start;
+	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+	/* Set up VSYNC active edge delay (in pixel clks) */
+	vsync_len = mode->vsync_end - mode->vsync_start;
+	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+}
+
+static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+{
+	if (!hdmi->phy_enabled)
+		return;
+
+	imx_hdmi_phy_enable_tmds(hdmi, 0);
+	imx_hdmi_phy_enable_power(hdmi, 0);
+
+	hdmi->phy_enabled = false;
+}
+
+/* HDMI Initialization Step B.4 */
+static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+{
+	u8 clkdis;
+
+	/* control period minimum duration */
+	hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
+	hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
+	hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+
+	/* Set to fill TMDS data channels */
+	hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+	hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
+	hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+
+	/* Enable pixel clock and tmds data path */
+	clkdis = 0x7F;
+	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	/* Enable csc path */
+	if (is_color_space_conversion(hdmi)) {
+		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	}
+}
+
+static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+{
+	u8 clkdis;
+
+	clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
+	clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+{
+	int count;
+	u8 val;
+
+	/* TMDS software reset */
+	hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+	val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+	if (hdmi->dev_type == IMX6DL_HDMI) {
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+		return;
+	}
+
+	for (count = 0; count < 5; count++)
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+		    HDMI_IH_MUTE_FC_STAT2);
+}
+
+static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+{
+	int ret;
+
+	hdmi_disable_overflow_interrupts(hdmi);
+
+	hdmi->vic = drm_match_cea_mode(mode);
+
+	if (!hdmi->vic) {
+		dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
+		hdmi->hdmi_data.video_mode.mdvi = true;
+	} else {
+		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+		hdmi->hdmi_data.video_mode.mdvi = false;
+	}
+
+	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+		(hdmi->vic == 21) || (hdmi->vic == 22) ||
+		(hdmi->vic == 2) || (hdmi->vic == 3) ||
+		(hdmi->vic == 17) || (hdmi->vic == 18))
+		hdmi->hdmi_data.colorimetry = ITU601;
+	else
+		hdmi->hdmi_data.colorimetry = ITU709;
+
+	if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+		(hdmi->vic == 12) || (hdmi->vic == 13) ||
+		(hdmi->vic == 14) || (hdmi->vic == 15) ||
+		(hdmi->vic == 25) || (hdmi->vic == 26) ||
+		(hdmi->vic == 27) || (hdmi->vic == 28) ||
+		(hdmi->vic == 29) || (hdmi->vic == 30) ||
+		(hdmi->vic == 35) || (hdmi->vic == 36) ||
+		(hdmi->vic == 37) || (hdmi->vic == 38))
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
+	else
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
+
+	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+	/* TODO: Get input format from IPU (via FB driver interface) */
+	hdmi->hdmi_data.enc_in_format = RGB;
+
+	hdmi->hdmi_data.enc_out_format = RGB;
+
+	hdmi->hdmi_data.enc_color_depth = 8;
+	hdmi->hdmi_data.pix_repet_factor = 0;
+	hdmi->hdmi_data.hdcp_enable = 0;
+	hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
+
+	/* HDMI Initialization Step B.1 */
+	hdmi_av_composer(hdmi, mode);
+
+	/* HDMI Initializateion Step B.2 */
+	ret = imx_hdmi_phy_init(hdmi);
+	if (ret)
+		return ret;
+
+	/* HDMI Initialization Step B.3 */
+	imx_hdmi_enable_video_path(hdmi);
+
+	/* not for DVI mode */
+	if (hdmi->hdmi_data.video_mode.mdvi)
+		dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
+	else {
+		dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+
+		/* HDMI Initialization Step E - Configure audio */
+		hdmi_clk_regenerator_update_pixel_clock(hdmi);
+		hdmi_enable_audio_clk(hdmi);
+
+		/* HDMI Initialization Step F - Configure AVI InfoFrame */
+		hdmi_config_AVI(hdmi);
+	}
+
+	hdmi_video_packetize(hdmi);
+	hdmi_video_csc(hdmi);
+	hdmi_video_sample(hdmi);
+	hdmi_tx_hdcp_config(hdmi);
+
+	imx_hdmi_clear_overflow(hdmi);
+	if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+		hdmi_enable_overflow_interrupts(hdmi);
+
+	return 0;
+}
+
+/* Wait until we are registered to enable interrupts */
+static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+{
+	int ret;
+
+	if (hdmi->fb_reg)
+		return 0;
+
+	ret = clk_prepare_enable(hdmi->iahb_clk);
+	if (ret)
+		return ret;
+
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+		    HDMI_PHY_I2CM_INT_ADDR);
+
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+		    HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+		    HDMI_PHY_I2CM_CTLINT_ADDR);
+
+	/* enable cable hot plug irq */
+	hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	/* Unmute interrupts */
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+	hdmi->fb_reg = true;
+
+	clk_disable_unprepare(hdmi->iahb_clk);
+
+	return 0;
+}
+
+static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+{
+	u8 ih_mute;
+
+	/*
+	 * Boot up defaults are:
+	 * HDMI_IH_MUTE   = 0x03 (disabled)
+	 * HDMI_IH_MUTE_* = 0x00 (enabled)
+	 *
+	 * Disable top level interrupt bits in HDMI block
+	 */
+	ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+	/* by default mask all interrupts */
+	hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+	hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+
+	/* Disable interrupts in the IH_MUTE_* registers */
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	/* Enable top level interrupt bits in HDMI block */
+	ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		    HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
+
+static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+{
+	imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+{
+	imx_hdmi_phy_disable(hdmi);
+}
+
+static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+							*connector, bool force)
+{
+	/* FIXME */
+	return connector_status_connected;
+}
+
+static void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+}
+
+static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+	struct edid *edid;
+	int ret;
+
+	if (!hdmi->ddc)
+		return 0;
+
+	edid = drm_get_edid(connector, hdmi->ddc);
+	if (edid) {
+		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		drm_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(hdmi->dev, "failed to get edid\n");
+	}
+
+	return 0;
+}
+
+static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
+			  struct drm_display_mode *mode)
+{
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+							   *connector)
+{
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+
+	return &hdmi->encoder;
+}
+
+static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	imx_hdmi_setup(hdmi, mode);
+
+	/* Store the display mode for plugin/DKMS poweron events */
+	memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+			const struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	if (mode)
+		imx_hdmi_poweroff(hdmi);
+	else
+		imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	imx_hdmi_poweroff(hdmi);
+	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
+				  V4L2_PIX_FMT_RGB24);
+}
+
+static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+	int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
+					     encoder->crtc);
+
+	imx_hdmi_set_ipu_di_mux(hdmi, mux);
+
+	imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
+{
+	return;
+}
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+	.destroy = imx_hdmi_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+	.dpms = imx_hdmi_encoder_dpms,
+	.prepare = imx_hdmi_encoder_prepare,
+	.commit = imx_hdmi_encoder_commit,
+	.mode_set = imx_hdmi_encoder_mode_set,
+	.mode_fixup = imx_hdmi_encoder_mode_fixup,
+	.disable = imx_hdmi_encoder_disable,
+};
+
+static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = imx_hdmi_connector_detect,
+	.destroy = imx_hdmi_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
+	.get_modes = imx_hdmi_connector_get_modes,
+	.mode_valid = imx_hdmi_connector_mode_valid,
+	.best_encoder = imx_hdmi_connector_best_encoder,
+};
+
+static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+{
+	struct imx_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+	u8 phy_int_pol;
+	u8 val;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+
+	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+
+	if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+		if (phy_int_pol & HDMI_PHY_HPD) {
+			dev_dbg(hdmi->dev, "EVENT=plugin\n");
+
+			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
+			val &= ~HDMI_PHY_HPD;
+			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+
+			imx_hdmi_poweron(hdmi);
+		} else {
+			dev_dbg(hdmi->dev, "EVENT=plugout\n");
+
+			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
+			val |= HDMI_PHY_HPD;
+			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+
+			imx_hdmi_poweroff(hdmi);
+		}
+	}
+
+	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+
+	return IRQ_HANDLED;
+}
+
+static int imx_hdmi_register(struct imx_hdmi *hdmi)
+{
+	int ret;
+
+	hdmi->connector.funcs = &imx_hdmi_connector_funcs;
+	hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
+
+	hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
+	hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+
+	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
+	ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
+			THIS_MODULE);
+	if (ret) {
+		dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
+		return ret;
+	}
+
+	drm_connector_helper_add(&hdmi->connector,
+			&imx_hdmi_connector_helper_funcs);
+
+	ret = imx_drm_add_connector(&hdmi->connector,
+			&hdmi->imx_drm_connector, THIS_MODULE);
+	if (ret) {
+		imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+		dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->connector.encoder = &hdmi->encoder;
+
+	drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+
+	return 0;
+}
+
+static struct platform_device_id imx_hdmi_devtype[] = {
+	{
+		.name = "imx6q-hdmi",
+		.driver_data = IMX6Q_HDMI,
+	}, {
+		.name = "imx6dl-hdmi",
+		.driver_data = IMX6DL_HDMI,
+	}, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
+{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
+{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+				of_match_device(imx_hdmi_dt_ids, &pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ddc_node;
+	struct imx_hdmi *hdmi;
+	int ret, irq;
+	struct resource *iores;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->dev = &pdev->dev;
+
+	if (of_id) {
+		const struct platform_device_id *device_id = of_id->data;
+		hdmi->dev_type = device_id->driver_data;
+	}
+
+	ddc_node = of_parse_phandle(np, "ddc", 0);
+	if (ddc_node) {
+		hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+		if (!hdmi->ddc)
+			dev_dbg(hdmi->dev, "failed to read ddc node\n");
+
+		of_node_put(ddc_node);
+	} else {
+		dev_dbg(hdmi->dev, "no ddc property found\n");
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -EINVAL;
+
+	ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
+			       dev_name(&pdev->dev), hdmi);
+	if (ret)
+		return ret;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+	if (IS_ERR(hdmi->regs))
+		return PTR_ERR(hdmi->regs);
+
+	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+	if (IS_ERR(hdmi->regmap))
+		return PTR_ERR(hdmi->regmap);
+
+	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+	if (IS_ERR(hdmi->isfr_clk)) {
+		ret = PTR_ERR(hdmi->isfr_clk);
+		dev_err(hdmi->dev,
+			"Unable to get HDMI isfr clk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdmi->isfr_clk);
+	if (ret) {
+		dev_err(hdmi->dev,
+			"Cannot enable HDMI isfr clock: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+	if (IS_ERR(hdmi->iahb_clk)) {
+		ret = PTR_ERR(hdmi->iahb_clk);
+		dev_err(hdmi->dev,
+			"Unable to get HDMI iahb clk: %d\n", ret);
+		goto err_isfr;
+	}
+
+	ret = clk_prepare_enable(hdmi->iahb_clk);
+	if (ret) {
+		dev_err(hdmi->dev,
+			"Cannot enable HDMI iahb clock: %d\n", ret);
+		goto err_isfr;
+	}
+
+	/* Product and revision IDs */
+	dev_info(&pdev->dev,
+		"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+		hdmi_readb(hdmi, HDMI_DESIGN_ID),
+		hdmi_readb(hdmi, HDMI_REVISION_ID),
+		hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+		hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+
+	initialize_hdmi_ih_mutes(hdmi);
+
+	/*
+	 * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+	 * N and cts values before enabling phy
+	 */
+	hdmi_init_clk_regenerator(hdmi);
+
+	/*
+	 * Configure registers related to HDMI interrupt
+	 * generation before registering IRQ.
+	 */
+	hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	ret = imx_hdmi_fb_registered(hdmi);
+	if (ret)
+		goto err_iahb;
+
+	ret = imx_hdmi_register(hdmi);
+	if (ret)
+		goto err_iahb;
+
+	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
+
+	platform_set_drvdata(pdev, hdmi);
+
+	return 0;
+
+err_iahb:
+	clk_disable_unprepare(hdmi->iahb_clk);
+err_isfr:
+	clk_disable_unprepare(hdmi->isfr_clk);
+
+	return ret;
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+	struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+	struct drm_connector *connector = &hdmi->connector;
+	struct drm_encoder *encoder = &hdmi->encoder;
+
+	drm_mode_connector_detach_encoder(connector, encoder);
+	imx_drm_remove_connector(hdmi->imx_drm_connector);
+	imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+
+	clk_disable_unprepare(hdmi->iahb_clk);
+	clk_disable_unprepare(hdmi->isfr_clk);
+	i2c_put_adapter(hdmi->ddc);
+
+	return 0;
+}
+
+static struct platform_driver imx_hdmi_driver = {
+	.probe  = imx_hdmi_platform_probe,
+	.remove = imx_hdmi_platform_remove,
+	.driver = {
+		.name = "imx-hdmi",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_hdmi_dt_ids,
+	},
+};
+
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
new file mode 100644
index 000000000000..39b677689db6
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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 __IMX_HDMI_H__
+#define __IMX_HDMI_H__
+
+/* Identification Registers */
+#define HDMI_DESIGN_ID                          0x0000
+#define HDMI_REVISION_ID                        0x0001
+#define HDMI_PRODUCT_ID0                        0x0002
+#define HDMI_PRODUCT_ID1                        0x0003
+#define HDMI_CONFIG0_ID                         0x0004
+#define HDMI_CONFIG1_ID                         0x0005
+#define HDMI_CONFIG2_ID                         0x0006
+#define HDMI_CONFIG3_ID                         0x0007
+
+/* Interrupt Registers */
+#define HDMI_IH_FC_STAT0                        0x0100
+#define HDMI_IH_FC_STAT1                        0x0101
+#define HDMI_IH_FC_STAT2                        0x0102
+#define HDMI_IH_AS_STAT0                        0x0103
+#define HDMI_IH_PHY_STAT0                       0x0104
+#define HDMI_IH_I2CM_STAT0                      0x0105
+#define HDMI_IH_CEC_STAT0                       0x0106
+#define HDMI_IH_VP_STAT0                        0x0107
+#define HDMI_IH_I2CMPHY_STAT0                   0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
+
+#define HDMI_IH_MUTE_FC_STAT0                   0x0180
+#define HDMI_IH_MUTE_FC_STAT1                   0x0181
+#define HDMI_IH_MUTE_FC_STAT2                   0x0182
+#define HDMI_IH_MUTE_AS_STAT0                   0x0183
+#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
+#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
+#define HDMI_IH_MUTE_VP_STAT0                   0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
+#define HDMI_IH_MUTE                            0x01FF
+
+/* Video Sample Registers */
+#define HDMI_TX_INVID0                          0x0200
+#define HDMI_TX_INSTUFFING                      0x0201
+#define HDMI_TX_GYDATA0                         0x0202
+#define HDMI_TX_GYDATA1                         0x0203
+#define HDMI_TX_RCRDATA0                        0x0204
+#define HDMI_TX_RCRDATA1                        0x0205
+#define HDMI_TX_BCBDATA0                        0x0206
+#define HDMI_TX_BCBDATA1                        0x0207
+
+/* Video Packetizer Registers */
+#define HDMI_VP_STATUS                          0x0800
+#define HDMI_VP_PR_CD                           0x0801
+#define HDMI_VP_STUFF                           0x0802
+#define HDMI_VP_REMAP                           0x0803
+#define HDMI_VP_CONF                            0x0804
+#define HDMI_VP_STAT                            0x0805
+#define HDMI_VP_INT                             0x0806
+#define HDMI_VP_MASK                            0x0807
+#define HDMI_VP_POL                             0x0808
+
+/* Frame Composer Registers */
+#define HDMI_FC_INVIDCONF                       0x1000
+#define HDMI_FC_INHACTV0                        0x1001
+#define HDMI_FC_INHACTV1                        0x1002
+#define HDMI_FC_INHBLANK0                       0x1003
+#define HDMI_FC_INHBLANK1                       0x1004
+#define HDMI_FC_INVACTV0                        0x1005
+#define HDMI_FC_INVACTV1                        0x1006
+#define HDMI_FC_INVBLANK                        0x1007
+#define HDMI_FC_HSYNCINDELAY0                   0x1008
+#define HDMI_FC_HSYNCINDELAY1                   0x1009
+#define HDMI_FC_HSYNCINWIDTH0                   0x100A
+#define HDMI_FC_HSYNCINWIDTH1                   0x100B
+#define HDMI_FC_VSYNCINDELAY                    0x100C
+#define HDMI_FC_VSYNCINWIDTH                    0x100D
+#define HDMI_FC_INFREQ0                         0x100E
+#define HDMI_FC_INFREQ1                         0x100F
+#define HDMI_FC_INFREQ2                         0x1010
+#define HDMI_FC_CTRLDUR                         0x1011
+#define HDMI_FC_EXCTRLDUR                       0x1012
+#define HDMI_FC_EXCTRLSPAC                      0x1013
+#define HDMI_FC_CH0PREAM                        0x1014
+#define HDMI_FC_CH1PREAM                        0x1015
+#define HDMI_FC_CH2PREAM                        0x1016
+#define HDMI_FC_AVICONF3                        0x1017
+#define HDMI_FC_GCP                             0x1018
+#define HDMI_FC_AVICONF0                        0x1019
+#define HDMI_FC_AVICONF1                        0x101A
+#define HDMI_FC_AVICONF2                        0x101B
+#define HDMI_FC_AVIVID                          0x101C
+#define HDMI_FC_AVIETB0                         0x101D
+#define HDMI_FC_AVIETB1                         0x101E
+#define HDMI_FC_AVISBB0                         0x101F
+#define HDMI_FC_AVISBB1                         0x1020
+#define HDMI_FC_AVIELB0                         0x1021
+#define HDMI_FC_AVIELB1                         0x1022
+#define HDMI_FC_AVISRB0                         0x1023
+#define HDMI_FC_AVISRB1                         0x1024
+#define HDMI_FC_AUDICONF0                       0x1025
+#define HDMI_FC_AUDICONF1                       0x1026
+#define HDMI_FC_AUDICONF2                       0x1027
+#define HDMI_FC_AUDICONF3                       0x1028
+#define HDMI_FC_VSDIEEEID0                      0x1029
+#define HDMI_FC_VSDSIZE                         0x102A
+#define HDMI_FC_VSDIEEEID1                      0x1030
+#define HDMI_FC_VSDIEEEID2                      0x1031
+#define HDMI_FC_VSDPAYLOAD0                     0x1032
+#define HDMI_FC_VSDPAYLOAD1                     0x1033
+#define HDMI_FC_VSDPAYLOAD2                     0x1034
+#define HDMI_FC_VSDPAYLOAD3                     0x1035
+#define HDMI_FC_VSDPAYLOAD4                     0x1036
+#define HDMI_FC_VSDPAYLOAD5                     0x1037
+#define HDMI_FC_VSDPAYLOAD6                     0x1038
+#define HDMI_FC_VSDPAYLOAD7                     0x1039
+#define HDMI_FC_VSDPAYLOAD8                     0x103A
+#define HDMI_FC_VSDPAYLOAD9                     0x103B
+#define HDMI_FC_VSDPAYLOAD10                    0x103C
+#define HDMI_FC_VSDPAYLOAD11                    0x103D
+#define HDMI_FC_VSDPAYLOAD12                    0x103E
+#define HDMI_FC_VSDPAYLOAD13                    0x103F
+#define HDMI_FC_VSDPAYLOAD14                    0x1040
+#define HDMI_FC_VSDPAYLOAD15                    0x1041
+#define HDMI_FC_VSDPAYLOAD16                    0x1042
+#define HDMI_FC_VSDPAYLOAD17                    0x1043
+#define HDMI_FC_VSDPAYLOAD18                    0x1044
+#define HDMI_FC_VSDPAYLOAD19                    0x1045
+#define HDMI_FC_VSDPAYLOAD20                    0x1046
+#define HDMI_FC_VSDPAYLOAD21                    0x1047
+#define HDMI_FC_VSDPAYLOAD22                    0x1048
+#define HDMI_FC_VSDPAYLOAD23                    0x1049
+#define HDMI_FC_SPDVENDORNAME0                  0x104A
+#define HDMI_FC_SPDVENDORNAME1                  0x104B
+#define HDMI_FC_SPDVENDORNAME2                  0x104C
+#define HDMI_FC_SPDVENDORNAME3                  0x104D
+#define HDMI_FC_SPDVENDORNAME4                  0x104E
+#define HDMI_FC_SPDVENDORNAME5                  0x104F
+#define HDMI_FC_SPDVENDORNAME6                  0x1050
+#define HDMI_FC_SPDVENDORNAME7                  0x1051
+#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
+#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
+#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
+#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
+#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
+#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
+#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
+#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
+#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
+#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
+#define HDMI_FC_SDPPRODUCTNAME10                0x105C
+#define HDMI_FC_SDPPRODUCTNAME11                0x105D
+#define HDMI_FC_SDPPRODUCTNAME12                0x105E
+#define HDMI_FC_SDPPRODUCTNAME13                0x105F
+#define HDMI_FC_SDPPRODUCTNAME14                0x1060
+#define HDMI_FC_SPDPRODUCTNAME15                0x1061
+#define HDMI_FC_SPDDEVICEINF                    0x1062
+#define HDMI_FC_AUDSCONF                        0x1063
+#define HDMI_FC_AUDSSTAT                        0x1064
+#define HDMI_FC_DATACH0FILL                     0x1070
+#define HDMI_FC_DATACH1FILL                     0x1071
+#define HDMI_FC_DATACH2FILL                     0x1072
+#define HDMI_FC_CTRLQHIGH                       0x1073
+#define HDMI_FC_CTRLQLOW                        0x1074
+#define HDMI_FC_ACP0                            0x1075
+#define HDMI_FC_ACP28                           0x1076
+#define HDMI_FC_ACP27                           0x1077
+#define HDMI_FC_ACP26                           0x1078
+#define HDMI_FC_ACP25                           0x1079
+#define HDMI_FC_ACP24                           0x107A
+#define HDMI_FC_ACP23                           0x107B
+#define HDMI_FC_ACP22                           0x107C
+#define HDMI_FC_ACP21                           0x107D
+#define HDMI_FC_ACP20                           0x107E
+#define HDMI_FC_ACP19                           0x107F
+#define HDMI_FC_ACP18                           0x1080
+#define HDMI_FC_ACP17                           0x1081
+#define HDMI_FC_ACP16                           0x1082
+#define HDMI_FC_ACP15                           0x1083
+#define HDMI_FC_ACP14                           0x1084
+#define HDMI_FC_ACP13                           0x1085
+#define HDMI_FC_ACP12                           0x1086
+#define HDMI_FC_ACP11                           0x1087
+#define HDMI_FC_ACP10                           0x1088
+#define HDMI_FC_ACP9                            0x1089
+#define HDMI_FC_ACP8                            0x108A
+#define HDMI_FC_ACP7                            0x108B
+#define HDMI_FC_ACP6                            0x108C
+#define HDMI_FC_ACP5                            0x108D
+#define HDMI_FC_ACP4                            0x108E
+#define HDMI_FC_ACP3                            0x108F
+#define HDMI_FC_ACP2                            0x1090
+#define HDMI_FC_ACP1                            0x1091
+#define HDMI_FC_ISCR1_0                         0x1092
+#define HDMI_FC_ISCR1_16                        0x1093
+#define HDMI_FC_ISCR1_15                        0x1094
+#define HDMI_FC_ISCR1_14                        0x1095
+#define HDMI_FC_ISCR1_13                        0x1096
+#define HDMI_FC_ISCR1_12                        0x1097
+#define HDMI_FC_ISCR1_11                        0x1098
+#define HDMI_FC_ISCR1_10                        0x1099
+#define HDMI_FC_ISCR1_9                         0x109A
+#define HDMI_FC_ISCR1_8                         0x109B
+#define HDMI_FC_ISCR1_7                         0x109C
+#define HDMI_FC_ISCR1_6                         0x109D
+#define HDMI_FC_ISCR1_5                         0x109E
+#define HDMI_FC_ISCR1_4                         0x109F
+#define HDMI_FC_ISCR1_3                         0x10A0
+#define HDMI_FC_ISCR1_2                         0x10A1
+#define HDMI_FC_ISCR1_1                         0x10A2
+#define HDMI_FC_ISCR2_15                        0x10A3
+#define HDMI_FC_ISCR2_14                        0x10A4
+#define HDMI_FC_ISCR2_13                        0x10A5
+#define HDMI_FC_ISCR2_12                        0x10A6
+#define HDMI_FC_ISCR2_11                        0x10A7
+#define HDMI_FC_ISCR2_10                        0x10A8
+#define HDMI_FC_ISCR2_9                         0x10A9
+#define HDMI_FC_ISCR2_8                         0x10AA
+#define HDMI_FC_ISCR2_7                         0x10AB
+#define HDMI_FC_ISCR2_6                         0x10AC
+#define HDMI_FC_ISCR2_5                         0x10AD
+#define HDMI_FC_ISCR2_4                         0x10AE
+#define HDMI_FC_ISCR2_3                         0x10AF
+#define HDMI_FC_ISCR2_2                         0x10B0
+#define HDMI_FC_ISCR2_1                         0x10B1
+#define HDMI_FC_ISCR2_0                         0x10B2
+#define HDMI_FC_DATAUTO0                        0x10B3
+#define HDMI_FC_DATAUTO1                        0x10B4
+#define HDMI_FC_DATAUTO2                        0x10B5
+#define HDMI_FC_DATMAN                          0x10B6
+#define HDMI_FC_DATAUTO3                        0x10B7
+#define HDMI_FC_RDRB0                           0x10B8
+#define HDMI_FC_RDRB1                           0x10B9
+#define HDMI_FC_RDRB2                           0x10BA
+#define HDMI_FC_RDRB3                           0x10BB
+#define HDMI_FC_RDRB4                           0x10BC
+#define HDMI_FC_RDRB5                           0x10BD
+#define HDMI_FC_RDRB6                           0x10BE
+#define HDMI_FC_RDRB7                           0x10BF
+#define HDMI_FC_STAT0                           0x10D0
+#define HDMI_FC_INT0                            0x10D1
+#define HDMI_FC_MASK0                           0x10D2
+#define HDMI_FC_POL0                            0x10D3
+#define HDMI_FC_STAT1                           0x10D4
+#define HDMI_FC_INT1                            0x10D5
+#define HDMI_FC_MASK1                           0x10D6
+#define HDMI_FC_POL1                            0x10D7
+#define HDMI_FC_STAT2                           0x10D8
+#define HDMI_FC_INT2                            0x10D9
+#define HDMI_FC_MASK2                           0x10DA
+#define HDMI_FC_POL2                            0x10DB
+#define HDMI_FC_PRCONF                          0x10E0
+
+#define HDMI_FC_GMD_STAT                        0x1100
+#define HDMI_FC_GMD_EN                          0x1101
+#define HDMI_FC_GMD_UP                          0x1102
+#define HDMI_FC_GMD_CONF                        0x1103
+#define HDMI_FC_GMD_HB                          0x1104
+#define HDMI_FC_GMD_PB0                         0x1105
+#define HDMI_FC_GMD_PB1                         0x1106
+#define HDMI_FC_GMD_PB2                         0x1107
+#define HDMI_FC_GMD_PB3                         0x1108
+#define HDMI_FC_GMD_PB4                         0x1109
+#define HDMI_FC_GMD_PB5                         0x110A
+#define HDMI_FC_GMD_PB6                         0x110B
+#define HDMI_FC_GMD_PB7                         0x110C
+#define HDMI_FC_GMD_PB8                         0x110D
+#define HDMI_FC_GMD_PB9                         0x110E
+#define HDMI_FC_GMD_PB10                        0x110F
+#define HDMI_FC_GMD_PB11                        0x1110
+#define HDMI_FC_GMD_PB12                        0x1111
+#define HDMI_FC_GMD_PB13                        0x1112
+#define HDMI_FC_GMD_PB14                        0x1113
+#define HDMI_FC_GMD_PB15                        0x1114
+#define HDMI_FC_GMD_PB16                        0x1115
+#define HDMI_FC_GMD_PB17                        0x1116
+#define HDMI_FC_GMD_PB18                        0x1117
+#define HDMI_FC_GMD_PB19                        0x1118
+#define HDMI_FC_GMD_PB20                        0x1119
+#define HDMI_FC_GMD_PB21                        0x111A
+#define HDMI_FC_GMD_PB22                        0x111B
+#define HDMI_FC_GMD_PB23                        0x111C
+#define HDMI_FC_GMD_PB24                        0x111D
+#define HDMI_FC_GMD_PB25                        0x111E
+#define HDMI_FC_GMD_PB26                        0x111F
+#define HDMI_FC_GMD_PB27                        0x1120
+
+#define HDMI_FC_DBGFORCE                        0x1200
+#define HDMI_FC_DBGAUD0CH0                      0x1201
+#define HDMI_FC_DBGAUD1CH0                      0x1202
+#define HDMI_FC_DBGAUD2CH0                      0x1203
+#define HDMI_FC_DBGAUD0CH1                      0x1204
+#define HDMI_FC_DBGAUD1CH1                      0x1205
+#define HDMI_FC_DBGAUD2CH1                      0x1206
+#define HDMI_FC_DBGAUD0CH2                      0x1207
+#define HDMI_FC_DBGAUD1CH2                      0x1208
+#define HDMI_FC_DBGAUD2CH2                      0x1209
+#define HDMI_FC_DBGAUD0CH3                      0x120A
+#define HDMI_FC_DBGAUD1CH3                      0x120B
+#define HDMI_FC_DBGAUD2CH3                      0x120C
+#define HDMI_FC_DBGAUD0CH4                      0x120D
+#define HDMI_FC_DBGAUD1CH4                      0x120E
+#define HDMI_FC_DBGAUD2CH4                      0x120F
+#define HDMI_FC_DBGAUD0CH5                      0x1210
+#define HDMI_FC_DBGAUD1CH5                      0x1211
+#define HDMI_FC_DBGAUD2CH5                      0x1212
+#define HDMI_FC_DBGAUD0CH6                      0x1213
+#define HDMI_FC_DBGAUD1CH6                      0x1214
+#define HDMI_FC_DBGAUD2CH6                      0x1215
+#define HDMI_FC_DBGAUD0CH7                      0x1216
+#define HDMI_FC_DBGAUD1CH7                      0x1217
+#define HDMI_FC_DBGAUD2CH7                      0x1218
+#define HDMI_FC_DBGTMDS0                        0x1219
+#define HDMI_FC_DBGTMDS1                        0x121A
+#define HDMI_FC_DBGTMDS2                        0x121B
+
+/* HDMI Source PHY Registers */
+#define HDMI_PHY_CONF0                          0x3000
+#define HDMI_PHY_TST0                           0x3001
+#define HDMI_PHY_TST1                           0x3002
+#define HDMI_PHY_TST2                           0x3003
+#define HDMI_PHY_STAT0                          0x3004
+#define HDMI_PHY_INT0                           0x3005
+#define HDMI_PHY_MASK0                          0x3006
+#define HDMI_PHY_POL0                           0x3007
+
+/* HDMI Master PHY Registers */
+#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
+#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
+
+/* Audio Sampler Registers */
+#define HDMI_AUD_CONF0                          0x3100
+#define HDMI_AUD_CONF1                          0x3101
+#define HDMI_AUD_INT                            0x3102
+#define HDMI_AUD_CONF2                          0x3103
+#define HDMI_AUD_N1                             0x3200
+#define HDMI_AUD_N2                             0x3201
+#define HDMI_AUD_N3                             0x3202
+#define HDMI_AUD_CTS1                           0x3203
+#define HDMI_AUD_CTS2                           0x3204
+#define HDMI_AUD_CTS3                           0x3205
+#define HDMI_AUD_INPUTCLKFS                     0x3206
+#define HDMI_AUD_SPDIFINT			0x3302
+#define HDMI_AUD_CONF0_HBR                      0x3400
+#define HDMI_AUD_HBR_STATUS                     0x3401
+#define HDMI_AUD_HBR_INT                        0x3402
+#define HDMI_AUD_HBR_POL                        0x3403
+#define HDMI_AUD_HBR_MASK                       0x3404
+
+/*
+ * Generic Parallel Audio Interface Registers
+ * Not used as GPAUD interface is not enabled in hw
+ */
+#define HDMI_GP_CONF0                           0x3500
+#define HDMI_GP_CONF1                           0x3501
+#define HDMI_GP_CONF2                           0x3502
+#define HDMI_GP_STAT                            0x3503
+#define HDMI_GP_INT                             0x3504
+#define HDMI_GP_MASK                            0x3505
+#define HDMI_GP_POL                             0x3506
+
+/* Audio DMA Registers */
+#define HDMI_AHB_DMA_CONF0                      0x3600
+#define HDMI_AHB_DMA_START                      0x3601
+#define HDMI_AHB_DMA_STOP                       0x3602
+#define HDMI_AHB_DMA_THRSLD                     0x3603
+#define HDMI_AHB_DMA_STRADDR0                   0x3604
+#define HDMI_AHB_DMA_STRADDR1                   0x3605
+#define HDMI_AHB_DMA_STRADDR2                   0x3606
+#define HDMI_AHB_DMA_STRADDR3                   0x3607
+#define HDMI_AHB_DMA_STPADDR0                   0x3608
+#define HDMI_AHB_DMA_STPADDR1                   0x3609
+#define HDMI_AHB_DMA_STPADDR2                   0x360a
+#define HDMI_AHB_DMA_STPADDR3                   0x360b
+#define HDMI_AHB_DMA_BSTADDR0                   0x360c
+#define HDMI_AHB_DMA_BSTADDR1                   0x360d
+#define HDMI_AHB_DMA_BSTADDR2                   0x360e
+#define HDMI_AHB_DMA_BSTADDR3                   0x360f
+#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
+#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
+#define HDMI_AHB_DMA_STAT                       0x3612
+#define HDMI_AHB_DMA_INT                        0x3613
+#define HDMI_AHB_DMA_MASK                       0x3614
+#define HDMI_AHB_DMA_POL                        0x3615
+#define HDMI_AHB_DMA_CONF1                      0x3616
+#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
+#define HDMI_AHB_DMA_BUFFINT                    0x3618
+#define HDMI_AHB_DMA_BUFFMASK                   0x3619
+#define HDMI_AHB_DMA_BUFFPOL                    0x361a
+
+/* Main Controller Registers */
+#define HDMI_MC_SFRDIV                          0x4000
+#define HDMI_MC_CLKDIS                          0x4001
+#define HDMI_MC_SWRSTZ                          0x4002
+#define HDMI_MC_OPCTRL                          0x4003
+#define HDMI_MC_FLOWCTRL                        0x4004
+#define HDMI_MC_PHYRSTZ                         0x4005
+#define HDMI_MC_LOCKONCLOCK                     0x4006
+#define HDMI_MC_HEACPHY_RST                     0x4007
+
+/* Color Space  Converter Registers */
+#define HDMI_CSC_CFG                            0x4100
+#define HDMI_CSC_SCALE                          0x4101
+#define HDMI_CSC_COEF_A1_MSB                    0x4102
+#define HDMI_CSC_COEF_A1_LSB                    0x4103
+#define HDMI_CSC_COEF_A2_MSB                    0x4104
+#define HDMI_CSC_COEF_A2_LSB                    0x4105
+#define HDMI_CSC_COEF_A3_MSB                    0x4106
+#define HDMI_CSC_COEF_A3_LSB                    0x4107
+#define HDMI_CSC_COEF_A4_MSB                    0x4108
+#define HDMI_CSC_COEF_A4_LSB                    0x4109
+#define HDMI_CSC_COEF_B1_MSB                    0x410A
+#define HDMI_CSC_COEF_B1_LSB                    0x410B
+#define HDMI_CSC_COEF_B2_MSB                    0x410C
+#define HDMI_CSC_COEF_B2_LSB                    0x410D
+#define HDMI_CSC_COEF_B3_MSB                    0x410E
+#define HDMI_CSC_COEF_B3_LSB                    0x410F
+#define HDMI_CSC_COEF_B4_MSB                    0x4110
+#define HDMI_CSC_COEF_B4_LSB                    0x4111
+#define HDMI_CSC_COEF_C1_MSB                    0x4112
+#define HDMI_CSC_COEF_C1_LSB                    0x4113
+#define HDMI_CSC_COEF_C2_MSB                    0x4114
+#define HDMI_CSC_COEF_C2_LSB                    0x4115
+#define HDMI_CSC_COEF_C3_MSB                    0x4116
+#define HDMI_CSC_COEF_C3_LSB                    0x4117
+#define HDMI_CSC_COEF_C4_MSB                    0x4118
+#define HDMI_CSC_COEF_C4_LSB                    0x4119
+
+/* HDCP Encryption Engine Registers */
+#define HDMI_A_HDCPCFG0                         0x5000
+#define HDMI_A_HDCPCFG1                         0x5001
+#define HDMI_A_HDCPOBS0                         0x5002
+#define HDMI_A_HDCPOBS1                         0x5003
+#define HDMI_A_HDCPOBS2                         0x5004
+#define HDMI_A_HDCPOBS3                         0x5005
+#define HDMI_A_APIINTCLR                        0x5006
+#define HDMI_A_APIINTSTAT                       0x5007
+#define HDMI_A_APIINTMSK                        0x5008
+#define HDMI_A_VIDPOLCFG                        0x5009
+#define HDMI_A_OESSWCFG                         0x500A
+#define HDMI_A_TIMER1SETUP0                     0x500B
+#define HDMI_A_TIMER1SETUP1                     0x500C
+#define HDMI_A_TIMER2SETUP0                     0x500D
+#define HDMI_A_TIMER2SETUP1                     0x500E
+#define HDMI_A_100MSCFG                         0x500F
+#define HDMI_A_2SCFG0                           0x5010
+#define HDMI_A_2SCFG1                           0x5011
+#define HDMI_A_5SCFG0                           0x5012
+#define HDMI_A_5SCFG1                           0x5013
+#define HDMI_A_SRMVERLSB                        0x5014
+#define HDMI_A_SRMVERMSB                        0x5015
+#define HDMI_A_SRMCTRL                          0x5016
+#define HDMI_A_SFRSETUP                         0x5017
+#define HDMI_A_I2CHSETUP                        0x5018
+#define HDMI_A_INTSETUP                         0x5019
+#define HDMI_A_PRESETUP                         0x501A
+#define HDMI_A_SRM_BASE                         0x5020
+
+/* CEC Engine Registers */
+#define HDMI_CEC_CTRL                           0x7D00
+#define HDMI_CEC_STAT                           0x7D01
+#define HDMI_CEC_MASK                           0x7D02
+#define HDMI_CEC_POLARITY                       0x7D03
+#define HDMI_CEC_INT                            0x7D04
+#define HDMI_CEC_ADDR_L                         0x7D05
+#define HDMI_CEC_ADDR_H                         0x7D06
+#define HDMI_CEC_TX_CNT                         0x7D07
+#define HDMI_CEC_RX_CNT                         0x7D08
+#define HDMI_CEC_TX_DATA0                       0x7D10
+#define HDMI_CEC_TX_DATA1                       0x7D11
+#define HDMI_CEC_TX_DATA2                       0x7D12
+#define HDMI_CEC_TX_DATA3                       0x7D13
+#define HDMI_CEC_TX_DATA4                       0x7D14
+#define HDMI_CEC_TX_DATA5                       0x7D15
+#define HDMI_CEC_TX_DATA6                       0x7D16
+#define HDMI_CEC_TX_DATA7                       0x7D17
+#define HDMI_CEC_TX_DATA8                       0x7D18
+#define HDMI_CEC_TX_DATA9                       0x7D19
+#define HDMI_CEC_TX_DATA10                      0x7D1a
+#define HDMI_CEC_TX_DATA11                      0x7D1b
+#define HDMI_CEC_TX_DATA12                      0x7D1c
+#define HDMI_CEC_TX_DATA13                      0x7D1d
+#define HDMI_CEC_TX_DATA14                      0x7D1e
+#define HDMI_CEC_TX_DATA15                      0x7D1f
+#define HDMI_CEC_RX_DATA0                       0x7D20
+#define HDMI_CEC_RX_DATA1                       0x7D21
+#define HDMI_CEC_RX_DATA2                       0x7D22
+#define HDMI_CEC_RX_DATA3                       0x7D23
+#define HDMI_CEC_RX_DATA4                       0x7D24
+#define HDMI_CEC_RX_DATA5                       0x7D25
+#define HDMI_CEC_RX_DATA6                       0x7D26
+#define HDMI_CEC_RX_DATA7                       0x7D27
+#define HDMI_CEC_RX_DATA8                       0x7D28
+#define HDMI_CEC_RX_DATA9                       0x7D29
+#define HDMI_CEC_RX_DATA10                      0x7D2a
+#define HDMI_CEC_RX_DATA11                      0x7D2b
+#define HDMI_CEC_RX_DATA12                      0x7D2c
+#define HDMI_CEC_RX_DATA13                      0x7D2d
+#define HDMI_CEC_RX_DATA14                      0x7D2e
+#define HDMI_CEC_RX_DATA15                      0x7D2f
+#define HDMI_CEC_LOCK                           0x7D30
+#define HDMI_CEC_WKUPCTRL                       0x7D31
+
+/* I2C Master Registers (E-DDC) */
+#define HDMI_I2CM_SLAVE                         0x7E00
+#define HDMI_I2CMESS                            0x7E01
+#define HDMI_I2CM_DATAO                         0x7E02
+#define HDMI_I2CM_DATAI                         0x7E03
+#define HDMI_I2CM_OPERATION                     0x7E04
+#define HDMI_I2CM_INT                           0x7E05
+#define HDMI_I2CM_CTLINT                        0x7E06
+#define HDMI_I2CM_DIV                           0x7E07
+#define HDMI_I2CM_SEGADDR                       0x7E08
+#define HDMI_I2CM_SOFTRSTZ                      0x7E09
+#define HDMI_I2CM_SEGPTR                        0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
+
+enum {
+/* IH_FC_INT2 field values */
+	HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_FC_STAT2 field values */
+	HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_PHY_STAT0 field values */
+	HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
+	HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
+	HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
+	HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
+	HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
+	HDMI_IH_PHY_STAT0_HPD = 0x1,
+
+/* IH_MUTE_I2CMPHY_STAT0 field values */
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
+/* IH_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE_FC_STAT2 field values */
+	HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_MUTE_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE field values */
+	HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
+	HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
+
+/* TX_INVID0 field values */
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
+	HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
+	HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
+
+/* TX_INSTUFFING field values */
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
+
+/* VP_PR_CD field values */
+	HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
+	HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
+
+/* VP_STUFF field values */
+	HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
+	HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
+	HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
+
+/* VP_CONF field values */
+	HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
+	HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
+	HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PR_EN_MASK = 0x10,
+	HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
+	HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
+	HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
+	HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
+	HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
+
+/* VP_REMAP field values */
+	HDMI_VP_REMAP_MASK = 0x3,
+	HDMI_VP_REMAP_YCC422_24bit = 0x2,
+	HDMI_VP_REMAP_YCC422_20bit = 0x1,
+	HDMI_VP_REMAP_YCC422_16bit = 0x0,
+
+/* FC_INVIDCONF field values */
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
+	HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
+
+/* FC_AUDICONF0 field values */
+	HDMI_FC_AUDICONF0_CC_OFFSET = 4,
+	HDMI_FC_AUDICONF0_CC_MASK = 0x70,
+	HDMI_FC_AUDICONF0_CT_OFFSET = 0,
+	HDMI_FC_AUDICONF0_CT_MASK = 0xF,
+
+/* FC_AUDICONF1 field values */
+	HDMI_FC_AUDICONF1_SS_OFFSET = 3,
+	HDMI_FC_AUDICONF1_SS_MASK = 0x18,
+	HDMI_FC_AUDICONF1_SF_OFFSET = 0,
+	HDMI_FC_AUDICONF1_SF_MASK = 0x7,
+
+/* FC_AUDICONF3 field values */
+	HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
+	HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
+	HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
+	HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
+	HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
+	HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
+
+/* FC_AUDSCHNLS0 field values */
+	HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
+
+/* FC_AUDSCHNLS3-6 field values */
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
+
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
+
+/* HDMI_FC_AUDSCHNLS7 field values */
+	HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+
+/* HDMI_FC_AUDSCHNLS8 field values */
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+
+/* FC_AUDSCONF field values */
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
+
+/* FC_STAT2 field values */
+	HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_INT2 field values */
+	HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_MASK2 field values */
+	HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_PRCONF field values */
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
+
+/* FC_AVICONF0-FC_AVICONF3 field values */
+	HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
+	HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
+	HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+	HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+	HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+	HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+	HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
+	HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
+
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
+	HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
+	HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
+	HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
+	HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
+
+	HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
+	HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
+	HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
+	HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
+	HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
+	HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
+	HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
+	HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
+	HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
+	HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
+	HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
+	HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
+
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
+	HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
+	HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
+	HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+
+/* FC_DBGFORCE field values */
+	HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
+	HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+
+/* PHY_CONF0 field values */
+	HDMI_PHY_CONF0_PDZ_MASK = 0x80,
+	HDMI_PHY_CONF0_PDZ_OFFSET = 7,
+	HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
+	HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
+	HDMI_PHY_CONF0_SPARECTRL = 0x20,
+	HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
+	HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
+	HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
+	HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
+	HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
+	HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
+
+/* PHY_TST0 field values */
+	HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
+	HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
+	HDMI_PHY_TST0_TSTEN_MASK = 0x10,
+	HDMI_PHY_TST0_TSTEN_OFFSET = 4,
+	HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
+	HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
+
+/* PHY_STAT0 field values */
+	HDMI_PHY_RX_SENSE3 = 0x80,
+	HDMI_PHY_RX_SENSE2 = 0x40,
+	HDMI_PHY_RX_SENSE1 = 0x20,
+	HDMI_PHY_RX_SENSE0 = 0x10,
+	HDMI_PHY_HPD = 0x02,
+	HDMI_PHY_TX_PHY_LOCK = 0x01,
+
+/* PHY_I2CM_SLAVE_ADDR field values */
+	HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
+	HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
+
+/* PHY_I2CM_OPERATION_ADDR field values */
+	HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
+	HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
+
+/* HDMI_PHY_I2CM_INT_ADDR */
+	HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
+	HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
+
+/* HDMI_PHY_I2CM_CTLINT_ADDR */
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
+
+/* AUD_CTS3 field values */
+	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
+	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
+	HDMI_AUD_CTS3_N_SHIFT_1 = 0,
+	HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
+	HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
+	HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
+	HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
+	HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
+	/* note that the CTS3 MANUAL bit has been removed
+	   from our part. Can't set it, will read as 0. */
+	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
+	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
+
+/* AHB_DMA_CONF0 field values */
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
+	HDMI_AHB_DMA_CONF0_HBR = 0x10,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
+	HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
+	HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
+	HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
+	HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
+
+/* HDMI_AHB_DMA_START field values */
+	HDMI_AHB_DMA_START_START_OFFSET = 0,
+	HDMI_AHB_DMA_START_START_MASK = 0x01,
+
+/* HDMI_AHB_DMA_STOP field values */
+	HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
+	HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
+
+/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
+	HDMI_AHB_DMA_DONE = 0x80,
+	HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
+	HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
+	HDMI_AHB_DMA_ERROR = 0x10,
+	HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
+	HDMI_AHB_DMA_FIFO_FULL = 0x02,
+	HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
+
+/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
+	HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
+	HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
+
+/* MC_CLKDIS field values */
+	HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
+	HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
+	HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
+	HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
+	HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
+	HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
+	HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
+
+/* MC_SWRSTZ field values */
+	HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+
+/* MC_FLOWCTRL field values */
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
+
+/* MC_PHYRSTZ field values */
+	HDMI_MC_PHYRSTZ_ASSERT = 0x0,
+	HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+
+/* MC_HEACPHY_RST field values */
+	HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
+	HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
+
+/* CSC_CFG field values */
+	HDMI_CSC_CFG_INTMODE_MASK = 0x30,
+	HDMI_CSC_CFG_INTMODE_OFFSET = 4,
+	HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
+	HDMI_CSC_CFG_DECMODE_MASK = 0x3,
+	HDMI_CSC_CFG_DECMODE_OFFSET = 0,
+	HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
+
+/* CSC_SCALE field values */
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
+	HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
+
+/* A_HDCPCFG0 field values */
+	HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
+
+/* A_HDCPCFG1 field values */
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
+	HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+
+/* A_VIDPOLCFG field values */
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
+	HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
+};
+#endif /* __IMX_HDMI_H__ */
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index b6d36b38b99c..866e355fa409 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -212,6 +212,7 @@
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1	(0x1 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0	(0x2 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1	(0x3 << 4)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT		2
 #define IMX6Q_GPR3_HDMI_MUX_CTL_MASK		(0x3 << 2)
 #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0	(0x0 << 2)
 #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1	(0x1 << 2)
-- 
1.7.4.4

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

* [PATCH RFC 08/46] imx-drm: add imx6 DT configuration for HDMI
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

Extracted from another patch by Fabio Estevam, this adds the DT
configuration for HDMI output on the IMX6 SoCs

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl.dtsi  |    4 ++++
 arch/arm/boot/dts/imx6q.dtsi   |    4 ++++
 arch/arm/boot/dts/imx6qdl.dtsi |   10 ++++++++++
 3 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9e8ae118fdd4..65e54b4529c5 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -88,3 +88,7 @@
 		crtcs = <&ipu1 0>, <&ipu1 1>;
 	};
 };
+
+&hdmi {
+	crtcs = <&ipu1 0>, <&ipu1 1>;
+}
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index f024ef28b34b..d2467f532de6 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -159,3 +159,7 @@
 		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
 	};
 };
+
+&hdmi {
+	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2ecb1db..400bbc624f25 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1368,6 +1368,16 @@
 				};
 			};
 
+			hdmi: hdmi at 0120000 {
+				compatible = "fsl,imx6q-hdmi";
+				reg = <0x00120000 0x9000>;
+				interrupts = <0 115 0x04>;
+				gpr = <&gpr>;
+				clocks = <&clks 123>, <&clks 124>;
+				clock-names = "iahb", "isfr";
+				status = "disabled";
+			};
+
 			dcic1: dcic at 020e4000 {
 				reg = <0x020e4000 0x4000>;
 				interrupts = <0 124 0x04>;
-- 
1.7.4.4

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

* [PATCH RFC 08/46] imx-drm: add imx6 DT configuration for HDMI
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Extracted from another patch by Fabio Estevam, this adds the DT
configuration for HDMI output on the IMX6 SoCs

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl.dtsi  |    4 ++++
 arch/arm/boot/dts/imx6q.dtsi   |    4 ++++
 arch/arm/boot/dts/imx6qdl.dtsi |   10 ++++++++++
 3 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 9e8ae118fdd4..65e54b4529c5 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -88,3 +88,7 @@
 		crtcs = <&ipu1 0>, <&ipu1 1>;
 	};
 };
+
+&hdmi {
+	crtcs = <&ipu1 0>, <&ipu1 1>;
+}
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index f024ef28b34b..d2467f532de6 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -159,3 +159,7 @@
 		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
 	};
 };
+
+&hdmi {
+	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index fb28b2ecb1db..400bbc624f25 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1368,6 +1368,16 @@
 				};
 			};
 
+			hdmi: hdmi@0120000 {
+				compatible = "fsl,imx6q-hdmi";
+				reg = <0x00120000 0x9000>;
+				interrupts = <0 115 0x04>;
+				gpr = <&gpr>;
+				clocks = <&clks 123>, <&clks 124>;
+				clock-names = "iahb", "isfr";
+				status = "disabled";
+			};
+
 			dcic1: dcic@020e4000 {
 				reg = <0x020e4000 0x4000>;
 				interrupts = <0 124 0x04>;
-- 
1.7.4.4

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

* [PATCH RFC 09/46] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl.dtsi  |    3 ++-
 arch/arm/boot/dts/imx6q.dtsi   |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi |    1 -
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 65e54b4529c5..6dc397022214 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -90,5 +90,6 @@
 };
 
 &hdmi {
+	compatible = "fsl,imx6dl-hdmi";
 	crtcs = <&ipu1 0>, <&ipu1 1>;
-}
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index d2467f532de6..187fe33ba515 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -161,5 +161,6 @@
 };
 
 &hdmi {
+	compatible = "fsl,imx6q-hdmi";
 	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 400bbc624f25..930ebe0c2937 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,7 +1369,6 @@
 			};
 
 			hdmi: hdmi at 0120000 {
-				compatible = "fsl,imx6q-hdmi";
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
-- 
1.7.4.4

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

* [PATCH RFC 09/46] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx6dl.dtsi  |    3 ++-
 arch/arm/boot/dts/imx6q.dtsi   |    1 +
 arch/arm/boot/dts/imx6qdl.dtsi |    1 -
 3 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 65e54b4529c5..6dc397022214 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -90,5 +90,6 @@
 };
 
 &hdmi {
+	compatible = "fsl,imx6dl-hdmi";
 	crtcs = <&ipu1 0>, <&ipu1 1>;
-}
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index d2467f532de6..187fe33ba515 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -161,5 +161,6 @@
 };
 
 &hdmi {
+	compatible = "fsl,imx6q-hdmi";
 	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 400bbc624f25..930ebe0c2937 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,7 +1369,6 @@
 			};
 
 			hdmi: hdmi@0120000 {
-				compatible = "fsl,imx6q-hdmi";
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
-- 
1.7.4.4

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

* [PATCH RFC 10/46] imx-drm: imx-hdmi: fix PLL lock wait
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

Enabling the debug for PLL lock shows that this times out almost every
time.  Having such an event at debug level is probably a bug in itself
because it hides this fact.

Waiting 5ms seems to allow it to lock.  Also, adjust the loop so that
we check for success before checking whether we've timed out: we don't
want to wait and then fail without first checking whether we locked.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   20 ++++++++++++--------
 1 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 2022635fffdf..ff00759b4d6f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1032,16 +1032,20 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 	imx_hdmi_phy_gen2_pddq(hdmi, 0);
 
 	/*Wait for PHY PLL lock */
-	msec = 4;
-	val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-	while (!val) {
-		udelay(1000);
-		if (msec-- == 0) {
-			dev_dbg(hdmi->dev, "PHY PLL not locked\n");
+	msec = 5;
+	do {
+		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+		if (!val)
+			break;
+
+		if (msec == 0) {
+			dev_err(hdmi->dev, "PHY PLL not locked\n");
 			return -EINVAL;
 		}
-		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-	}
+
+		udelay(1000);
+		msec--;
+	} while (1);
 
 	return 0;
 }
-- 
1.7.4.4

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

* [PATCH RFC 10/46] imx-drm: imx-hdmi: fix PLL lock wait
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Enabling the debug for PLL lock shows that this times out almost every
time.  Having such an event at debug level is probably a bug in itself
because it hides this fact.

Waiting 5ms seems to allow it to lock.  Also, adjust the loop so that
we check for success before checking whether we've timed out: we don't
want to wait and then fail without first checking whether we locked.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   20 ++++++++++++--------
 1 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 2022635fffdf..ff00759b4d6f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1032,16 +1032,20 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 	imx_hdmi_phy_gen2_pddq(hdmi, 0);
 
 	/*Wait for PHY PLL lock */
-	msec = 4;
-	val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-	while (!val) {
-		udelay(1000);
-		if (msec-- == 0) {
-			dev_dbg(hdmi->dev, "PHY PLL not locked\n");
+	msec = 5;
+	do {
+		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+		if (!val)
+			break;
+
+		if (msec == 0) {
+			dev_err(hdmi->dev, "PHY PLL not locked\n");
 			return -EINVAL;
 		}
-		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
-	}
+
+		udelay(1000);
+		msec--;
+	} while (1);
 
 	return 0;
 }
-- 
1.7.4.4

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

* [PATCH RFC 11/46] imx-drm: imx-hdmi: fix pixel clock
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

The correct pixel clock can be found in the drm_display_mode structure.
Use this rather than trying to calculate it from the h/v total and the
refresh rate, which can be inaccurate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ff00759b4d6f..fe3a6779b620 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1206,8 +1206,7 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
 	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
 	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
 	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
-	vmode->mpixelclock = mode->htotal * mode->vtotal *
-			     drm_mode_vrefresh(mode);
+	vmode->mpixelclock = mode->clock * 1000;
 
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
-- 
1.7.4.4

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

* [PATCH RFC 11/46] imx-drm: imx-hdmi: fix pixel clock
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The correct pixel clock can be found in the drm_display_mode structure.
Use this rather than trying to calculate it from the h/v total and the
refresh rate, which can be inaccurate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ff00759b4d6f..fe3a6779b620 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1206,8 +1206,7 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
 	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
 	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
 	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
-	vmode->mpixelclock = mode->htotal * mode->vtotal *
-			     drm_mode_vrefresh(mode);
+	vmode->mpixelclock = mode->clock * 1000;
 
 	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
 
-- 
1.7.4.4

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

* [PATCH RFC 12/46] imx-drm: imx-hdmi: fix wrong comment
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

The vsync active edge delay is in lines, not pixel clocks.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index fe3a6779b620..0cba5d4a9966 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1275,7 +1275,7 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
 	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
 	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
 
-	/* Set up VSYNC active edge delay (in pixel clks) */
+	/* Set up VSYNC active edge delay (in lines) */
 	vsync_len = mode->vsync_end - mode->vsync_start;
 	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
-- 
1.7.4.4

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

* [PATCH RFC 12/46] imx-drm: imx-hdmi: fix wrong comment
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The vsync active edge delay is in lines, not pixel clocks.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index fe3a6779b620..0cba5d4a9966 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1275,7 +1275,7 @@ static void hdmi_av_composer(struct imx_hdmi *hdmi,
 	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
 	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
 
-	/* Set up VSYNC active edge delay (in pixel clks) */
+	/* Set up VSYNC active edge delay (in lines) */
 	vsync_len = mode->vsync_end - mode->vsync_start;
 	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
 }
-- 
1.7.4.4

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

* [PATCH RFC 13/46] imx-drm: imx-hdmi: get rid of pointless fb_reg
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

fb_reg provides no real benefit to the driver: imx_hdmi_fb_registered()
will never be called multiple times.  Let's get rid of this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 0cba5d4a9966..267d3c9114c6 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -130,7 +130,6 @@ struct imx_hdmi {
 	int vic;
 
 	u8 edid[HDMI_EDID_LEN];
-	bool fb_reg;
 	bool cable_plugin;
 
 	bool phy_enabled;
@@ -1451,9 +1450,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
 	int ret;
 
-	if (hdmi->fb_reg)
-		return 0;
-
 	ret = clk_prepare_enable(hdmi->iahb_clk);
 	if (ret)
 		return ret;
@@ -1474,8 +1470,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
-	hdmi->fb_reg = true;
-
 	clk_disable_unprepare(hdmi->iahb_clk);
 
 	return 0;
-- 
1.7.4.4

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

* [PATCH RFC 13/46] imx-drm: imx-hdmi: get rid of pointless fb_reg
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

fb_reg provides no real benefit to the driver: imx_hdmi_fb_registered()
will never be called multiple times.  Let's get rid of this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 0cba5d4a9966..267d3c9114c6 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -130,7 +130,6 @@ struct imx_hdmi {
 	int vic;
 
 	u8 edid[HDMI_EDID_LEN];
-	bool fb_reg;
 	bool cable_plugin;
 
 	bool phy_enabled;
@@ -1451,9 +1450,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
 	int ret;
 
-	if (hdmi->fb_reg)
-		return 0;
-
 	ret = clk_prepare_enable(hdmi->iahb_clk);
 	if (ret)
 		return ret;
@@ -1474,8 +1470,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
-	hdmi->fb_reg = true;
-
 	clk_disable_unprepare(hdmi->iahb_clk);
 
 	return 0;
-- 
1.7.4.4

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

* [PATCH RFC 14/46] imx-drm: imx-hdmi: get rid of clk manipulations in imx_hdmi_fb_registered()
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:26   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: linux-arm-kernel

The clock manipulations do nothing for us: the clock is already enabled
by the only caller (imx_hdmi_platform_probe()).  Get rid of these and
simplify the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    8 --------
 1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 267d3c9114c6..1eb12c57aa3e 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1448,12 +1448,6 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 /* Wait until we are registered to enable interrupts */
 static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
-	int ret;
-
-	ret = clk_prepare_enable(hdmi->iahb_clk);
-	if (ret)
-		return ret;
-
 	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
 		    HDMI_PHY_I2CM_INT_ADDR);
 
@@ -1470,8 +1464,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
-	clk_disable_unprepare(hdmi->iahb_clk);
-
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 14/46] imx-drm: imx-hdmi: get rid of clk manipulations in imx_hdmi_fb_registered()
@ 2014-01-02 21:26   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:26 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The clock manipulations do nothing for us: the clock is already enabled
by the only caller (imx_hdmi_platform_probe()).  Get rid of these and
simplify the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    8 --------
 1 files changed, 0 insertions(+), 8 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 267d3c9114c6..1eb12c57aa3e 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1448,12 +1448,6 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 /* Wait until we are registered to enable interrupts */
 static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
-	int ret;
-
-	ret = clk_prepare_enable(hdmi->iahb_clk);
-	if (ret)
-		return ret;
-
 	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
 		    HDMI_PHY_I2CM_INT_ADDR);
 
@@ -1470,8 +1464,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
-	clk_disable_unprepare(hdmi->iahb_clk);
-
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 15/46] imx-drm: imx-hdmi: minor cleanups
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Some minor cleanups to the HDMI driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 1eb12c57aa3e..ee0fceb7b5b2 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -19,7 +19,6 @@
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-
 #include <linux/of_device.h>
 
 #include <drm/drmP.h>
@@ -37,7 +36,7 @@
 #define YCBCR444		1
 #define YCBCR422_16BITS		2
 #define YCBCR422_8BITS		3
-#define	XVYCC444		4
+#define XVYCC444		4
 
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
@@ -1762,8 +1761,8 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
-	int ret, irq;
 	struct resource *iores;
+	int ret, irq;
 
 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
-- 
1.7.4.4

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

* [PATCH RFC 15/46] imx-drm: imx-hdmi: minor cleanups
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Some minor cleanups to the HDMI driver.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 1eb12c57aa3e..ee0fceb7b5b2 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -19,7 +19,6 @@
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
 #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-
 #include <linux/of_device.h>
 
 #include <drm/drmP.h>
@@ -37,7 +36,7 @@
 #define YCBCR444		1
 #define YCBCR422_16BITS		2
 #define YCBCR422_8BITS		3
-#define	XVYCC444		4
+#define XVYCC444		4
 
 enum hdmi_datamap {
 	RGB444_8B = 0x01,
@@ -1762,8 +1761,8 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
-	int ret, irq;
 	struct resource *iores;
+	int ret, irq;
 
 	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
-- 
1.7.4.4

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

* [PATCH RFC 16/46] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than having large if() and switch() statements, provide a table
to look up the register settings for various clock rates.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |  250 ++++++++++++++----------------------
 1 files changed, 95 insertions(+), 155 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ee0fceb7b5b2..5fda630a798d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -810,19 +810,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
+enum {
+	RES_8,
+	RES_10,
+	RES_12,
+	RES_MAX,
+};
+
+struct mpll_config {
+	unsigned long mpixelclock;
+	struct {
+		u16 cpce;
+		u16 gmp;
+	} res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+	{
+		45250000, {
+			{ 0x01e0, 0x0000 },
+			{ 0x21e1, 0x0000 },
+			{ 0x41e2, 0x0000 }
+		},
+	}, {
+		92500000, {
+			{ 0x0140, 0x0005 },
+			{ 0x2141, 0x0005 },
+			{ 0x4142, 0x0005 },
+		},
+	}, {
+		148500000, {
+			{ 0x00a0, 0x000a },
+			{ 0x20a1, 0x000a },
+			{ 0x40a2, 0x000a },
+		},
+	}, {
+		~0UL, {
+			{ 0x00a0, 0x000a },
+			{ 0x2001, 0x000f },
+			{ 0x4002, 0x000f },
+		},
+	}
+};
+
+struct curr_ctrl {
+	unsigned long mpixelclock;
+	u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+	/*	pixelclk     bpp8    bpp10   bpp12 */
+	{
+		 54000000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		 58400000, { 0x091c, 0x06dc, 0x06dc },
+	}, {
+		 72000000, { 0x06dc, 0x06dc, 0x091c },
+	}, {
+		 74250000, { 0x06dc, 0x0b5c, 0x091c },
+	}, {
+		118800000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		216000000, { 0x06dc, 0x0b5c, 0x091c },
+	}
+};
+
 static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 			      unsigned char res, int cscon)
 {
+	unsigned res_idx, i;
 	u8 val, msec;
 
-	/* color resolution 0 is 8 bit colour depth */
-	if (!res)
-		res = 8;
-
 	if (prep)
 		return -EINVAL;
-	else if (res != 8 && res != 12)
+
+	switch (res) {
+	case 0:	/* color resolution 0 is 8 bit colour depth */
+	case 8:
+		res_idx = RES_8;
+		break;
+	case 10:
+		res_idx = RES_10;
+		break;
+	case 12:
+		res_idx = RES_12;
+		break;
+	default:
 		return -EINVAL;
+	}
 
 	/* Enable csc path */
 	if (cscon)
@@ -849,165 +924,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 			HDMI_PHY_I2CM_SLAVE_ADDR);
 	hdmi_phy_test_clear(hdmi, 0);
 
-	if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
-		switch (res) {
-		case 8:
-			/* PLL/MPLL Cfg */
-			hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);  /* GMPCTRL */
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-		default:
-			return -EINVAL;
-		}
-	} else {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+	/* PLL/MPLL Cfg - always match on final entry */
+	for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    mpll_config[i].mpixelclock)
 			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
-		default:
-			return -EINVAL;
-		}
-	}
 
-	if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);  /* CURRCTRL */
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+	for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    curr_ctrl[i].mpixelclock)
 			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
+
+	if (i >= ARRAY_SIZE(curr_ctrl)) {
 		dev_err(hdmi->dev,
 				"Pixel clock %d - unsupported by HDMI\n",
 				hdmi->hdmi_data.video_mode.mpixelclock);
 		return -EINVAL;
 	}
 
+	/* CURRCTRL */
+	hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
 	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
 	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
 	/* RESISTANCE TERM 133Ohm Cfg */
-- 
1.7.4.4

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

* [PATCH RFC 16/46] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Rather than having large if() and switch() statements, provide a table
to look up the register settings for various clock rates.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |  250 ++++++++++++++----------------------
 1 files changed, 95 insertions(+), 155 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index ee0fceb7b5b2..5fda630a798d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -810,19 +810,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
 			 HDMI_PHY_CONF0_SELDIPIF_MASK);
 }
 
+enum {
+	RES_8,
+	RES_10,
+	RES_12,
+	RES_MAX,
+};
+
+struct mpll_config {
+	unsigned long mpixelclock;
+	struct {
+		u16 cpce;
+		u16 gmp;
+	} res[RES_MAX];
+};
+
+static const struct mpll_config mpll_config[] = {
+	{
+		45250000, {
+			{ 0x01e0, 0x0000 },
+			{ 0x21e1, 0x0000 },
+			{ 0x41e2, 0x0000 }
+		},
+	}, {
+		92500000, {
+			{ 0x0140, 0x0005 },
+			{ 0x2141, 0x0005 },
+			{ 0x4142, 0x0005 },
+		},
+	}, {
+		148500000, {
+			{ 0x00a0, 0x000a },
+			{ 0x20a1, 0x000a },
+			{ 0x40a2, 0x000a },
+		},
+	}, {
+		~0UL, {
+			{ 0x00a0, 0x000a },
+			{ 0x2001, 0x000f },
+			{ 0x4002, 0x000f },
+		},
+	}
+};
+
+struct curr_ctrl {
+	unsigned long mpixelclock;
+	u16 curr[RES_MAX];
+};
+
+static const struct curr_ctrl curr_ctrl[] = {
+	/*	pixelclk     bpp8    bpp10   bpp12 */
+	{
+		 54000000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		 58400000, { 0x091c, 0x06dc, 0x06dc },
+	}, {
+		 72000000, { 0x06dc, 0x06dc, 0x091c },
+	}, {
+		 74250000, { 0x06dc, 0x0b5c, 0x091c },
+	}, {
+		118800000, { 0x091c, 0x091c, 0x06dc },
+	}, {
+		216000000, { 0x06dc, 0x0b5c, 0x091c },
+	}
+};
+
 static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 			      unsigned char res, int cscon)
 {
+	unsigned res_idx, i;
 	u8 val, msec;
 
-	/* color resolution 0 is 8 bit colour depth */
-	if (!res)
-		res = 8;
-
 	if (prep)
 		return -EINVAL;
-	else if (res != 8 && res != 12)
+
+	switch (res) {
+	case 0:	/* color resolution 0 is 8 bit colour depth */
+	case 8:
+		res_idx = RES_8;
+		break;
+	case 10:
+		res_idx = RES_10;
+		break;
+	case 12:
+		res_idx = RES_12;
+		break;
+	default:
 		return -EINVAL;
+	}
 
 	/* Enable csc path */
 	if (cscon)
@@ -849,165 +924,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
 			HDMI_PHY_I2CM_SLAVE_ADDR);
 	hdmi_phy_test_clear(hdmi, 0);
 
-	if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
-		switch (res) {
-		case 8:
-			/* PLL/MPLL Cfg */
-			hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);  /* GMPCTRL */
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-		default:
-			return -EINVAL;
-		}
-	} else {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+	/* PLL/MPLL Cfg - always match on final entry */
+	for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    mpll_config[i].mpixelclock)
 			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
-			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
-		default:
-			return -EINVAL;
-		}
-	}
 
-	if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);  /* CURRCTRL */
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		default:
-			return -EINVAL;
-		}
-	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
-		switch (res) {
-		case 8:
-			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
-			break;
-		case 10:
-			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
-			break;
-		case 12:
-			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+	hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+	for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
+		if (hdmi->hdmi_data.video_mode.mpixelclock <=
+		    curr_ctrl[i].mpixelclock)
 			break;
-		default:
-			return -EINVAL;
-		}
-	} else {
+
+	if (i >= ARRAY_SIZE(curr_ctrl)) {
 		dev_err(hdmi->dev,
 				"Pixel clock %d - unsupported by HDMI\n",
 				hdmi->hdmi_data.video_mode.mpixelclock);
 		return -EINVAL;
 	}
 
+	/* CURRCTRL */
+	hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
 	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
 	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
 	/* RESISTANCE TERM 133Ohm Cfg */
-- 
1.7.4.4

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

* [PATCH RFC 17/46] imx-drm: imx-hdmi: clean up setting CSC registers
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than manually writing each register sequentially, we can use a
loop to reduce the amount of code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   40 ++++++++++++-----------------------
 1 files changed, 14 insertions(+), 26 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 5fda630a798d..dc46d2acd9c5 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -484,6 +484,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
 static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 {
 	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+	unsigned i;
 	u32 csc_scale = 1;
 	u8 val;
 
@@ -502,32 +503,19 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 		}
 	}
 
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
-
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
-
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
+	/* The CSC registers are sequential, alternating MSB then LSB */
+	for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+		u16 coeff_a = (*csc_coeff)[0][i];
+		u16 coeff_b = (*csc_coeff)[1][i];
+		u16 coeff_c = (*csc_coeff)[2][i];
+
+		hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+	}
 
 	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
 	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
-- 
1.7.4.4

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

* [PATCH RFC 17/46] imx-drm: imx-hdmi: clean up setting CSC registers
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Rather than manually writing each register sequentially, we can use a
loop to reduce the amount of code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   40 ++++++++++++-----------------------
 1 files changed, 14 insertions(+), 26 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 5fda630a798d..dc46d2acd9c5 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -484,6 +484,7 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi)
 static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 {
 	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+	unsigned i;
 	u32 csc_scale = 1;
 	u8 val;
 
@@ -502,32 +503,19 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 		}
 	}
 
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
-
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
-
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
-	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
+	/* The CSC registers are sequential, alternating MSB then LSB */
+	for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+		u16 coeff_a = (*csc_coeff)[0][i];
+		u16 coeff_b = (*csc_coeff)[1][i];
+		u16 coeff_c = (*csc_coeff)[2][i];
+
+		hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
+		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+	}
 
 	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
 	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
-- 
1.7.4.4

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

* [PATCH RFC 18/46] imx-drm: imx-hdmi: provide register modification function
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

There are a load of read-modify-write patterns to change bitfields in
various registers in this driver; provide a helper to perform this
manipulation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |  188 +++++++++++++-----------------------
 1 files changed, 68 insertions(+), 120 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index dc46d2acd9c5..f8c652e58a6d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -160,37 +160,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
 	return readb(hdmi->regs + offset);
 }
 
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+	u8 val = hdmi_readb(hdmi, reg) & ~mask;
+	val |= data & mask;
+	hdmi_writeb(hdmi, val, reg);
+}
+
 static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
 		      u8 shift, u8 mask)
 {
-	u8 value = hdmi_readb(hdmi, reg) & ~mask;
-	value |= (data << shift) & mask;
-	hdmi_writeb(hdmi, value, reg);
+	hdmi_modb(hdmi, data << shift, mask, reg);
 }
 
 static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
 					 unsigned int value)
 {
-	u8 val;
-
 	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
 	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
 	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
 
 	/* nshift factor = 0 */
-	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
-	val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
-	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
 }
 
 static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
 {
-	u8 val;
-
 	/* Must be set/cleared first */
-	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
-	val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
-	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
 
 	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
 	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
@@ -486,7 +483,6 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
 	unsigned i;
 	u32 csc_scale = 1;
-	u8 val;
 
 	if (is_color_space_conversion(hdmi)) {
 		if (hdmi->hdmi_data.enc_out_format == RGB) {
@@ -517,10 +513,8 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
 	}
 
-	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
-	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
-	val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
-	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+	hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+		  HDMI_CSC_SCALE);
 }
 
 static void hdmi_video_csc(struct imx_hdmi *hdmi)
@@ -528,7 +522,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
 	int color_depth = 0;
 	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
 	int decimation = 0;
-	u8 val;
 
 	/* YCC422 interpolation to 444 mode */
 	if (is_color_space_interpolation(hdmi))
@@ -549,10 +542,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
 
 	/* Configure the CSC registers */
 	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
-	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
-	val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
-	val |= color_depth;
-	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+	hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+		  HDMI_CSC_SCALE);
 
 	imx_hdmi_update_csc_coeffs(hdmi);
 }
@@ -607,107 +598,80 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
 	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
-	val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
 
 	/* Data from pixel repeater block */
 	if (hdmi_data->pix_repet_factor > 1) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
-			HDMI_VP_CONF_BYPASS_SELECT_MASK);
-		val |= HDMI_VP_CONF_PR_EN_ENABLE |
-			HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
+				HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
+			  HDMI_VP_CONF_PR_EN_MASK |
+			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
 	} else { /* data from packetizer block */
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
-			HDMI_VP_CONF_BYPASS_SELECT_MASK);
-		val |= HDMI_VP_CONF_PR_EN_DISABLE |
-			HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
+				HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
+			  HDMI_VP_CONF_PR_EN_MASK |
+			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
 	}
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
-	val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
 
 	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
 
 	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			HDMI_VP_CONF_PP_EN_ENABLE |
-			HDMI_VP_CONF_YCC422_EN_DISABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+				HDMI_VP_CONF_PP_EN_ENABLE |
+				HDMI_VP_CONF_YCC422_EN_DISABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			HDMI_VP_CONF_PP_EN_DISABLE |
-			HDMI_VP_CONF_YCC422_EN_ENABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+				HDMI_VP_CONF_PP_EN_DISABLE |
+				HDMI_VP_CONF_YCC422_EN_ENABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
-			HDMI_VP_CONF_PP_EN_DISABLE |
-			HDMI_VP_CONF_YCC422_EN_DISABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
+				HDMI_VP_CONF_PP_EN_DISABLE |
+				HDMI_VP_CONF_YCC422_EN_DISABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else {
 		return;
 	}
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
-		HDMI_VP_STUFF_YCC422_STUFFING_MASK);
-	val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
-		HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PP_STUFFING_MASK |
+		  HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
 
-	val = hdmi_readb(hdmi, HDMI_VP_CONF);
-	val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
-	val |= output_select;
-	hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+		  HDMI_VP_CONF);
 }
 
 static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
-		HDMI_PHY_TST0_TSTCLR_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+		  HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTEN_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
-		HDMI_PHY_TST0_TSTEN_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+		  HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
-		HDMI_PHY_TST0_TSTCLK_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+		  HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
@@ -1004,7 +968,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
 
 static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
 {
-	u8 de, val;
+	u8 de;
 
 	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
 		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
@@ -1012,20 +976,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
 		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
 
 	/* disable rx detect */
-	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
-	val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
-	val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
-	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+		  HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
 
-	val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
-	val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
-	val |= de;
-	hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+	hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
 
-	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
-	val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
-	val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
-	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+		  HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
 }
 
 static void hdmi_config_AVI(struct imx_hdmi *hdmi)
@@ -1249,11 +1206,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
 
 static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
 {
-	u8 clkdis;
-
-	clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
-	clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
 }
 
 /* Workaround to clear the overflow condition */
@@ -1597,7 +1550,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	struct imx_hdmi *hdmi = dev_id;
 	u8 intr_stat;
 	u8 phy_int_pol;
-	u8 val;
 
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
 
@@ -1607,17 +1559,13 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 		if (phy_int_pol & HDMI_PHY_HPD) {
 			dev_dbg(hdmi->dev, "EVENT=plugin\n");
 
-			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
-			val &= ~HDMI_PHY_HPD;
-			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
-			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
-			val |= HDMI_PHY_HPD;
-			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
 			imx_hdmi_poweroff(hdmi);
 		}
-- 
1.7.4.4

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

* [PATCH RFC 18/46] imx-drm: imx-hdmi: provide register modification function
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

There are a load of read-modify-write patterns to change bitfields in
various registers in this driver; provide a helper to perform this
manipulation.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |  188 +++++++++++++-----------------------
 1 files changed, 68 insertions(+), 120 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index dc46d2acd9c5..f8c652e58a6d 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -160,37 +160,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
 	return readb(hdmi->regs + offset);
 }
 
+static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+	u8 val = hdmi_readb(hdmi, reg) & ~mask;
+	val |= data & mask;
+	hdmi_writeb(hdmi, val, reg);
+}
+
 static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
 		      u8 shift, u8 mask)
 {
-	u8 value = hdmi_readb(hdmi, reg) & ~mask;
-	value |= (data << shift) & mask;
-	hdmi_writeb(hdmi, value, reg);
+	hdmi_modb(hdmi, data << shift, mask, reg);
 }
 
 static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
 					 unsigned int value)
 {
-	u8 val;
-
 	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
 	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
 	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
 
 	/* nshift factor = 0 */
-	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
-	val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
-	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
 }
 
 static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
 {
-	u8 val;
-
 	/* Must be set/cleared first */
-	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
-	val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
-	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+	hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
 
 	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
 	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
@@ -486,7 +483,6 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
 	unsigned i;
 	u32 csc_scale = 1;
-	u8 val;
 
 	if (is_color_space_conversion(hdmi)) {
 		if (hdmi->hdmi_data.enc_out_format == RGB) {
@@ -517,10 +513,8 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
 		hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
 	}
 
-	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
-	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
-	val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
-	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+	hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+		  HDMI_CSC_SCALE);
 }
 
 static void hdmi_video_csc(struct imx_hdmi *hdmi)
@@ -528,7 +522,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
 	int color_depth = 0;
 	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
 	int decimation = 0;
-	u8 val;
 
 	/* YCC422 interpolation to 444 mode */
 	if (is_color_space_interpolation(hdmi))
@@ -549,10 +542,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi)
 
 	/* Configure the CSC registers */
 	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
-	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
-	val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
-	val |= color_depth;
-	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+	hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+		  HDMI_CSC_SCALE);
 
 	imx_hdmi_update_csc_coeffs(hdmi);
 }
@@ -607,107 +598,80 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
 	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
-	val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
 
 	/* Data from pixel repeater block */
 	if (hdmi_data->pix_repet_factor > 1) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
-			HDMI_VP_CONF_BYPASS_SELECT_MASK);
-		val |= HDMI_VP_CONF_PR_EN_ENABLE |
-			HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
+				HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
+			  HDMI_VP_CONF_PR_EN_MASK |
+			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
 	} else { /* data from packetizer block */
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
-			HDMI_VP_CONF_BYPASS_SELECT_MASK);
-		val |= HDMI_VP_CONF_PR_EN_DISABLE |
-			HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
+				HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
+			  HDMI_VP_CONF_PR_EN_MASK |
+			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
 	}
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
-	val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
 
 	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
 
 	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			HDMI_VP_CONF_PP_EN_ENABLE |
-			HDMI_VP_CONF_YCC422_EN_DISABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+				HDMI_VP_CONF_PP_EN_ENABLE |
+				HDMI_VP_CONF_YCC422_EN_DISABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
-			HDMI_VP_CONF_PP_EN_DISABLE |
-			HDMI_VP_CONF_YCC422_EN_ENABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
+				HDMI_VP_CONF_PP_EN_DISABLE |
+				HDMI_VP_CONF_YCC422_EN_ENABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-		val = hdmi_readb(hdmi, HDMI_VP_CONF);
-		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
-			HDMI_VP_CONF_PP_EN_ENMASK |
-			HDMI_VP_CONF_YCC422_EN_MASK);
-		val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
-			HDMI_VP_CONF_PP_EN_DISABLE |
-			HDMI_VP_CONF_YCC422_EN_DISABLE;
-		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
+				HDMI_VP_CONF_PP_EN_DISABLE |
+				HDMI_VP_CONF_YCC422_EN_DISABLE,
+			  HDMI_VP_CONF_BYPASS_EN_MASK |
+			  HDMI_VP_CONF_PP_EN_ENMASK |
+			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
 	} else {
 		return;
 	}
 
-	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
-	val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
-		HDMI_VP_STUFF_YCC422_STUFFING_MASK);
-	val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
-		HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
-	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+		  HDMI_VP_STUFF_PP_STUFFING_MASK |
+		  HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
 
-	val = hdmi_readb(hdmi, HDMI_VP_CONF);
-	val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
-	val |= output_select;
-	hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+		  HDMI_VP_CONF);
 }
 
 static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
-		HDMI_PHY_TST0_TSTCLR_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+		  HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTEN_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
-		HDMI_PHY_TST0_TSTEN_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+		  HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
 						unsigned char bit)
 {
-	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
-	val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
-	val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
-		HDMI_PHY_TST0_TSTCLK_MASK;
-	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+	hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+		  HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
 }
 
 static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
@@ -1004,7 +968,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
 
 static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
 {
-	u8 de, val;
+	u8 de;
 
 	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
 		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
@@ -1012,20 +976,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
 		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
 
 	/* disable rx detect */
-	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
-	val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
-	val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
-	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+		  HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
 
-	val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
-	val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
-	val |= de;
-	hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+	hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
 
-	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
-	val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
-	val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
-	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+	hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+		  HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
 }
 
 static void hdmi_config_AVI(struct imx_hdmi *hdmi)
@@ -1249,11 +1206,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
 
 static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
 {
-	u8 clkdis;
-
-	clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
-	clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
 }
 
 /* Workaround to clear the overflow condition */
@@ -1597,7 +1550,6 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	struct imx_hdmi *hdmi = dev_id;
 	u8 intr_stat;
 	u8 phy_int_pol;
-	u8 val;
 
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
 
@@ -1607,17 +1559,13 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 		if (phy_int_pol & HDMI_PHY_HPD) {
 			dev_dbg(hdmi->dev, "EVENT=plugin\n");
 
-			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
-			val &= ~HDMI_PHY_HPD;
-			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
-			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
-			val |= HDMI_PHY_HPD;
-			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
 			imx_hdmi_poweroff(hdmi);
 		}
-- 
1.7.4.4

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

* [PATCH RFC 19/46] imx-drm: imx-hdmi: clean up setting of vp_conf
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   49 ++++++++++++++++-------------------
 1 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index f8c652e58a6d..075dd1f0c8a7 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -559,7 +559,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
 	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
 	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
-	u8 val;
+	u8 val, vp_conf;
 
 	if (hdmi_data->enc_out_format == RGB
 		|| hdmi_data->enc_out_format == YCBCR444) {
@@ -603,47 +603,42 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 
 	/* Data from pixel repeater block */
 	if (hdmi_data->pix_repet_factor > 1) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
-				HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
-			  HDMI_VP_CONF_PR_EN_MASK |
-			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
 	} else { /* data from packetizer block */
-		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
-				HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
-			  HDMI_VP_CONF_PR_EN_MASK |
-			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
 	}
 
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_PR_EN_MASK |
+		  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
 	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
 		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
 
 	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
 
 	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
-				HDMI_VP_CONF_PP_EN_ENABLE |
-				HDMI_VP_CONF_YCC422_EN_DISABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_ENABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
-				HDMI_VP_CONF_PP_EN_DISABLE |
-				HDMI_VP_CONF_YCC422_EN_ENABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_ENABLE;
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
-				HDMI_VP_CONF_PP_EN_DISABLE |
-				HDMI_VP_CONF_YCC422_EN_DISABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
 	} else {
 		return;
 	}
 
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+		  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
 	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
 			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
 		  HDMI_VP_STUFF_PP_STUFFING_MASK |
-- 
1.7.4.4

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

* [PATCH RFC 19/46] imx-drm: imx-hdmi: clean up setting of vp_conf
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   49 ++++++++++++++++-------------------
 1 files changed, 22 insertions(+), 27 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index f8c652e58a6d..075dd1f0c8a7 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -559,7 +559,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
 	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
 	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
-	u8 val;
+	u8 val, vp_conf;
 
 	if (hdmi_data->enc_out_format == RGB
 		|| hdmi_data->enc_out_format == YCBCR444) {
@@ -603,47 +603,42 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi)
 
 	/* Data from pixel repeater block */
 	if (hdmi_data->pix_repet_factor > 1) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_ENABLE |
-				HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER,
-			  HDMI_VP_CONF_PR_EN_MASK |
-			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
 	} else { /* data from packetizer block */
-		hdmi_modb(hdmi, HDMI_VP_CONF_PR_EN_DISABLE |
-				HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER,
-			  HDMI_VP_CONF_PR_EN_MASK |
-			  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+			  HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
 	}
 
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_PR_EN_MASK |
+		  HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
 	hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
 		  HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
 
 	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
 
 	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
-				HDMI_VP_CONF_PP_EN_ENABLE |
-				HDMI_VP_CONF_YCC422_EN_DISABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_ENABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_DISABLE |
-				HDMI_VP_CONF_PP_EN_DISABLE |
-				HDMI_VP_CONF_YCC422_EN_ENABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_ENABLE;
 	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
-		hdmi_modb(hdmi, HDMI_VP_CONF_BYPASS_EN_ENABLE |
-				HDMI_VP_CONF_PP_EN_DISABLE |
-				HDMI_VP_CONF_YCC422_EN_DISABLE,
-			  HDMI_VP_CONF_BYPASS_EN_MASK |
-			  HDMI_VP_CONF_PP_EN_ENMASK |
-			  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+		vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+			  HDMI_VP_CONF_PP_EN_DISABLE |
+			  HDMI_VP_CONF_YCC422_EN_DISABLE;
 	} else {
 		return;
 	}
 
+	hdmi_modb(hdmi, vp_conf,
+		  HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+		  HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
 	hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
 			HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
 		  HDMI_VP_STUFF_PP_STUFFING_MASK |
-- 
1.7.4.4

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

* [PATCH RFC 20/46] imx-drm: imx-hdmi: fix CTS/N setup at init time
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Many of the variables for the audio clock regenerator (CTS/N) were not
initialised in any way.  The pixel rate which was being used also
wasn't being adjusted at all when the display mode is modified.

Get rid of the seaprate 'pixel_clk_rate', and use the stored pixel
clock rate instead.  Pass this desired pixel clock rate into
hdmi_set_clk_regenerator().  Collapse down hdmi_init_clk_regenerator()
since it is a copy of hdmi_set_clk_regenerator(), and pass a default
pixel clock rate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   48 +++++++----------------------------
 1 files changed, 10 insertions(+), 38 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 075dd1f0c8a7..2eb51e7ea9bb 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -138,7 +138,6 @@ struct imx_hdmi {
 	struct i2c_adapter *ddc;
 	void __iomem *regs;
 
-	unsigned long pixel_clk_rate;
 	unsigned int sample_rate;
 	int ratio;
 };
@@ -332,34 +331,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
 		return (cts * ratio) / 100;
 }
 
-static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
-{
-	unsigned long rate;
-
-	rate = 65000000; /* FIXME */
-
-	if (rate)
-		hdmi->pixel_clk_rate = rate;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+	unsigned long pixel_clk)
 {
 	unsigned int clk_n, clk_cts;
 
-	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+	clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
 			       hdmi->ratio);
-	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
 				   hdmi->ratio);
 
 	if (!clk_cts) {
 		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-			 __func__, hdmi->pixel_clk_rate);
+			 __func__, pixel_clk);
 		return;
 	}
 
 	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
 		__func__, hdmi->sample_rate, hdmi->ratio,
-		hdmi->pixel_clk_rate, clk_n, clk_cts);
+		pixel_clk, clk_n, clk_cts);
 
 	hdmi_set_clock_regenerator_n(hdmi, clk_n);
 	hdmi_regenerate_cts(hdmi, clk_cts);
@@ -367,32 +357,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
 
 static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
 {
-	unsigned int clk_n, clk_cts;
-
-	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
-			       hdmi->ratio);
-	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
-				   hdmi->ratio);
-
-	if (!clk_cts) {
-		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-			 __func__, hdmi->pixel_clk_rate);
-		return;
-	}
-
-	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
-		__func__, hdmi->sample_rate, hdmi->ratio,
-		hdmi->pixel_clk_rate, clk_n, clk_cts);
-
-	hdmi_set_clock_regenerator_n(hdmi, clk_n);
-	hdmi_regenerate_cts(hdmi, clk_cts);
+	hdmi_set_clk_regenerator(hdmi, 74250000);
 }
 
 static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
 {
-	/* Get pixel clock from ipu */
-	hdmi_get_pixel_clk(hdmi);
-	hdmi_set_clk_regenerator(hdmi);
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
 }
 
 /*
@@ -1640,6 +1610,8 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	hdmi->dev = &pdev->dev;
+	hdmi->sample_rate = 48000;
+	hdmi->ratio = 100;
 
 	if (of_id) {
 		const struct platform_device_id *device_id = of_id->data;
-- 
1.7.4.4

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

* [PATCH RFC 20/46] imx-drm: imx-hdmi: fix CTS/N setup at init time
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Many of the variables for the audio clock regenerator (CTS/N) were not
initialised in any way.  The pixel rate which was being used also
wasn't being adjusted at all when the display mode is modified.

Get rid of the seaprate 'pixel_clk_rate', and use the stored pixel
clock rate instead.  Pass this desired pixel clock rate into
hdmi_set_clk_regenerator().  Collapse down hdmi_init_clk_regenerator()
since it is a copy of hdmi_set_clk_regenerator(), and pass a default
pixel clock rate.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   48 +++++++----------------------------
 1 files changed, 10 insertions(+), 38 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 075dd1f0c8a7..2eb51e7ea9bb 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -138,7 +138,6 @@ struct imx_hdmi {
 	struct i2c_adapter *ddc;
 	void __iomem *regs;
 
-	unsigned long pixel_clk_rate;
 	unsigned int sample_rate;
 	int ratio;
 };
@@ -332,34 +331,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
 		return (cts * ratio) / 100;
 }
 
-static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
-{
-	unsigned long rate;
-
-	rate = 65000000; /* FIXME */
-
-	if (rate)
-		hdmi->pixel_clk_rate = rate;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
+	unsigned long pixel_clk)
 {
 	unsigned int clk_n, clk_cts;
 
-	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+	clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
 			       hdmi->ratio);
-	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
 				   hdmi->ratio);
 
 	if (!clk_cts) {
 		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-			 __func__, hdmi->pixel_clk_rate);
+			 __func__, pixel_clk);
 		return;
 	}
 
 	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
 		__func__, hdmi->sample_rate, hdmi->ratio,
-		hdmi->pixel_clk_rate, clk_n, clk_cts);
+		pixel_clk, clk_n, clk_cts);
 
 	hdmi_set_clock_regenerator_n(hdmi, clk_n);
 	hdmi_regenerate_cts(hdmi, clk_cts);
@@ -367,32 +357,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
 
 static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
 {
-	unsigned int clk_n, clk_cts;
-
-	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
-			       hdmi->ratio);
-	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
-				   hdmi->ratio);
-
-	if (!clk_cts) {
-		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
-			 __func__, hdmi->pixel_clk_rate);
-		return;
-	}
-
-	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
-		__func__, hdmi->sample_rate, hdmi->ratio,
-		hdmi->pixel_clk_rate, clk_n, clk_cts);
-
-	hdmi_set_clock_regenerator_n(hdmi, clk_n);
-	hdmi_regenerate_cts(hdmi, clk_cts);
+	hdmi_set_clk_regenerator(hdmi, 74250000);
 }
 
 static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
 {
-	/* Get pixel clock from ipu */
-	hdmi_get_pixel_clk(hdmi);
-	hdmi_set_clk_regenerator(hdmi);
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
 }
 
 /*
@@ -1640,6 +1610,8 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	hdmi->dev = &pdev->dev;
+	hdmi->sample_rate = 48000;
+	hdmi->ratio = 100;
 
 	if (of_id) {
 		const struct platform_device_id *device_id = of_id->data;
-- 
1.7.4.4

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

The encoder possible_crtcs mask identifies which CRTCs can be bound to
a particular encoder.  Each bit from bit 0 defines an index in the list
of CRTCs held in the DRM mode_config crtc_list.  Rather than having
drivers trying to track the position of their CRTCs in the list, expose
the code which already exists for calculating the appropriate mask bit
for a CRTC.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
 include/drm/drm_crtc_helper.h     |    1 +
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 01361aba033b..10708c248196 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 
 /**
+ * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
+ * @crtc: crtc to find mask for
+ *
+ * Given a registered CRTC, return the mask bit of that CRTC for an
+ * encoder's possible_crtcs field.
+ */
+uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_crtc *tmp;
+	uint32_t crtc_mask = 1;
+
+	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
+		if (tmp == crtc)
+			return crtc_mask;
+		crtc_mask <<= 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_helper_crtc_possible_mask);
+
+/**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  * @encoder: encoder to test
  * @crtc: crtc to test
@@ -334,23 +357,13 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
 				struct drm_crtc *crtc)
 {
-	struct drm_device *dev;
-	struct drm_crtc *tmp;
-	int crtc_mask = 1;
+	uint32_t crtc_mask;
 
 	WARN(!crtc, "checking null crtc?\n");
 
-	dev = crtc->dev;
-
-	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
-		if (tmp == crtc)
-			break;
-		crtc_mask <<= 1;
-	}
+	crtc_mask = drm_helper_crtc_possible_mask(crtc);
 
-	if (encoder->possible_crtcs & crtc_mask)
-		return true;
-	return false;
+	return !!(encoder->possible_crtcs & crtc_mask);
 }
 
 /*
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index ef6ad3a8e58e..21b9f47dd88c 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -127,6 +127,7 @@ struct drm_connector_helper_funcs {
 
 extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
+extern uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 				     struct drm_display_mode *mode,
-- 
1.7.4.4

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The encoder possible_crtcs mask identifies which CRTCs can be bound to
a particular encoder.  Each bit from bit 0 defines an index in the list
of CRTCs held in the DRM mode_config crtc_list.  Rather than having
drivers trying to track the position of their CRTCs in the list, expose
the code which already exists for calculating the appropriate mask bit
for a CRTC.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
 include/drm/drm_crtc_helper.h     |    1 +
 2 files changed, 27 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 01361aba033b..10708c248196 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 
 /**
+ * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
+ * @crtc: crtc to find mask for
+ *
+ * Given a registered CRTC, return the mask bit of that CRTC for an
+ * encoder's possible_crtcs field.
+ */
+uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_crtc *tmp;
+	uint32_t crtc_mask = 1;
+
+	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
+		if (tmp == crtc)
+			return crtc_mask;
+		crtc_mask <<= 1;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(drm_helper_crtc_possible_mask);
+
+/**
  * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
  * @encoder: encoder to test
  * @crtc: crtc to test
@@ -334,23 +357,13 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
 				struct drm_crtc *crtc)
 {
-	struct drm_device *dev;
-	struct drm_crtc *tmp;
-	int crtc_mask = 1;
+	uint32_t crtc_mask;
 
 	WARN(!crtc, "checking null crtc?\n");
 
-	dev = crtc->dev;
-
-	list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
-		if (tmp == crtc)
-			break;
-		crtc_mask <<= 1;
-	}
+	crtc_mask = drm_helper_crtc_possible_mask(crtc);
 
-	if (encoder->possible_crtcs & crtc_mask)
-		return true;
-	return false;
+	return !!(encoder->possible_crtcs & crtc_mask);
 }
 
 /*
diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index ef6ad3a8e58e..21b9f47dd88c 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -127,6 +127,7 @@ struct drm_connector_helper_funcs {
 
 extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
 extern void drm_helper_disable_unused_functions(struct drm_device *dev);
+extern uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc);
 extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
 extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
 				     struct drm_display_mode *mode,
-- 
1.7.4.4

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

* [PATCH RFC 22/46] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id()
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Address the following issues:
- imx_drm_encoder_get_mux_id() searches the CRTC list for the matching
  CRTC, and returns the position within this list as the MUX programming
  value for encoders.  This is sub-optimal for two reasons:
  1. It relies upon the CRTC list not changing during the lifetime of
     the driver.
  2. It is dependent on the initialisation order of the CRTCs.

  We address (1) in this patch, leaving (2) until a better solution can
  be found, as (2) requires larger changes.

- imx_drm_encoder is unused.  Instead, pass the drm_encoder which is
  slightly more useful; all callers pass encoder->crtc as the required
  crtc, so move this inside the function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   17 ++++++-----------
 drivers/staging/imx-drm/imx-drm.h      |    3 +--
 drivers/staging/imx-drm/imx-hdmi.c     |    3 +--
 drivers/staging/imx-drm/imx-ldb.c      |    6 ++----
 4 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 05dd24ee80dd..a402df0f3005 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -53,6 +53,7 @@ struct imx_drm_crtc {
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	struct module				*owner;
 	struct crtc_cookie			cookie;
+	int					mux_id;
 };
 
 struct imx_drm_encoder {
@@ -502,7 +503,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	imx_drm_crtc->pipe = imxdrm->pipes++;
 	imx_drm_crtc->cookie.cookie = cookie;
 	imx_drm_crtc->cookie.id = id;
-
+	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
 	imx_drm_crtc->imxdrm = imxdrm;
 
@@ -656,22 +657,16 @@ int imx_drm_encoder_add_possible_crtcs(
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
 
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
-		struct drm_crtc *crtc)
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_crtc *imx_crtc;
-	int i = 0;
 
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
-		if (imx_crtc->crtc == crtc)
-			goto found;
-		i++;
-	}
+	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+		if (imx_crtc->crtc == encoder->crtc)
+			return imx_crtc->mux_id;
 
 	return -EINVAL;
-found:
-	return i;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c15312..5649f180dc44 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,8 +64,7 @@ void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
 struct device_node;
 
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
-		struct drm_crtc *crtc);
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 2eb51e7ea9bb..c8152043143f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1471,8 +1471,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
 static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
 {
 	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-	int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	imx_hdmi_set_ipu_di_mux(hdmi, mux);
 
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 654bf03e05ff..bbcbd52f0169 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -180,8 +180,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 	u32 pixel_fmt;
 	unsigned long serial_clk;
 	unsigned long di_clk = mode->clock * 1000;
-	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
 		/* dual channel LVDS mode */
@@ -217,8 +216,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
 	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
-	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	if (dual) {
 		clk_prepare_enable(ldb->clk[0]);
-- 
1.7.4.4

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

* [PATCH RFC 22/46] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id()
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Address the following issues:
- imx_drm_encoder_get_mux_id() searches the CRTC list for the matching
  CRTC, and returns the position within this list as the MUX programming
  value for encoders.  This is sub-optimal for two reasons:
  1. It relies upon the CRTC list not changing during the lifetime of
     the driver.
  2. It is dependent on the initialisation order of the CRTCs.

  We address (1) in this patch, leaving (2) until a better solution can
  be found, as (2) requires larger changes.

- imx_drm_encoder is unused.  Instead, pass the drm_encoder which is
  slightly more useful; all callers pass encoder->crtc as the required
  crtc, so move this inside the function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   17 ++++++-----------
 drivers/staging/imx-drm/imx-drm.h      |    3 +--
 drivers/staging/imx-drm/imx-hdmi.c     |    3 +--
 drivers/staging/imx-drm/imx-ldb.c      |    6 ++----
 4 files changed, 10 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 05dd24ee80dd..a402df0f3005 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -53,6 +53,7 @@ struct imx_drm_crtc {
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	struct module				*owner;
 	struct crtc_cookie			cookie;
+	int					mux_id;
 };
 
 struct imx_drm_encoder {
@@ -502,7 +503,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	imx_drm_crtc->pipe = imxdrm->pipes++;
 	imx_drm_crtc->cookie.cookie = cookie;
 	imx_drm_crtc->cookie.id = id;
-
+	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
 	imx_drm_crtc->imxdrm = imxdrm;
 
@@ -656,22 +657,16 @@ int imx_drm_encoder_add_possible_crtcs(
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
 
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
-		struct drm_crtc *crtc)
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_crtc *imx_crtc;
-	int i = 0;
 
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
-		if (imx_crtc->crtc == crtc)
-			goto found;
-		i++;
-	}
+	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
+		if (imx_crtc->crtc == encoder->crtc)
+			return imx_crtc->mux_id;
 
 	return -EINVAL;
-found:
-	return i;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index ae90c9c15312..5649f180dc44 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,8 +64,7 @@ void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
 struct device_node;
 
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
-		struct drm_crtc *crtc);
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 2eb51e7ea9bb..c8152043143f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1471,8 +1471,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
 static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
 {
 	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-	int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	imx_hdmi_set_ipu_di_mux(hdmi, mux);
 
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 654bf03e05ff..bbcbd52f0169 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -180,8 +180,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 	u32 pixel_fmt;
 	unsigned long serial_clk;
 	unsigned long di_clk = mode->clock * 1000;
-	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
 		/* dual channel LVDS mode */
@@ -217,8 +216,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
 	struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
 	int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN;
-	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder,
-					     encoder->crtc);
+	int mux = imx_drm_encoder_get_mux_id(encoder);
 
 	if (dual) {
 		clk_prepare_enable(ldb->clk[0]);
-- 
1.7.4.4

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

* [PATCH RFC 23/46] imx-drm: imx-drm-core: use array instead of list for CRTCs
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

The DRM core indexes vblank by number, so there's little point
maintaining a list, and have to scan the list to find the appropriate
structure.  Instead, use an array of pointers to the CRTCs.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   57 +++++++++++++-------------------
 1 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index a402df0f3005..8aef203a017b 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -34,10 +34,12 @@ struct crtc_cookie {
 	struct list_head list;
 };
 
+struct imx_drm_crtc;
+
 struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
-	struct list_head			crtc_list;
+	struct imx_drm_crtc			*crtc[MAX_CRTC];
 	struct list_head			encoder_list;
 	struct list_head			connector_list;
 	struct mutex				mutex;
@@ -47,7 +49,6 @@ struct imx_drm_device {
 
 struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
-	struct list_head			list;
 	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
@@ -69,6 +70,8 @@ struct imx_drm_connector {
 	struct module				*owner;
 };
 
+static struct imx_drm_device *__imx_drm_device(void);
+
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
 	return crtc->pipe;
@@ -96,34 +99,28 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 	return 0;
 }
 
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
-		int num)
+struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 {
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	unsigned i;
+
+	for (i = 0; i < MAX_CRTC; i++)
+		if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+			return imxdrm->crtc[i];
 
-	list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
-		if (imx_drm_crtc->pipe == num)
-			return imx_drm_crtc;
 	return NULL;
 }
 
 int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
-	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
-	struct imx_drm_crtc *imx_crtc;
 	struct imx_drm_crtc_helper_funcs *helper;
+	struct imx_drm_crtc *imx_crtc;
 
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
-		if (imx_crtc->crtc == crtc)
-			goto found;
+	imx_crtc = imx_drm_find_crtc(crtc);
+	if (!imx_crtc)
+		return -EINVAL;
 
-	return -EINVAL;
-found:
 	helper = &imx_crtc->imx_drm_helper_funcs;
 	if (helper->set_interface_pix_fmt)
 		return helper->set_interface_pix_fmt(crtc,
@@ -162,10 +159,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
 	int ret;
 
-	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
 	if (!imx_drm_crtc)
 		return -EINVAL;
 
@@ -181,9 +177,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
 
-	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
 	if (!imx_drm_crtc)
 		return;
 
@@ -509,7 +504,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
 	imx_drm_crtc->owner = owner;
 
-	list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
 
@@ -532,7 +527,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	return 0;
 
 err_register:
-	list_del(&imx_drm_crtc->list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 	kfree(imx_drm_crtc);
 err_alloc:
 err_busy:
@@ -552,7 +547,7 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 
 	drm_crtc_cleanup(imx_drm_crtc->crtc);
 
-	list_del(&imx_drm_crtc->list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
 	drm_mode_group_reinit(imxdrm->drm);
 
@@ -659,14 +654,9 @@ EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
 
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_crtc *imx_crtc;
-
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
-		if (imx_crtc->crtc == encoder->crtc)
-			return imx_crtc->mux_id;
+	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
 
-	return -EINVAL;
+	return imx_crtc ? imx_crtc->mux_id : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
@@ -853,7 +843,6 @@ static int __init imx_drm_init(void)
 		return -ENOMEM;
 
 	mutex_init(&imx_drm_device->mutex);
-	INIT_LIST_HEAD(&imx_drm_device->crtc_list);
 	INIT_LIST_HEAD(&imx_drm_device->connector_list);
 	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
-- 
1.7.4.4

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

* [PATCH RFC 23/46] imx-drm: imx-drm-core: use array instead of list for CRTCs
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The DRM core indexes vblank by number, so there's little point
maintaining a list, and have to scan the list to find the appropriate
structure.  Instead, use an array of pointers to the CRTCs.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   57 +++++++++++++-------------------
 1 files changed, 23 insertions(+), 34 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index a402df0f3005..8aef203a017b 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -34,10 +34,12 @@ struct crtc_cookie {
 	struct list_head list;
 };
 
+struct imx_drm_crtc;
+
 struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
-	struct list_head			crtc_list;
+	struct imx_drm_crtc			*crtc[MAX_CRTC];
 	struct list_head			encoder_list;
 	struct list_head			connector_list;
 	struct mutex				mutex;
@@ -47,7 +49,6 @@ struct imx_drm_device {
 
 struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
-	struct list_head			list;
 	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
@@ -69,6 +70,8 @@ struct imx_drm_connector {
 	struct module				*owner;
 };
 
+static struct imx_drm_device *__imx_drm_device(void);
+
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
 	return crtc->pipe;
@@ -96,34 +99,28 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 	return 0;
 }
 
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
-		int num)
+struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 {
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_device *imxdrm = __imx_drm_device();
+	unsigned i;
+
+	for (i = 0; i < MAX_CRTC; i++)
+		if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+			return imxdrm->crtc[i];
 
-	list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
-		if (imx_drm_crtc->pipe == num)
-			return imx_drm_crtc;
 	return NULL;
 }
 
 int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
-	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
-	struct imx_drm_crtc *imx_crtc;
 	struct imx_drm_crtc_helper_funcs *helper;
+	struct imx_drm_crtc *imx_crtc;
 
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
-		if (imx_crtc->crtc == crtc)
-			goto found;
+	imx_crtc = imx_drm_find_crtc(crtc);
+	if (!imx_crtc)
+		return -EINVAL;
 
-	return -EINVAL;
-found:
 	helper = &imx_crtc->imx_drm_helper_funcs;
 	if (helper->set_interface_pix_fmt)
 		return helper->set_interface_pix_fmt(crtc,
@@ -162,10 +159,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
 	int ret;
 
-	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
 	if (!imx_drm_crtc)
 		return -EINVAL;
 
@@ -181,9 +177,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
-	struct imx_drm_crtc *imx_drm_crtc;
+	struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
 
-	imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
 	if (!imx_drm_crtc)
 		return;
 
@@ -509,7 +504,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 
 	imx_drm_crtc->owner = owner;
 
-	list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
 
@@ -532,7 +527,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	return 0;
 
 err_register:
-	list_del(&imx_drm_crtc->list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 	kfree(imx_drm_crtc);
 err_alloc:
 err_busy:
@@ -552,7 +547,7 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 
 	drm_crtc_cleanup(imx_drm_crtc->crtc);
 
-	list_del(&imx_drm_crtc->list);
+	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
 	drm_mode_group_reinit(imxdrm->drm);
 
@@ -659,14 +654,9 @@ EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
 
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_crtc *imx_crtc;
-
-	list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
-		if (imx_crtc->crtc == encoder->crtc)
-			return imx_crtc->mux_id;
+	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
 
-	return -EINVAL;
+	return imx_crtc ? imx_crtc->mux_id : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
@@ -853,7 +843,6 @@ static int __init imx_drm_init(void)
 		return -ENOMEM;
 
 	mutex_init(&imx_drm_device->mutex);
-	INIT_LIST_HEAD(&imx_drm_device->crtc_list);
 	INIT_LIST_HEAD(&imx_drm_device->connector_list);
 	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
-- 
1.7.4.4

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

* [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Provide a common connector mode validation function, which can be used
to limit the available modes according to other components in the
system.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c     |    7 +++++++
 drivers/staging/imx-drm/imx-drm.h          |    3 +++
 drivers/staging/imx-drm/imx-hdmi.c         |    9 +--------
 drivers/staging/imx-drm/imx-ldb.c          |    8 +-------
 drivers/staging/imx-drm/imx-tve.c          |    5 +++++
 drivers/staging/imx-drm/parallel-display.c |    8 +-------
 6 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8aef203a017b..d7cb0af9479a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -211,6 +211,13 @@ static const struct file_operations imx_drm_driver_fops = {
 	.llseek = noop_llseek,
 };
 
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+	struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+EXPORT_SYMBOL(imx_drm_connector_mode_valid);
+
 static struct imx_drm_device *imx_drm_device;
 
 static struct imx_drm_device *__imx_drm_device(void)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 5649f180dc44..4eb594ce9cff 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
 
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+	struct drm_display_mode *mode);
+
 #endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c8152043143f..8421c715ce14 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1410,13 +1410,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 	return 0;
 }
 
-static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-
-	return MODE_OK;
-}
-
 static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
 							   *connector)
 {
@@ -1505,7 +1498,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
 
 static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
 	.get_modes = imx_hdmi_connector_get_modes,
-	.mode_valid = imx_hdmi_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 	.best_encoder = imx_hdmi_connector_best_encoder,
 };
 
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index bbcbd52f0169..81a23685b42d 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -120,12 +120,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 	return num_modes;
 }
 
-static int imx_ldb_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-	return 0;
-}
-
 static struct drm_encoder *imx_ldb_connector_best_encoder(
 		struct drm_connector *connector)
 {
@@ -330,7 +324,7 @@ static struct drm_connector_funcs imx_ldb_connector_funcs = {
 static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
 	.get_modes = imx_ldb_connector_get_modes,
 	.best_encoder = imx_ldb_connector_best_encoder,
-	.mode_valid = imx_ldb_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 };
 
 static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 2c44fef8d58b..f315c5250fe8 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -254,6 +254,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
 {
 	struct imx_tve *tve = con_to_tve(connector);
 	unsigned long rate;
+	int ret;
+
+	ret = imx_drm_connector_mode_valid(connector, mode);
+	if (ret != MODE_OK)
+		return ret;
 
 	/* pixel clock with 2x oversampling */
 	rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 24aa9beedcfb..789950b87b29 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -84,12 +84,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
 	return num_modes;
 }
 
-static int imx_pd_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-	return 0;
-}
-
 static struct drm_encoder *imx_pd_connector_best_encoder(
 		struct drm_connector *connector)
 {
@@ -146,7 +140,7 @@ static struct drm_connector_funcs imx_pd_connector_funcs = {
 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 	.get_modes = imx_pd_connector_get_modes,
 	.best_encoder = imx_pd_connector_best_encoder,
-	.mode_valid = imx_pd_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 };
 
 static struct drm_encoder_funcs imx_pd_encoder_funcs = {
-- 
1.7.4.4

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

* [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Provide a common connector mode validation function, which can be used
to limit the available modes according to other components in the
system.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c     |    7 +++++++
 drivers/staging/imx-drm/imx-drm.h          |    3 +++
 drivers/staging/imx-drm/imx-hdmi.c         |    9 +--------
 drivers/staging/imx-drm/imx-ldb.c          |    8 +-------
 drivers/staging/imx-drm/imx-tve.c          |    5 +++++
 drivers/staging/imx-drm/parallel-display.c |    8 +-------
 6 files changed, 18 insertions(+), 22 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8aef203a017b..d7cb0af9479a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -211,6 +211,13 @@ static const struct file_operations imx_drm_driver_fops = {
 	.llseek = noop_llseek,
 };
 
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+	struct drm_display_mode *mode)
+{
+	return MODE_OK;
+}
+EXPORT_SYMBOL(imx_drm_connector_mode_valid);
+
 static struct imx_drm_device *imx_drm_device;
 
 static struct imx_drm_device *__imx_drm_device(void)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 5649f180dc44..4eb594ce9cff 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
 
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+	struct drm_display_mode *mode);
+
 #endif /* _IMX_DRM_H_ */
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index c8152043143f..8421c715ce14 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1410,13 +1410,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 	return 0;
 }
 
-static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-
-	return MODE_OK;
-}
-
 static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
 							   *connector)
 {
@@ -1505,7 +1498,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
 
 static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
 	.get_modes = imx_hdmi_connector_get_modes,
-	.mode_valid = imx_hdmi_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 	.best_encoder = imx_hdmi_connector_best_encoder,
 };
 
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index bbcbd52f0169..81a23685b42d 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -120,12 +120,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 	return num_modes;
 }
 
-static int imx_ldb_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-	return 0;
-}
-
 static struct drm_encoder *imx_ldb_connector_best_encoder(
 		struct drm_connector *connector)
 {
@@ -330,7 +324,7 @@ static struct drm_connector_funcs imx_ldb_connector_funcs = {
 static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
 	.get_modes = imx_ldb_connector_get_modes,
 	.best_encoder = imx_ldb_connector_best_encoder,
-	.mode_valid = imx_ldb_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 };
 
 static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index 2c44fef8d58b..f315c5250fe8 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -254,6 +254,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector,
 {
 	struct imx_tve *tve = con_to_tve(connector);
 	unsigned long rate;
+	int ret;
+
+	ret = imx_drm_connector_mode_valid(connector, mode);
+	if (ret != MODE_OK)
+		return ret;
 
 	/* pixel clock with 2x oversampling */
 	rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 24aa9beedcfb..789950b87b29 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -84,12 +84,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
 	return num_modes;
 }
 
-static int imx_pd_connector_mode_valid(struct drm_connector *connector,
-			  struct drm_display_mode *mode)
-{
-	return 0;
-}
-
 static struct drm_encoder *imx_pd_connector_best_encoder(
 		struct drm_connector *connector)
 {
@@ -146,7 +140,7 @@ static struct drm_connector_funcs imx_pd_connector_funcs = {
 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 	.get_modes = imx_pd_connector_get_modes,
 	.best_encoder = imx_pd_connector_best_encoder,
-	.mode_valid = imx_pd_connector_mode_valid,
+	.mode_valid = imx_drm_connector_mode_valid,
 };
 
 static struct drm_encoder_funcs imx_pd_encoder_funcs = {
-- 
1.7.4.4

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

* [PATCH RFC 25/46] imx-drm: simplify setup of panel format
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

The encoder format passed into imx_drm_crtc_panel_format*() is the
encoder format used for DRM in most cases; the HDMI encoder sets
this to none, but this is incorrect, it should be TMDS.

Since this is the case, we can pass the drm_encoder structure
directly into this function and use the supplied fields there to
configure the CRTC.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c     |   18 ++++++++----------
 drivers/staging/imx-drm/imx-drm.h          |    4 ++--
 drivers/staging/imx-drm/imx-hdmi.c         |    3 +--
 drivers/staging/imx-drm/imx-ldb.c          |    3 +--
 drivers/staging/imx-drm/imx-tve.c          |   12 +++++++-----
 drivers/staging/imx-drm/ipuv3-crtc.c       |    1 +
 drivers/staging/imx-drm/parallel-display.c |    3 +--
 7 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d7cb0af9479a..839dbb7c7b36 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -111,32 +111,30 @@ struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 	return NULL;
 }
 
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
 	struct imx_drm_crtc_helper_funcs *helper;
 	struct imx_drm_crtc *imx_crtc;
 
-	imx_crtc = imx_drm_find_crtc(crtc);
+	imx_crtc = imx_drm_find_crtc(encoder->crtc);
 	if (!imx_crtc)
 		return -EINVAL;
 
 	helper = &imx_crtc->imx_drm_helper_funcs;
 	if (helper->set_interface_pix_fmt)
-		return helper->set_interface_pix_fmt(crtc,
-				encoder_type, interface_pix_fmt,
+		return helper->set_interface_pix_fmt(encoder->crtc,
+				encoder->encoder_type, interface_pix_fmt,
 				hsync_pin, vsync_pin);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
 
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
-		u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
 {
-	return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
-					      interface_pix_fmt, 2, 3);
+	return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 4eb594ce9cff..e3ca0c6b6a39 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -56,9 +56,9 @@ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
 
 struct drm_device *imx_drm_device_get(void);
 void imx_drm_device_put(void);
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
 void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 8421c715ce14..0e5e7a6f6168 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1457,8 +1457,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
 	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
 
 	imx_hdmi_poweroff(hdmi);
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
-				  V4L2_PIX_FMT_RGB24);
+	imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
 }
 
 static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 81a23685b42d..70455c4d7e48 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -201,8 +201,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 		pixel_fmt = V4L2_PIX_FMT_RGB24;
 	}
 
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
-			pixel_fmt);
+	imx_drm_panel_format(encoder, pixel_fmt);
 }
 
 static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index f315c5250fe8..b2f214971501 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -310,13 +310,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
 
 	switch (tve->mode) {
 	case TVE_MODE_VGA:
-		imx_drm_crtc_panel_format_pins(encoder->crtc,
-				DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+		imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
 				tve->hsync_pin, tve->vsync_pin);
 		break;
 	case TVE_MODE_TVOUT:
-		imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
-					  V4L2_PIX_FMT_YUV444);
+		imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
 		break;
 	}
 }
@@ -510,12 +508,16 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
 
 static int imx_tve_register(struct imx_tve *tve)
 {
+	int encoder_type;
 	int ret;
 
+	encoder_type = tve->mode == TVE_MODE_VGA ?
+				DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
+
 	tve->connector.funcs = &imx_tve_connector_funcs;
 	tve->encoder.funcs = &imx_tve_encoder_funcs;
 
-	tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+	tve->encoder.encoder_type = encoder_type;
 	tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
 
 	drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ce6ba987ec91..2bee6fa585f8 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -283,6 +283,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
 		ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
 			IPU_DI_CLKMODE_EXT;
 		break;
+	case DRM_MODE_ENCODER_TMDS:
 	case DRM_MODE_ENCODER_NONE:
 		ipu_crtc->di_clkflags = 0;
 		break;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 789950b87b29..9ba9ca1aeb67 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -107,8 +107,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
 {
 	struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
 
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
-			imxpd->interface_pix_fmt);
+	imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
 }
 
 static void imx_pd_encoder_commit(struct drm_encoder *encoder)
-- 
1.7.4.4

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

* [PATCH RFC 25/46] imx-drm: simplify setup of panel format
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The encoder format passed into imx_drm_crtc_panel_format*() is the
encoder format used for DRM in most cases; the HDMI encoder sets
this to none, but this is incorrect, it should be TMDS.

Since this is the case, we can pass the drm_encoder structure
directly into this function and use the supplied fields there to
configure the CRTC.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c     |   18 ++++++++----------
 drivers/staging/imx-drm/imx-drm.h          |    4 ++--
 drivers/staging/imx-drm/imx-hdmi.c         |    3 +--
 drivers/staging/imx-drm/imx-ldb.c          |    3 +--
 drivers/staging/imx-drm/imx-tve.c          |   12 +++++++-----
 drivers/staging/imx-drm/ipuv3-crtc.c       |    1 +
 drivers/staging/imx-drm/parallel-display.c |    3 +--
 7 files changed, 21 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d7cb0af9479a..839dbb7c7b36 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -111,32 +111,30 @@ struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 	return NULL;
 }
 
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
 	struct imx_drm_crtc_helper_funcs *helper;
 	struct imx_drm_crtc *imx_crtc;
 
-	imx_crtc = imx_drm_find_crtc(crtc);
+	imx_crtc = imx_drm_find_crtc(encoder->crtc);
 	if (!imx_crtc)
 		return -EINVAL;
 
 	helper = &imx_crtc->imx_drm_helper_funcs;
 	if (helper->set_interface_pix_fmt)
-		return helper->set_interface_pix_fmt(crtc,
-				encoder_type, interface_pix_fmt,
+		return helper->set_interface_pix_fmt(encoder->crtc,
+				encoder->encoder_type, interface_pix_fmt,
 				hsync_pin, vsync_pin);
 	return 0;
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
 
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
-		u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
 {
-	return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
-					      interface_pix_fmt, 2, 3);
+	return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 4eb594ce9cff..e3ca0c6b6a39 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -56,9 +56,9 @@ struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
 
 struct drm_device *imx_drm_device_get(void);
 void imx_drm_device_put(void);
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
 void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 8421c715ce14..0e5e7a6f6168 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -1457,8 +1457,7 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
 	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
 
 	imx_hdmi_poweroff(hdmi);
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
-				  V4L2_PIX_FMT_RGB24);
+	imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
 }
 
 static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 81a23685b42d..70455c4d7e48 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -201,8 +201,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
 		pixel_fmt = V4L2_PIX_FMT_RGB24;
 	}
 
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS,
-			pixel_fmt);
+	imx_drm_panel_format(encoder, pixel_fmt);
 }
 
 static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index f315c5250fe8..b2f214971501 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -310,13 +310,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
 
 	switch (tve->mode) {
 	case TVE_MODE_VGA:
-		imx_drm_crtc_panel_format_pins(encoder->crtc,
-				DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24,
+		imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24,
 				tve->hsync_pin, tve->vsync_pin);
 		break;
 	case TVE_MODE_TVOUT:
-		imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC,
-					  V4L2_PIX_FMT_YUV444);
+		imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444);
 		break;
 	}
 }
@@ -510,12 +508,16 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
 
 static int imx_tve_register(struct imx_tve *tve)
 {
+	int encoder_type;
 	int ret;
 
+	encoder_type = tve->mode == TVE_MODE_VGA ?
+				DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
+
 	tve->connector.funcs = &imx_tve_connector_funcs;
 	tve->encoder.funcs = &imx_tve_encoder_funcs;
 
-	tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
+	tve->encoder.encoder_type = encoder_type;
 	tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
 
 	drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ce6ba987ec91..2bee6fa585f8 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -283,6 +283,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
 		ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
 			IPU_DI_CLKMODE_EXT;
 		break;
+	case DRM_MODE_ENCODER_TMDS:
 	case DRM_MODE_ENCODER_NONE:
 		ipu_crtc->di_clkflags = 0;
 		break;
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 789950b87b29..9ba9ca1aeb67 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -107,8 +107,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
 {
 	struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
 
-	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
-			imxpd->interface_pix_fmt);
+	imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
 }
 
 static void imx_pd_encoder_commit(struct drm_encoder *encoder)
-- 
1.7.4.4

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:27   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

Subsystems such as ALSA, DRM and others require a single card-level
device structure to represent a subsystem.  However, firmware tends to
describe the individual devices and the connections between them.

Therefore, we need a way to gather up the individual component devices
together, and indicate when we have all the component devices.

We do this in DT by providing a "superdevice" node which specifies
the components, eg:

	imx-drm {
		compatible = "fsl,drm";
		crtcs = <&ipu1>;
		connectors = <&hdmi>;
	};

The superdevice is declared into the component support, along with the
subcomponents.  The superdevice receives callbacks to locate the
subcomponents, and identify when all components are present.  At this
point, we bind the superdevice, which causes the appropriate subsystem
to be initialised in the conventional way.

When any of the components or superdevice are removed from the system,
we unbind the superdevice, thereby taking the subsystem down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/base/Makefile     |    2 +-
 drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/component.h |   31 ++++
 3 files changed, 411 insertions(+), 1 deletions(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 include/linux/component.h

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80e87f8..870ecfd503af 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o bus.o dd.o syscore.o \
+obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
diff --git a/drivers/base/component.c b/drivers/base/component.c
new file mode 100644
index 000000000000..5492cd8d2247
--- /dev/null
+++ b/drivers/base/component.c
@@ -0,0 +1,379 @@
+/*
+ * Componentized device handling.
+ *
+ * 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.
+ *
+ * This is work in progress.  We gather up the component devices into a list,
+ * and bind them when instructed.  At the moment, we're specific to the DRM
+ * subsystem, and only handles one master device, but this doesn't have to be
+ * the case.
+ */
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+struct master {
+	struct list_head node;
+	struct list_head components;
+	bool bound;
+
+	const struct component_master_ops *ops;
+	struct device *dev;
+};
+
+struct component {
+	struct list_head node;
+	struct list_head master_node;
+	struct master *master;
+	bool bound;
+
+	const struct component_ops *ops;
+	struct device *dev;
+};
+
+static DEFINE_MUTEX(component_mutex);
+static LIST_HEAD(component_list);
+static LIST_HEAD(masters);
+
+static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *m;
+
+	list_for_each_entry(m, &masters, node)
+		if (m->dev == dev && (!ops || m->ops == ops))
+			return m;
+
+	return NULL;
+}
+
+/* Attach an unattached component to a master. */
+static void component_attach_master(struct master *master, struct component *c)
+{
+	c->master = master;
+
+	list_add_tail(&c->master_node, &master->components);
+}
+
+/* Detach a component from a master. */
+static void component_detach_master(struct master *master, struct component *c)
+{
+	list_del(&c->master_node);
+
+	c->master = NULL;
+}
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data)
+{
+	struct component *c;
+	int ret = -ENXIO;
+
+	list_for_each_entry(c, &component_list, node) {
+		if (c->master)
+			continue;
+
+		if (compare(c->dev, compare_data)) {
+			component_attach_master(master, c);
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_master_add_child);
+
+/* Detach all attached components from this master */
+static void master_remove_components(struct master *master)
+{
+	while (!list_empty(&master->components)) {
+		struct component *c = list_first_entry(&master->components,
+					struct component, master_node);
+
+		WARN_ON(c->master != master);
+
+		component_detach_master(master, c);
+	}
+}
+
+/*
+ * Try to bring up a master.  If component is NULL, we're interested in
+ * this master, otherwise it's a component which must be present to try
+ * and bring up the master.
+ *
+ * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
+ */
+static int try_to_bring_up_master(struct master *master,
+	struct component *component)
+{
+	int ret = 0;
+
+	if (!master->bound) {
+		/*
+		 * Search the list of components, looking for components that
+		 * belong to this master, and attach them to the master.
+		 */
+		if (master->ops->add_components(master->dev, master)) {
+			/* Failed to find all components */
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		if (component && component->master != master) {
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		/* Found all components */
+		ret = master->ops->bind(master->dev);
+		if (ret < 0) {
+			master_remove_components(master);
+			goto out;
+		}
+
+		master->bound = true;
+		ret = 1;
+	}
+out:
+
+	return ret;
+}
+
+static int try_to_bring_up_masters(struct component *component)
+{
+	struct master *m;
+	int ret = 0;
+
+	list_for_each_entry(m, &masters, node) {
+		ret = try_to_bring_up_master(m, component);
+		if (ret != 0)
+			break;
+	}
+
+	return ret;
+}
+
+static void take_down_master(struct master *master)
+{
+	if (master->bound) {
+		master->ops->unbind(master->dev);
+		master->bound = false;
+	}
+
+	master_remove_components(master);
+}
+
+int component_master_add(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *master;
+	int ret;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return -ENOMEM;
+
+	master->dev = dev;
+	master->ops = ops;
+	INIT_LIST_HEAD(&master->components);
+
+	/* Add to the list of available masters. */
+	mutex_lock(&component_mutex);
+	list_add(&master->node, &masters);
+
+	ret = try_to_bring_up_master(master, NULL);
+
+	if (ret < 0) {
+		/* Delete off the list if we weren't successful */
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_master_add);
+
+void component_master_del(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *master;
+
+	mutex_lock(&component_mutex);
+	master = __master_find(dev, ops);
+	if (master) {
+		take_down_master(master);
+
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+}
+EXPORT_SYMBOL_GPL(component_master_del);
+
+static void component_unbind(struct component *component,
+	struct master *master, void *data)
+{
+	WARN_ON(!component->bound);
+
+	component->ops->unbind(component->dev, master->dev, data);
+	component->bound = false;
+
+	/* Release all resources claimed in the binding of this component */
+	devres_release_group(component->dev, component);
+}
+
+void component_unbind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return;
+
+	list_for_each_entry_reverse(c, &master->components, master_node)
+		component_unbind(c, master, data);
+}
+EXPORT_SYMBOL_GPL(component_unbind_all);
+
+static int component_bind(struct component *component, struct master *master,
+	void *data)
+{
+	int ret;
+
+	/*
+	 * Each component initialises inside its own devres group.
+	 * This allows us to roll-back a failed component without
+	 * affecting anything else.
+	 */
+	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	/*
+	 * Also open a group for the device itself: this allows us
+	 * to release the resources claimed against the sub-device
+	 * at the appropriate moment.
+	 */
+	if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
+		devres_release_group(master->dev, NULL);
+		return -ENOMEM;
+	}
+
+	dev_dbg(master->dev, "binding %s (ops %ps)\n",
+		dev_name(component->dev), component->ops);
+
+	ret = component->ops->bind(component->dev, master->dev, data);
+	if (!ret) {
+		component->bound = true;
+
+		/*
+		 * Close the component device's group so that resources
+		 * allocated in the binding are encapsulated for removal
+		 * at unbind.  Remove the group on the DRM device as we
+		 * can clean those resources up independently.
+		 */
+		devres_close_group(component->dev, NULL);
+		devres_remove_group(master->dev, NULL);
+
+		dev_info(master->dev, "bound %s (ops %ps)\n",
+			 dev_name(component->dev), component->ops);
+	} else {
+		devres_release_group(component->dev, NULL);
+		devres_release_group(master->dev, NULL);
+
+		dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+			dev_name(component->dev), component->ops, ret);
+	}
+
+	return ret;
+}
+
+int component_bind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+	int ret = 0;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return -EINVAL;
+
+	list_for_each_entry(c, &master->components, master_node) {
+		ret = component_bind(c, master, data);
+		if (ret)
+			break;
+	}
+
+	if (ret != 0) {
+		list_for_each_entry_continue_reverse(c, &master->components,
+						     master_node)
+			component_unbind(c, master, data);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_bind_all);
+
+int component_add(struct device *dev, const struct component_ops *ops)
+{
+	struct component *component;
+	int ret;
+
+	component = kzalloc(sizeof(*component), GFP_KERNEL);
+	if (!component)
+		return -ENOMEM;
+
+	component->ops = ops;
+	component->dev = dev;
+
+	dev_dbg(dev, "adding component (ops %ps)\n", ops);
+
+	mutex_lock(&component_mutex);
+	list_add_tail(&component->node, &component_list);
+
+	ret = try_to_bring_up_masters(component);
+	if (ret < 0) {
+		list_del(&component->node);
+
+		kfree(component);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_add);
+
+void component_del(struct device *dev, const struct component_ops *ops)
+{
+	struct component *c, *component = NULL;
+
+	mutex_lock(&component_mutex);
+	list_for_each_entry(c, &component_list, node)
+		if (c->dev == dev && c->ops == ops) {
+			list_del(&c->node);
+			component = c;
+			break;
+		}
+
+	if (component && component->master)
+		take_down_master(component->master);
+
+	mutex_unlock(&component_mutex);
+
+	WARN_ON(!component);
+	kfree(component);
+}
+EXPORT_SYMBOL_GPL(component_del);
+
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/component.h b/include/linux/component.h
new file mode 100644
index 000000000000..73657636db0b
--- /dev/null
+++ b/include/linux/component.h
@@ -0,0 +1,31 @@
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+struct device;
+
+struct component_ops {
+	int (*bind)(struct device *, struct device *, void *);
+	void (*unbind)(struct device *, struct device *, void *);
+};
+
+int component_add(struct device *, const struct component_ops *);
+void component_del(struct device *, const struct component_ops *);
+
+int component_bind_all(struct device *, void *);
+void component_unbind_all(struct device *, void *);
+
+struct master;
+
+struct component_master_ops {
+	int (*add_components)(struct device *, struct master *);
+	int (*bind)(struct device *);
+	void (*unbind)(struct device *);
+};
+
+int component_master_add(struct device *, const struct component_master_ops *);
+void component_master_del(struct device *, const struct component_master_ops *);
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data);
+
+#endif
-- 
1.7.4.4

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-02 21:27   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:27 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Subsystems such as ALSA, DRM and others require a single card-level
device structure to represent a subsystem.  However, firmware tends to
describe the individual devices and the connections between them.

Therefore, we need a way to gather up the individual component devices
together, and indicate when we have all the component devices.

We do this in DT by providing a "superdevice" node which specifies
the components, eg:

	imx-drm {
		compatible = "fsl,drm";
		crtcs = <&ipu1>;
		connectors = <&hdmi>;
	};

The superdevice is declared into the component support, along with the
subcomponents.  The superdevice receives callbacks to locate the
subcomponents, and identify when all components are present.  At this
point, we bind the superdevice, which causes the appropriate subsystem
to be initialised in the conventional way.

When any of the components or superdevice are removed from the system,
we unbind the superdevice, thereby taking the subsystem down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/base/Makefile     |    2 +-
 drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
 include/linux/component.h |   31 ++++
 3 files changed, 411 insertions(+), 1 deletions(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 include/linux/component.h

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80e87f8..870ecfd503af 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o bus.o dd.o syscore.o \
+obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
diff --git a/drivers/base/component.c b/drivers/base/component.c
new file mode 100644
index 000000000000..5492cd8d2247
--- /dev/null
+++ b/drivers/base/component.c
@@ -0,0 +1,379 @@
+/*
+ * Componentized device handling.
+ *
+ * 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.
+ *
+ * This is work in progress.  We gather up the component devices into a list,
+ * and bind them when instructed.  At the moment, we're specific to the DRM
+ * subsystem, and only handles one master device, but this doesn't have to be
+ * the case.
+ */
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+struct master {
+	struct list_head node;
+	struct list_head components;
+	bool bound;
+
+	const struct component_master_ops *ops;
+	struct device *dev;
+};
+
+struct component {
+	struct list_head node;
+	struct list_head master_node;
+	struct master *master;
+	bool bound;
+
+	const struct component_ops *ops;
+	struct device *dev;
+};
+
+static DEFINE_MUTEX(component_mutex);
+static LIST_HEAD(component_list);
+static LIST_HEAD(masters);
+
+static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *m;
+
+	list_for_each_entry(m, &masters, node)
+		if (m->dev == dev && (!ops || m->ops == ops))
+			return m;
+
+	return NULL;
+}
+
+/* Attach an unattached component to a master. */
+static void component_attach_master(struct master *master, struct component *c)
+{
+	c->master = master;
+
+	list_add_tail(&c->master_node, &master->components);
+}
+
+/* Detach a component from a master. */
+static void component_detach_master(struct master *master, struct component *c)
+{
+	list_del(&c->master_node);
+
+	c->master = NULL;
+}
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data)
+{
+	struct component *c;
+	int ret = -ENXIO;
+
+	list_for_each_entry(c, &component_list, node) {
+		if (c->master)
+			continue;
+
+		if (compare(c->dev, compare_data)) {
+			component_attach_master(master, c);
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_master_add_child);
+
+/* Detach all attached components from this master */
+static void master_remove_components(struct master *master)
+{
+	while (!list_empty(&master->components)) {
+		struct component *c = list_first_entry(&master->components,
+					struct component, master_node);
+
+		WARN_ON(c->master != master);
+
+		component_detach_master(master, c);
+	}
+}
+
+/*
+ * Try to bring up a master.  If component is NULL, we're interested in
+ * this master, otherwise it's a component which must be present to try
+ * and bring up the master.
+ *
+ * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
+ */
+static int try_to_bring_up_master(struct master *master,
+	struct component *component)
+{
+	int ret = 0;
+
+	if (!master->bound) {
+		/*
+		 * Search the list of components, looking for components that
+		 * belong to this master, and attach them to the master.
+		 */
+		if (master->ops->add_components(master->dev, master)) {
+			/* Failed to find all components */
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		if (component && component->master != master) {
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		/* Found all components */
+		ret = master->ops->bind(master->dev);
+		if (ret < 0) {
+			master_remove_components(master);
+			goto out;
+		}
+
+		master->bound = true;
+		ret = 1;
+	}
+out:
+
+	return ret;
+}
+
+static int try_to_bring_up_masters(struct component *component)
+{
+	struct master *m;
+	int ret = 0;
+
+	list_for_each_entry(m, &masters, node) {
+		ret = try_to_bring_up_master(m, component);
+		if (ret != 0)
+			break;
+	}
+
+	return ret;
+}
+
+static void take_down_master(struct master *master)
+{
+	if (master->bound) {
+		master->ops->unbind(master->dev);
+		master->bound = false;
+	}
+
+	master_remove_components(master);
+}
+
+int component_master_add(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *master;
+	int ret;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return -ENOMEM;
+
+	master->dev = dev;
+	master->ops = ops;
+	INIT_LIST_HEAD(&master->components);
+
+	/* Add to the list of available masters. */
+	mutex_lock(&component_mutex);
+	list_add(&master->node, &masters);
+
+	ret = try_to_bring_up_master(master, NULL);
+
+	if (ret < 0) {
+		/* Delete off the list if we weren't successful */
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_master_add);
+
+void component_master_del(struct device *dev, const struct component_master_ops *ops)
+{
+	struct master *master;
+
+	mutex_lock(&component_mutex);
+	master = __master_find(dev, ops);
+	if (master) {
+		take_down_master(master);
+
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+}
+EXPORT_SYMBOL_GPL(component_master_del);
+
+static void component_unbind(struct component *component,
+	struct master *master, void *data)
+{
+	WARN_ON(!component->bound);
+
+	component->ops->unbind(component->dev, master->dev, data);
+	component->bound = false;
+
+	/* Release all resources claimed in the binding of this component */
+	devres_release_group(component->dev, component);
+}
+
+void component_unbind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return;
+
+	list_for_each_entry_reverse(c, &master->components, master_node)
+		component_unbind(c, master, data);
+}
+EXPORT_SYMBOL_GPL(component_unbind_all);
+
+static int component_bind(struct component *component, struct master *master,
+	void *data)
+{
+	int ret;
+
+	/*
+	 * Each component initialises inside its own devres group.
+	 * This allows us to roll-back a failed component without
+	 * affecting anything else.
+	 */
+	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	/*
+	 * Also open a group for the device itself: this allows us
+	 * to release the resources claimed against the sub-device
+	 * at the appropriate moment.
+	 */
+	if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
+		devres_release_group(master->dev, NULL);
+		return -ENOMEM;
+	}
+
+	dev_dbg(master->dev, "binding %s (ops %ps)\n",
+		dev_name(component->dev), component->ops);
+
+	ret = component->ops->bind(component->dev, master->dev, data);
+	if (!ret) {
+		component->bound = true;
+
+		/*
+		 * Close the component device's group so that resources
+		 * allocated in the binding are encapsulated for removal
+		 * at unbind.  Remove the group on the DRM device as we
+		 * can clean those resources up independently.
+		 */
+		devres_close_group(component->dev, NULL);
+		devres_remove_group(master->dev, NULL);
+
+		dev_info(master->dev, "bound %s (ops %ps)\n",
+			 dev_name(component->dev), component->ops);
+	} else {
+		devres_release_group(component->dev, NULL);
+		devres_release_group(master->dev, NULL);
+
+		dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+			dev_name(component->dev), component->ops, ret);
+	}
+
+	return ret;
+}
+
+int component_bind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+	int ret = 0;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return -EINVAL;
+
+	list_for_each_entry(c, &master->components, master_node) {
+		ret = component_bind(c, master, data);
+		if (ret)
+			break;
+	}
+
+	if (ret != 0) {
+		list_for_each_entry_continue_reverse(c, &master->components,
+						     master_node)
+			component_unbind(c, master, data);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_bind_all);
+
+int component_add(struct device *dev, const struct component_ops *ops)
+{
+	struct component *component;
+	int ret;
+
+	component = kzalloc(sizeof(*component), GFP_KERNEL);
+	if (!component)
+		return -ENOMEM;
+
+	component->ops = ops;
+	component->dev = dev;
+
+	dev_dbg(dev, "adding component (ops %ps)\n", ops);
+
+	mutex_lock(&component_mutex);
+	list_add_tail(&component->node, &component_list);
+
+	ret = try_to_bring_up_masters(component);
+	if (ret < 0) {
+		list_del(&component->node);
+
+		kfree(component);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_add);
+
+void component_del(struct device *dev, const struct component_ops *ops)
+{
+	struct component *c, *component = NULL;
+
+	mutex_lock(&component_mutex);
+	list_for_each_entry(c, &component_list, node)
+		if (c->dev == dev && c->ops == ops) {
+			list_del(&c->node);
+			component = c;
+			break;
+		}
+
+	if (component && component->master)
+		take_down_master(component->master);
+
+	mutex_unlock(&component_mutex);
+
+	WARN_ON(!component);
+	kfree(component);
+}
+EXPORT_SYMBOL_GPL(component_del);
+
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/component.h b/include/linux/component.h
new file mode 100644
index 000000000000..73657636db0b
--- /dev/null
+++ b/include/linux/component.h
@@ -0,0 +1,31 @@
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+struct device;
+
+struct component_ops {
+	int (*bind)(struct device *, struct device *, void *);
+	void (*unbind)(struct device *, struct device *, void *);
+};
+
+int component_add(struct device *, const struct component_ops *);
+void component_del(struct device *, const struct component_ops *);
+
+int component_bind_all(struct device *, void *);
+void component_unbind_all(struct device *, void *);
+
+struct master;
+
+struct component_master_ops {
+	int (*add_components)(struct device *, struct master *);
+	int (*bind)(struct device *);
+	void (*unbind)(struct device *);
+};
+
+int component_master_add(struct device *, const struct component_master_ops *);
+void component_master_del(struct device *, const struct component_master_ops *);
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data);
+
+#endif
-- 
1.7.4.4

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Use the componentised device support for imx-drm.  This requires all
the sub-components and the master device to register with the component
device support.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx51-babbage.dts        |   10 ++-
 arch/arm/boot/dts/imx53-m53evk.dts         |    8 ++-
 arch/arm/boot/dts/imx53-mba53.dts          |    6 ++
 arch/arm/boot/dts/imx53-qsb.dts            |    8 ++-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi     |    6 ++
 drivers/staging/imx-drm/imx-drm-core.c     |  105 ++++++++++++++++++++++-----
 drivers/staging/imx-drm/imx-ldb.c          |   40 ++++++++---
 drivers/staging/imx-drm/imx-tve.c          |   63 +++++++++++------
 drivers/staging/imx-drm/ipuv3-crtc.c       |   46 +++++++++----
 drivers/staging/imx-drm/parallel-display.c |   30 ++++++--
 10 files changed, 242 insertions(+), 80 deletions(-)

diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index be1407cf5abd..6ff15a0eacb3 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,7 +21,7 @@
 		reg = <0x90000000 0x20000000>;
 	};
 
-	display at di0 {
+	display0: display at di0 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 0>;
 		interface-pix-fmt = "rgb24";
@@ -43,7 +43,7 @@
 		};
 	};
 
-	display at di1 {
+	display1: display at di1 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 1>;
 		interface-pix-fmt = "rgb565";
@@ -81,6 +81,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 0>, <&ipu 1>;
+		connectors = <&display0>, <&display1>;
+	};
+
 	sound {
 		compatible = "fsl,imx51-babbage-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
index 7d304d02ed38..ee6107b6484c 100644
--- a/arch/arm/boot/dts/imx53-m53evk.dts
+++ b/arch/arm/boot/dts/imx53-m53evk.dts
@@ -21,7 +21,7 @@
 	};
 
 	soc {
-		display at di1 {
+		display1: display at di1 {
 			compatible = "fsl,imx-parallel-display";
 			crtcs = <&ipu 1>;
 			interface-pix-fmt = "bgr666";
@@ -53,6 +53,12 @@
 		default-brightness-level = <6>;
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 1>;
+		connectors = <&display1>;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
index a63090267941..9b6e76980a74 100644
--- a/arch/arm/boot/dts/imx53-mba53.dts
+++ b/arch/arm/boot/dts/imx53-mba53.dts
@@ -43,6 +43,12 @@
 		status = "disabled";
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 1>;
+		connectors = <&disp1>, <&tve>;
+	};
+
 	reg_3p2v: 3p2v {
 		compatible = "regulator-fixed";
 		regulator-name = "3P2V";
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 91a5935a4aac..3cb4f7791a91 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -21,7 +21,7 @@
 		reg = <0x70000000 0x40000000>;
 	};
 
-	display at di0 {
+	display0: display at di0 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 0>;
 		interface-pix-fmt = "rgb565";
@@ -72,6 +72,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 0>;
+		connectors = <&display0>;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index e75e11b36dff..0e005f21d241 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -62,6 +62,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu1 0>, <&ipu1 1>;
+		connectors = <&ldb>;
+	};
+
 	sound {
 		compatible = "fsl,imx6q-sabresd-wm8962",
 			   "fsl,imx-audio-wm8962";
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 839dbb7c7b36..8ece15944569 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  *
  */
-
+#include <linux/component.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
@@ -90,6 +90,8 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+	component_unbind_all(drm->dev, drm);
+
 	imx_drm_device_put();
 
 	drm_vblank_cleanup(drm);
@@ -371,11 +373,8 @@ static void imx_drm_connector_unregister(
 }
 
 /*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
  */
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
@@ -427,8 +426,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	}
 
 	mutex_unlock(&imxdrm->mutex);
+
+	/* Now try and bind all our sub-components */
+	ret = component_bind_all(drm->dev, drm);
+	if (ret)
+		goto err_relock;
 	return 0;
 
+err_relock:
+	mutex_lock(&imxdrm->mutex);
 err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
@@ -808,6 +814,70 @@ static struct drm_driver imx_drm_driver = {
 	.patchlevel		= 0,
 };
 
+static int compare_parent_of(struct device *dev, void *data)
+{
+	struct of_phandle_args *args = data;
+	return dev->parent && dev->parent->of_node == args->np;
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int imx_drm_add_components(struct device *master, struct master *m)
+{
+	struct device_node *np = master->of_node;
+	unsigned i;
+	int ret;
+
+	for (i = 0; ; i++) {
+		struct of_phandle_args args;
+
+		ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
+						       i, &args);
+		if (ret)
+			break;
+
+		ret = component_master_add_child(m, compare_parent_of, &args);
+		of_node_put(args.np);
+
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; ; i++) {
+		struct device_node *node;
+
+		node = of_parse_phandle(np, "connectors", i);
+		if (!node)
+			break;
+
+		ret = component_master_add_child(m, compare_of, node);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int imx_drm_bind(struct device *dev)
+{
+	return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+	drm_platform_exit(&imx_drm_driver, to_platform_device(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+	.add_components = imx_drm_add_components,
+	.bind = imx_drm_bind,
+	.unbind = imx_drm_unbind,
+};
+
 static int imx_drm_platform_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -818,27 +888,31 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 
 	imx_drm_device->dev = &pdev->dev;
 
-	return drm_platform_init(&imx_drm_driver, pdev);
+	return component_master_add(&pdev->dev, &imx_drm_ops);
 }
 
 static int imx_drm_platform_remove(struct platform_device *pdev)
 {
-	drm_platform_exit(&imx_drm_driver, pdev);
-
+	component_master_del(&pdev->dev, &imx_drm_ops);
 	return 0;
 }
 
+static const struct of_device_id imx_drm_dt_ids[] = {
+	{ .compatible = "fsl,imx-drm", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
 static struct platform_driver imx_drm_pdrv = {
 	.probe		= imx_drm_platform_probe,
 	.remove		= imx_drm_platform_remove,
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.name	= "imx-drm",
+		.of_match_table = imx_drm_dt_ids,
 	},
 };
 
-static struct platform_device *imx_drm_pdev;
-
 static int __init imx_drm_init(void)
 {
 	int ret;
@@ -851,12 +925,6 @@ static int __init imx_drm_init(void)
 	INIT_LIST_HEAD(&imx_drm_device->connector_list);
 	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
-	imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
-	if (IS_ERR(imx_drm_pdev)) {
-		ret = PTR_ERR(imx_drm_pdev);
-		goto err_pdev;
-	}
-
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
 		goto err_pdrv;
@@ -864,8 +932,6 @@ static int __init imx_drm_init(void)
 	return 0;
 
 err_pdrv:
-	platform_device_unregister(imx_drm_pdev);
-err_pdev:
 	kfree(imx_drm_device);
 
 	return ret;
@@ -873,7 +939,6 @@ static int __init imx_drm_init(void)
 
 static void __exit imx_drm_exit(void)
 {
-	platform_device_unregister(imx_drm_pdev);
 	platform_driver_unregister(&imx_drm_pdrv);
 
 	kfree(imx_drm_device);
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 70455c4d7e48..5b71f49faa0a 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -20,6 +20,7 @@
 
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -451,11 +452,11 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
-static int imx_ldb_probe(struct platform_device *pdev)
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = dev->of_node;
 	const struct of_device_id *of_id =
-			of_match_device(imx_ldb_dt_ids, &pdev->dev);
+			of_match_device(imx_ldb_dt_ids, dev);
 	struct device_node *child;
 	const u8 *edidp;
 	struct imx_ldb *imx_ldb;
@@ -465,17 +466,17 @@ static int imx_ldb_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
+	imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
 	if (!imx_ldb)
 		return -ENOMEM;
 
 	imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
 	if (IS_ERR(imx_ldb->regmap)) {
-		dev_err(&pdev->dev, "failed to get parent regmap\n");
+		dev_err(dev, "failed to get parent regmap\n");
 		return PTR_ERR(imx_ldb->regmap);
 	}
 
-	imx_ldb->dev = &pdev->dev;
+	imx_ldb->dev = dev;
 
 	if (of_id)
 		imx_ldb->lvds_mux = of_id->data;
@@ -513,7 +514,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 			return -EINVAL;
 
 		if (dual && i > 0) {
-			dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n");
+			dev_warn(dev, "dual-channel mode, ignoring second output\n");
 			continue;
 		}
 
@@ -552,7 +553,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 			break;
 		case LVDS_BIT_MAP_JEIDA:
 			if (datawidth == 18) {
-				dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n");
+				dev_err(dev, "JEIDA standard only supported in 24 bit\n");
 				return -EINVAL;
 			}
 			if (i == 0 || dual)
@@ -561,7 +562,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 				imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA;
 			break;
 		default:
-			dev_err(&pdev->dev, "data mapping not specified or invalid\n");
+			dev_err(dev, "data mapping not specified or invalid\n");
 			return -EINVAL;
 		}
 
@@ -572,14 +573,15 @@ static int imx_ldb_probe(struct platform_device *pdev)
 		imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
 	}
 
-	platform_set_drvdata(pdev, imx_ldb);
+	dev_set_drvdata(dev, imx_ldb);
 
 	return 0;
 }
 
-static int imx_ldb_remove(struct platform_device *pdev)
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
+	struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
 	int i;
 
 	for (i = 0; i < 2; i++) {
@@ -592,7 +594,21 @@ static int imx_ldb_remove(struct platform_device *pdev)
 		imx_drm_remove_connector(channel->imx_drm_connector);
 		imx_drm_remove_encoder(channel->imx_drm_encoder);
 	}
+}
 
+static const struct component_ops imx_ldb_ops = {
+	.bind	= imx_ldb_bind,
+	.unbind	= imx_ldb_unbind,
+};
+
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_ldb_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index b2f214971501..f8720f1ef86e 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -20,6 +20,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/component.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
@@ -583,9 +584,10 @@ const int of_get_tve_mode(struct device_node *np)
 	return -EINVAL;
 }
 
-static int imx_tve_probe(struct platform_device *pdev)
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_tve *tve;
 	struct resource *res;
@@ -594,11 +596,11 @@ static int imx_tve_probe(struct platform_device *pdev)
 	int irq;
 	int ret;
 
-	tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+	tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
 	if (!tve)
 		return -ENOMEM;
 
-	tve->dev = &pdev->dev;
+	tve->dev = dev;
 	spin_lock_init(&tve->lock);
 
 	ddc_node = of_parse_phandle(np, "ddc", 0);
@@ -609,7 +611,7 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	tve->mode = of_get_tve_mode(np);
 	if (tve->mode != TVE_MODE_VGA) {
-		dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+		dev_err(dev, "only VGA mode supported, currently\n");
 		return -EINVAL;
 	}
 
@@ -618,7 +620,7 @@ static int imx_tve_probe(struct platform_device *pdev)
 					   &tve->hsync_pin);
 
 		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to get vsync pin\n");
+			dev_err(dev, "failed to get vsync pin\n");
 			return ret;
 		}
 
@@ -626,40 +628,40 @@ static int imx_tve_probe(struct platform_device *pdev)
 					    &tve->vsync_pin);
 
 		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to get vsync pin\n");
+			dev_err(dev, "failed to get vsync pin\n");
 			return ret;
 		}
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
+	base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
 	tve_regmap_config.lock_arg = tve;
-	tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+	tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
 						&tve_regmap_config);
 	if (IS_ERR(tve->regmap)) {
-		dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+		dev_err(dev, "failed to init regmap: %ld\n",
 			PTR_ERR(tve->regmap));
 		return PTR_ERR(tve->regmap);
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "failed to get irq\n");
+		dev_err(dev, "failed to get irq\n");
 		return irq;
 	}
 
-	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+	ret = devm_request_threaded_irq(dev, irq, NULL,
 					imx_tve_irq_handler, IRQF_ONESHOT,
 					"imx-tve", tve);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+		dev_err(dev, "failed to request irq: %d\n", ret);
 		return ret;
 	}
 
-	tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+	tve->dac_reg = devm_regulator_get(dev, "dac");
 	if (!IS_ERR(tve->dac_reg)) {
 		regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
 		ret = regulator_enable(tve->dac_reg);
@@ -667,17 +669,17 @@ static int imx_tve_probe(struct platform_device *pdev)
 			return ret;
 	}
 
-	tve->clk = devm_clk_get(&pdev->dev, "tve");
+	tve->clk = devm_clk_get(dev, "tve");
 	if (IS_ERR(tve->clk)) {
-		dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+		dev_err(dev, "failed to get high speed tve clock: %ld\n",
 			PTR_ERR(tve->clk));
 		return PTR_ERR(tve->clk);
 	}
 
 	/* this is the IPU DI clock input selector, can be parented to tve_di */
-	tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+	tve->di_sel_clk = devm_clk_get(dev, "di_sel");
 	if (IS_ERR(tve->di_sel_clk)) {
-		dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+		dev_err(dev, "failed to get ipu di mux clock: %ld\n",
 			PTR_ERR(tve->di_sel_clk));
 		return PTR_ERR(tve->di_sel_clk);
 	}
@@ -688,11 +690,11 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+		dev_err(dev, "failed to read configuration register: %d\n", ret);
 		return ret;
 	}
 	if (val != 0x00100000) {
-		dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+		dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
 		return -ENODEV;
 	}
 
@@ -705,14 +707,15 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, tve);
+	dev_set_drvdata(dev, tve);
 
 	return 0;
 }
 
-static int imx_tve_remove(struct platform_device *pdev)
+static void imx_tve_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_tve *tve = platform_get_drvdata(pdev);
+	struct imx_tve *tve = dev_get_drvdata(dev);
 	struct drm_connector *connector = &tve->connector;
 	struct drm_encoder *encoder = &tve->encoder;
 
@@ -723,7 +726,21 @@ static int imx_tve_remove(struct platform_device *pdev)
 
 	if (!IS_ERR(tve->dac_reg))
 		regulator_disable(tve->dac_reg);
+}
 
+static const struct component_ops imx_tve_ops = {
+	.bind	= imx_tve_bind,
+	.unbind	= imx_tve_unbind,
+};
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_tve_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 2bee6fa585f8..eb9653a5a887 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  * MA 02110-1301, USA.
  */
+#include <linux/component.h>
 #include <linux/module.h>
 #include <linux/export.h>
 #include <linux/device.h>
@@ -399,43 +400,60 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 	return ret;
 }
 
-static int ipu_drm_probe(struct platform_device *pdev)
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 {
-	struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
+	struct ipu_client_platformdata *pdata = dev->platform_data;
 	struct ipu_crtc *ipu_crtc;
 	int ret;
 
-	if (!pdata)
-		return -EINVAL;
-
-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+	ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
 	if (!ipu_crtc)
 		return -ENOMEM;
 
-	ipu_crtc->dev = &pdev->dev;
+	ipu_crtc->dev = dev;
 
 	ret = ipu_crtc_init(ipu_crtc, pdata);
 	if (ret)
 		return ret;
 
-	platform_set_drvdata(pdev, ipu_crtc);
+	dev_set_drvdata(dev, ipu_crtc);
 
 	return 0;
 }
 
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+	struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
 
 	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 
 	ipu_plane_put_resources(ipu_crtc->plane[0]);
 	ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+	.bind = ipu_drm_bind,
+	.unbind = ipu_drm_unbind,
+};
 
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!pdev->dev.platform_data)
+		return -EINVAL;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	return component_add(&pdev->dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ipu_crtc_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 9ba9ca1aeb67..110c0021a797 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -18,6 +18,7 @@
  * MA 02110-1301, USA.
  */
 
+#include <linux/component.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
@@ -191,15 +192,15 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
 	return 0;
 }
 
-static int imx_pd_probe(struct platform_device *pdev)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = dev->of_node;
 	const u8 *edidp;
 	struct imx_parallel_display *imxpd;
 	int ret;
 	const char *fmt;
 
-	imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+	imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
 	if (!imxpd)
 		return -ENOMEM;
 
@@ -217,7 +218,7 @@ static int imx_pd_probe(struct platform_device *pdev)
 			imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
 	}
 
-	imxpd->dev = &pdev->dev;
+	imxpd->dev = dev;
 
 	ret = imx_pd_register(imxpd);
 	if (ret)
@@ -225,14 +226,15 @@ static int imx_pd_probe(struct platform_device *pdev)
 
 	ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, imxpd);
+	dev_set_drvdata(dev, imxpd);
 
 	return 0;
 }
 
-static int imx_pd_remove(struct platform_device *pdev)
+static void imx_pd_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
+	struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
 	struct drm_connector *connector = &imxpd->connector;
 	struct drm_encoder *encoder = &imxpd->encoder;
 
@@ -240,7 +242,21 @@ static int imx_pd_remove(struct platform_device *pdev)
 
 	imx_drm_remove_connector(imxpd->imx_drm_connector);
 	imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+}
 
+static const struct component_ops imx_pd_ops = {
+	.bind	= imx_pd_bind,
+	.unbind	= imx_pd_unbind,
+};
+
+static int imx_pd_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_pd_ops);
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Use the componentised device support for imx-drm.  This requires all
the sub-components and the master device to register with the component
device support.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 arch/arm/boot/dts/imx51-babbage.dts        |   10 ++-
 arch/arm/boot/dts/imx53-m53evk.dts         |    8 ++-
 arch/arm/boot/dts/imx53-mba53.dts          |    6 ++
 arch/arm/boot/dts/imx53-qsb.dts            |    8 ++-
 arch/arm/boot/dts/imx6qdl-sabresd.dtsi     |    6 ++
 drivers/staging/imx-drm/imx-drm-core.c     |  105 ++++++++++++++++++++++-----
 drivers/staging/imx-drm/imx-ldb.c          |   40 ++++++++---
 drivers/staging/imx-drm/imx-tve.c          |   63 +++++++++++------
 drivers/staging/imx-drm/ipuv3-crtc.c       |   46 +++++++++----
 drivers/staging/imx-drm/parallel-display.c |   30 ++++++--
 10 files changed, 242 insertions(+), 80 deletions(-)

diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
index be1407cf5abd..6ff15a0eacb3 100644
--- a/arch/arm/boot/dts/imx51-babbage.dts
+++ b/arch/arm/boot/dts/imx51-babbage.dts
@@ -21,7 +21,7 @@
 		reg = <0x90000000 0x20000000>;
 	};
 
-	display@di0 {
+	display0: display@di0 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 0>;
 		interface-pix-fmt = "rgb24";
@@ -43,7 +43,7 @@
 		};
 	};
 
-	display@di1 {
+	display1: display@di1 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 1>;
 		interface-pix-fmt = "rgb565";
@@ -81,6 +81,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 0>, <&ipu 1>;
+		connectors = <&display0>, <&display1>;
+	};
+
 	sound {
 		compatible = "fsl,imx51-babbage-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
index 7d304d02ed38..ee6107b6484c 100644
--- a/arch/arm/boot/dts/imx53-m53evk.dts
+++ b/arch/arm/boot/dts/imx53-m53evk.dts
@@ -21,7 +21,7 @@
 	};
 
 	soc {
-		display@di1 {
+		display1: display@di1 {
 			compatible = "fsl,imx-parallel-display";
 			crtcs = <&ipu 1>;
 			interface-pix-fmt = "bgr666";
@@ -53,6 +53,12 @@
 		default-brightness-level = <6>;
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 1>;
+		connectors = <&display1>;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
index a63090267941..9b6e76980a74 100644
--- a/arch/arm/boot/dts/imx53-mba53.dts
+++ b/arch/arm/boot/dts/imx53-mba53.dts
@@ -43,6 +43,12 @@
 		status = "disabled";
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 1>;
+		connectors = <&disp1>, <&tve>;
+	};
+
 	reg_3p2v: 3p2v {
 		compatible = "regulator-fixed";
 		regulator-name = "3P2V";
diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts
index 91a5935a4aac..3cb4f7791a91 100644
--- a/arch/arm/boot/dts/imx53-qsb.dts
+++ b/arch/arm/boot/dts/imx53-qsb.dts
@@ -21,7 +21,7 @@
 		reg = <0x70000000 0x40000000>;
 	};
 
-	display@di0 {
+	display0: display@di0 {
 		compatible = "fsl,imx-parallel-display";
 		crtcs = <&ipu 0>;
 		interface-pix-fmt = "rgb565";
@@ -72,6 +72,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu 0>;
+		connectors = <&display0>;
+	};
+
 	leds {
 		compatible = "gpio-leds";
 		pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index e75e11b36dff..0e005f21d241 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -62,6 +62,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu1 0>, <&ipu1 1>;
+		connectors = <&ldb>;
+	};
+
 	sound {
 		compatible = "fsl,imx6q-sabresd-wm8962",
 			   "fsl,imx-audio-wm8962";
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 839dbb7c7b36..8ece15944569 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  *
  */
-
+#include <linux/component.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
@@ -90,6 +90,8 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+	component_unbind_all(drm->dev, drm);
+
 	imx_drm_device_put();
 
 	drm_vblank_cleanup(drm);
@@ -371,11 +373,8 @@ static void imx_drm_connector_unregister(
 }
 
 /*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
  */
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
@@ -427,8 +426,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	}
 
 	mutex_unlock(&imxdrm->mutex);
+
+	/* Now try and bind all our sub-components */
+	ret = component_bind_all(drm->dev, drm);
+	if (ret)
+		goto err_relock;
 	return 0;
 
+err_relock:
+	mutex_lock(&imxdrm->mutex);
 err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
@@ -808,6 +814,70 @@ static struct drm_driver imx_drm_driver = {
 	.patchlevel		= 0,
 };
 
+static int compare_parent_of(struct device *dev, void *data)
+{
+	struct of_phandle_args *args = data;
+	return dev->parent && dev->parent->of_node == args->np;
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+	return dev->of_node == data;
+}
+
+static int imx_drm_add_components(struct device *master, struct master *m)
+{
+	struct device_node *np = master->of_node;
+	unsigned i;
+	int ret;
+
+	for (i = 0; ; i++) {
+		struct of_phandle_args args;
+
+		ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
+						       i, &args);
+		if (ret)
+			break;
+
+		ret = component_master_add_child(m, compare_parent_of, &args);
+		of_node_put(args.np);
+
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; ; i++) {
+		struct device_node *node;
+
+		node = of_parse_phandle(np, "connectors", i);
+		if (!node)
+			break;
+
+		ret = component_master_add_child(m, compare_of, node);
+		of_node_put(node);
+
+		if (ret)
+			return ret;
+	}
+	return 0;
+}
+
+static int imx_drm_bind(struct device *dev)
+{
+	return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+	drm_platform_exit(&imx_drm_driver, to_platform_device(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+	.add_components = imx_drm_add_components,
+	.bind = imx_drm_bind,
+	.unbind = imx_drm_unbind,
+};
+
 static int imx_drm_platform_probe(struct platform_device *pdev)
 {
 	int ret;
@@ -818,27 +888,31 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 
 	imx_drm_device->dev = &pdev->dev;
 
-	return drm_platform_init(&imx_drm_driver, pdev);
+	return component_master_add(&pdev->dev, &imx_drm_ops);
 }
 
 static int imx_drm_platform_remove(struct platform_device *pdev)
 {
-	drm_platform_exit(&imx_drm_driver, pdev);
-
+	component_master_del(&pdev->dev, &imx_drm_ops);
 	return 0;
 }
 
+static const struct of_device_id imx_drm_dt_ids[] = {
+	{ .compatible = "fsl,imx-drm", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
 static struct platform_driver imx_drm_pdrv = {
 	.probe		= imx_drm_platform_probe,
 	.remove		= imx_drm_platform_remove,
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.name	= "imx-drm",
+		.of_match_table = imx_drm_dt_ids,
 	},
 };
 
-static struct platform_device *imx_drm_pdev;
-
 static int __init imx_drm_init(void)
 {
 	int ret;
@@ -851,12 +925,6 @@ static int __init imx_drm_init(void)
 	INIT_LIST_HEAD(&imx_drm_device->connector_list);
 	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
-	imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
-	if (IS_ERR(imx_drm_pdev)) {
-		ret = PTR_ERR(imx_drm_pdev);
-		goto err_pdev;
-	}
-
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
 		goto err_pdrv;
@@ -864,8 +932,6 @@ static int __init imx_drm_init(void)
 	return 0;
 
 err_pdrv:
-	platform_device_unregister(imx_drm_pdev);
-err_pdev:
 	kfree(imx_drm_device);
 
 	return ret;
@@ -873,7 +939,6 @@ static int __init imx_drm_init(void)
 
 static void __exit imx_drm_exit(void)
 {
-	platform_device_unregister(imx_drm_pdev);
 	platform_driver_unregister(&imx_drm_pdrv);
 
 	kfree(imx_drm_device);
diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 70455c4d7e48..5b71f49faa0a 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -20,6 +20,7 @@
 
 #include <linux/module.h>
 #include <linux/clk.h>
+#include <linux/component.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
@@ -451,11 +452,11 @@ static const struct of_device_id imx_ldb_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
-static int imx_ldb_probe(struct platform_device *pdev)
+static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = dev->of_node;
 	const struct of_device_id *of_id =
-			of_match_device(imx_ldb_dt_ids, &pdev->dev);
+			of_match_device(imx_ldb_dt_ids, dev);
 	struct device_node *child;
 	const u8 *edidp;
 	struct imx_ldb *imx_ldb;
@@ -465,17 +466,17 @@ static int imx_ldb_probe(struct platform_device *pdev)
 	int ret;
 	int i;
 
-	imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL);
+	imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL);
 	if (!imx_ldb)
 		return -ENOMEM;
 
 	imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
 	if (IS_ERR(imx_ldb->regmap)) {
-		dev_err(&pdev->dev, "failed to get parent regmap\n");
+		dev_err(dev, "failed to get parent regmap\n");
 		return PTR_ERR(imx_ldb->regmap);
 	}
 
-	imx_ldb->dev = &pdev->dev;
+	imx_ldb->dev = dev;
 
 	if (of_id)
 		imx_ldb->lvds_mux = of_id->data;
@@ -513,7 +514,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 			return -EINVAL;
 
 		if (dual && i > 0) {
-			dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n");
+			dev_warn(dev, "dual-channel mode, ignoring second output\n");
 			continue;
 		}
 
@@ -552,7 +553,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 			break;
 		case LVDS_BIT_MAP_JEIDA:
 			if (datawidth == 18) {
-				dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n");
+				dev_err(dev, "JEIDA standard only supported in 24 bit\n");
 				return -EINVAL;
 			}
 			if (i == 0 || dual)
@@ -561,7 +562,7 @@ static int imx_ldb_probe(struct platform_device *pdev)
 				imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA;
 			break;
 		default:
-			dev_err(&pdev->dev, "data mapping not specified or invalid\n");
+			dev_err(dev, "data mapping not specified or invalid\n");
 			return -EINVAL;
 		}
 
@@ -572,14 +573,15 @@ static int imx_ldb_probe(struct platform_device *pdev)
 		imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
 	}
 
-	platform_set_drvdata(pdev, imx_ldb);
+	dev_set_drvdata(dev, imx_ldb);
 
 	return 0;
 }
 
-static int imx_ldb_remove(struct platform_device *pdev)
+static void imx_ldb_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_ldb *imx_ldb = platform_get_drvdata(pdev);
+	struct imx_ldb *imx_ldb = dev_get_drvdata(dev);
 	int i;
 
 	for (i = 0; i < 2; i++) {
@@ -592,7 +594,21 @@ static int imx_ldb_remove(struct platform_device *pdev)
 		imx_drm_remove_connector(channel->imx_drm_connector);
 		imx_drm_remove_encoder(channel->imx_drm_encoder);
 	}
+}
 
+static const struct component_ops imx_ldb_ops = {
+	.bind	= imx_ldb_bind,
+	.unbind	= imx_ldb_unbind,
+};
+
+static int imx_ldb_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_ldb_ops);
+}
+
+static int imx_ldb_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_ldb_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index b2f214971501..f8720f1ef86e 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -20,6 +20,7 @@
 
 #include <linux/clk.h>
 #include <linux/clk-provider.h>
+#include <linux/component.h>
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/regmap.h>
@@ -583,9 +584,10 @@ const int of_get_tve_mode(struct device_node *np)
 	return -EINVAL;
 }
 
-static int imx_tve_probe(struct platform_device *pdev)
+static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_tve *tve;
 	struct resource *res;
@@ -594,11 +596,11 @@ static int imx_tve_probe(struct platform_device *pdev)
 	int irq;
 	int ret;
 
-	tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL);
+	tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL);
 	if (!tve)
 		return -ENOMEM;
 
-	tve->dev = &pdev->dev;
+	tve->dev = dev;
 	spin_lock_init(&tve->lock);
 
 	ddc_node = of_parse_phandle(np, "ddc", 0);
@@ -609,7 +611,7 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	tve->mode = of_get_tve_mode(np);
 	if (tve->mode != TVE_MODE_VGA) {
-		dev_err(&pdev->dev, "only VGA mode supported, currently\n");
+		dev_err(dev, "only VGA mode supported, currently\n");
 		return -EINVAL;
 	}
 
@@ -618,7 +620,7 @@ static int imx_tve_probe(struct platform_device *pdev)
 					   &tve->hsync_pin);
 
 		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to get vsync pin\n");
+			dev_err(dev, "failed to get vsync pin\n");
 			return ret;
 		}
 
@@ -626,40 +628,40 @@ static int imx_tve_probe(struct platform_device *pdev)
 					    &tve->vsync_pin);
 
 		if (ret < 0) {
-			dev_err(&pdev->dev, "failed to get vsync pin\n");
+			dev_err(dev, "failed to get vsync pin\n");
 			return ret;
 		}
 	}
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	base = devm_ioremap_resource(&pdev->dev, res);
+	base = devm_ioremap_resource(dev, res);
 	if (IS_ERR(base))
 		return PTR_ERR(base);
 
 	tve_regmap_config.lock_arg = tve;
-	tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base,
+	tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base,
 						&tve_regmap_config);
 	if (IS_ERR(tve->regmap)) {
-		dev_err(&pdev->dev, "failed to init regmap: %ld\n",
+		dev_err(dev, "failed to init regmap: %ld\n",
 			PTR_ERR(tve->regmap));
 		return PTR_ERR(tve->regmap);
 	}
 
 	irq = platform_get_irq(pdev, 0);
 	if (irq < 0) {
-		dev_err(&pdev->dev, "failed to get irq\n");
+		dev_err(dev, "failed to get irq\n");
 		return irq;
 	}
 
-	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+	ret = devm_request_threaded_irq(dev, irq, NULL,
 					imx_tve_irq_handler, IRQF_ONESHOT,
 					"imx-tve", tve);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+		dev_err(dev, "failed to request irq: %d\n", ret);
 		return ret;
 	}
 
-	tve->dac_reg = devm_regulator_get(&pdev->dev, "dac");
+	tve->dac_reg = devm_regulator_get(dev, "dac");
 	if (!IS_ERR(tve->dac_reg)) {
 		regulator_set_voltage(tve->dac_reg, 2750000, 2750000);
 		ret = regulator_enable(tve->dac_reg);
@@ -667,17 +669,17 @@ static int imx_tve_probe(struct platform_device *pdev)
 			return ret;
 	}
 
-	tve->clk = devm_clk_get(&pdev->dev, "tve");
+	tve->clk = devm_clk_get(dev, "tve");
 	if (IS_ERR(tve->clk)) {
-		dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n",
+		dev_err(dev, "failed to get high speed tve clock: %ld\n",
 			PTR_ERR(tve->clk));
 		return PTR_ERR(tve->clk);
 	}
 
 	/* this is the IPU DI clock input selector, can be parented to tve_di */
-	tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel");
+	tve->di_sel_clk = devm_clk_get(dev, "di_sel");
 	if (IS_ERR(tve->di_sel_clk)) {
-		dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n",
+		dev_err(dev, "failed to get ipu di mux clock: %ld\n",
 			PTR_ERR(tve->di_sel_clk));
 		return PTR_ERR(tve->di_sel_clk);
 	}
@@ -688,11 +690,11 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret);
+		dev_err(dev, "failed to read configuration register: %d\n", ret);
 		return ret;
 	}
 	if (val != 0x00100000) {
-		dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n");
+		dev_err(dev, "configuration register default value indicates this is not a TVEv2\n");
 		return -ENODEV;
 	}
 
@@ -705,14 +707,15 @@ static int imx_tve_probe(struct platform_device *pdev)
 
 	ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, tve);
+	dev_set_drvdata(dev, tve);
 
 	return 0;
 }
 
-static int imx_tve_remove(struct platform_device *pdev)
+static void imx_tve_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_tve *tve = platform_get_drvdata(pdev);
+	struct imx_tve *tve = dev_get_drvdata(dev);
 	struct drm_connector *connector = &tve->connector;
 	struct drm_encoder *encoder = &tve->encoder;
 
@@ -723,7 +726,21 @@ static int imx_tve_remove(struct platform_device *pdev)
 
 	if (!IS_ERR(tve->dac_reg))
 		regulator_disable(tve->dac_reg);
+}
 
+static const struct component_ops imx_tve_ops = {
+	.bind	= imx_tve_bind,
+	.unbind	= imx_tve_unbind,
+};
+
+static int imx_tve_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_tve_ops);
+}
+
+static int imx_tve_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_tve_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index 2bee6fa585f8..eb9653a5a887 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -17,6 +17,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  * MA 02110-1301, USA.
  */
+#include <linux/component.h>
 #include <linux/module.h>
 #include <linux/export.h>
 #include <linux/device.h>
@@ -399,43 +400,60 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 	return ret;
 }
 
-static int ipu_drm_probe(struct platform_device *pdev)
+static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 {
-	struct ipu_client_platformdata *pdata = pdev->dev.platform_data;
+	struct ipu_client_platformdata *pdata = dev->platform_data;
 	struct ipu_crtc *ipu_crtc;
 	int ret;
 
-	if (!pdata)
-		return -EINVAL;
-
-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
-	if (ret)
-		return ret;
-
-	ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL);
+	ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL);
 	if (!ipu_crtc)
 		return -ENOMEM;
 
-	ipu_crtc->dev = &pdev->dev;
+	ipu_crtc->dev = dev;
 
 	ret = ipu_crtc_init(ipu_crtc, pdata);
 	if (ret)
 		return ret;
 
-	platform_set_drvdata(pdev, ipu_crtc);
+	dev_set_drvdata(dev, ipu_crtc);
 
 	return 0;
 }
 
-static int ipu_drm_remove(struct platform_device *pdev)
+static void ipu_drm_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev);
+	struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev);
 
 	imx_drm_remove_crtc(ipu_crtc->imx_crtc);
 
 	ipu_plane_put_resources(ipu_crtc->plane[0]);
 	ipu_put_resources(ipu_crtc);
+}
+
+static const struct component_ops ipu_crtc_ops = {
+	.bind = ipu_drm_bind,
+	.unbind = ipu_drm_unbind,
+};
 
+static int ipu_drm_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!pdev->dev.platform_data)
+		return -EINVAL;
+
+	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+	if (ret)
+		return ret;
+
+	return component_add(&pdev->dev, &ipu_crtc_ops);
+}
+
+static int ipu_drm_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &ipu_crtc_ops);
 	return 0;
 }
 
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 9ba9ca1aeb67..110c0021a797 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -18,6 +18,7 @@
  * MA 02110-1301, USA.
  */
 
+#include <linux/component.h>
 #include <linux/module.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
@@ -191,15 +192,15 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
 	return 0;
 }
 
-static int imx_pd_probe(struct platform_device *pdev)
+static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 {
-	struct device_node *np = pdev->dev.of_node;
+	struct device_node *np = dev->of_node;
 	const u8 *edidp;
 	struct imx_parallel_display *imxpd;
 	int ret;
 	const char *fmt;
 
-	imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
+	imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
 	if (!imxpd)
 		return -ENOMEM;
 
@@ -217,7 +218,7 @@ static int imx_pd_probe(struct platform_device *pdev)
 			imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
 	}
 
-	imxpd->dev = &pdev->dev;
+	imxpd->dev = dev;
 
 	ret = imx_pd_register(imxpd);
 	if (ret)
@@ -225,14 +226,15 @@ static int imx_pd_probe(struct platform_device *pdev)
 
 	ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, imxpd);
+	dev_set_drvdata(dev, imxpd);
 
 	return 0;
 }
 
-static int imx_pd_remove(struct platform_device *pdev)
+static void imx_pd_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_parallel_display *imxpd = platform_get_drvdata(pdev);
+	struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
 	struct drm_connector *connector = &imxpd->connector;
 	struct drm_encoder *encoder = &imxpd->encoder;
 
@@ -240,7 +242,21 @@ static int imx_pd_remove(struct platform_device *pdev)
 
 	imx_drm_remove_connector(imxpd->imx_drm_connector);
 	imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+}
 
+static const struct component_ops imx_pd_ops = {
+	.bind	= imx_pd_bind,
+	.unbind	= imx_pd_unbind,
+};
+
+static int imx_pd_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &imx_pd_ops);
+}
+
+static int imx_pd_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &imx_pd_ops);
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 28/46] imx-drm: imx-hdmi: convert to a component device
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Convert imx-hdmi to be a component device; it will bind and unbind
at the appropriate moment in the main DRM driver's functions.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   41 +++++++++++++++++++++++++----------
 1 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 0e5e7a6f6168..d81940a8904f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -12,6 +12,7 @@
  * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  */
 
+#include <linux/component.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -1586,21 +1587,22 @@ static const struct of_device_id imx_hdmi_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
 
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	const struct of_device_id *of_id =
-				of_match_device(imx_hdmi_dt_ids, &pdev->dev);
-	struct device_node *np = pdev->dev.of_node;
+				of_match_device(imx_hdmi_dt_ids, dev);
+	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
 	int ret, irq;
 
-	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
 		return -ENOMEM;
 
-	hdmi->dev = &pdev->dev;
+	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
@@ -1624,13 +1626,13 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return -EINVAL;
 
-	ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
-			       dev_name(&pdev->dev), hdmi);
+	ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
+			       dev_name(dev), hdmi);
 	if (ret)
 		return ret;
 
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+	hdmi->regs = devm_ioremap_resource(dev, iores);
 	if (IS_ERR(hdmi->regs))
 		return PTR_ERR(hdmi->regs);
 
@@ -1669,7 +1671,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	}
 
 	/* Product and revision IDs */
-	dev_info(&pdev->dev,
+	dev_info(dev,
 		"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
 		hdmi_readb(hdmi, HDMI_DESIGN_ID),
 		hdmi_readb(hdmi, HDMI_REVISION_ID),
@@ -1703,7 +1705,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 
 	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, hdmi);
+	dev_set_drvdata(dev, hdmi);
 
 	return 0;
 
@@ -1715,9 +1717,10 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 	struct drm_connector *connector = &hdmi->connector;
 	struct drm_encoder *encoder = &hdmi->encoder;
 
@@ -1728,7 +1731,21 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
 	i2c_put_adapter(hdmi->ddc);
+}
 
+static const struct component_ops hdmi_ops = {
+	.bind	= imx_hdmi_bind,
+	.unbind	= imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &hdmi_ops);
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &hdmi_ops);
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 28/46] imx-drm: imx-hdmi: convert to a component device
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Convert imx-hdmi to be a component device; it will bind and unbind
at the appropriate moment in the main DRM driver's functions.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   41 +++++++++++++++++++++++++----------
 1 files changed, 29 insertions(+), 12 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 0e5e7a6f6168..d81940a8904f 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -12,6 +12,7 @@
  * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
  */
 
+#include <linux/component.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/err.h>
@@ -1586,21 +1587,22 @@ static const struct of_device_id imx_hdmi_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
 
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
+static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 {
+	struct platform_device *pdev = to_platform_device(dev);
 	const struct of_device_id *of_id =
-				of_match_device(imx_hdmi_dt_ids, &pdev->dev);
-	struct device_node *np = pdev->dev.of_node;
+				of_match_device(imx_hdmi_dt_ids, dev);
+	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
 	int ret, irq;
 
-	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
 	if (!hdmi)
 		return -ENOMEM;
 
-	hdmi->dev = &pdev->dev;
+	hdmi->dev = dev;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
@@ -1624,13 +1626,13 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	if (irq < 0)
 		return -EINVAL;
 
-	ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
-			       dev_name(&pdev->dev), hdmi);
+	ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
+			       dev_name(dev), hdmi);
 	if (ret)
 		return ret;
 
 	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+	hdmi->regs = devm_ioremap_resource(dev, iores);
 	if (IS_ERR(hdmi->regs))
 		return PTR_ERR(hdmi->regs);
 
@@ -1669,7 +1671,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	}
 
 	/* Product and revision IDs */
-	dev_info(&pdev->dev,
+	dev_info(dev,
 		"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
 		hdmi_readb(hdmi, HDMI_DESIGN_ID),
 		hdmi_readb(hdmi, HDMI_REVISION_ID),
@@ -1703,7 +1705,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 
 	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
 
-	platform_set_drvdata(pdev, hdmi);
+	dev_set_drvdata(dev, hdmi);
 
 	return 0;
 
@@ -1715,9 +1717,10 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
+static void imx_hdmi_unbind(struct device *dev, struct device *master,
+	void *data)
 {
-	struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 	struct drm_connector *connector = &hdmi->connector;
 	struct drm_encoder *encoder = &hdmi->encoder;
 
@@ -1728,7 +1731,21 @@ static int imx_hdmi_platform_remove(struct platform_device *pdev)
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
 	i2c_put_adapter(hdmi->ddc);
+}
 
+static const struct component_ops hdmi_ops = {
+	.bind	= imx_hdmi_bind,
+	.unbind	= imx_hdmi_unbind,
+};
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+	return component_add(&pdev->dev, &hdmi_ops);
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &hdmi_ops);
 	return 0;
 }
 
-- 
1.7.4.4

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

* [PATCH RFC 29/46] imx-drm: delay publishing sysfs connector entries
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Delay publishing sysfs connector entries until all components have
initialised.  This reduces the probability of generating false hotplug
events when we're uncertain whether the driver can fully initialise.
This also pulls that code out of the individual imx-drm connector
drivers.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8ece15944569..d5bf4a4646a3 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -355,7 +355,7 @@ static int imx_drm_connector_register(
 			imx_drm_connector->connector->connector_type);
 	drm_mode_group_reinit(imxdrm->drm);
 
-	return drm_sysfs_connector_add(imx_drm_connector->connector);
+	return 0;
 }
 
 /*
@@ -379,6 +379,7 @@ static void imx_drm_connector_unregister(
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct drm_connector *connector;
 	int ret;
 
 	imxdrm->drm = drm;
@@ -431,8 +432,27 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	ret = component_bind_all(drm->dev, drm);
 	if (ret)
 		goto err_relock;
+
+	/*
+	 * All components are now added, we can publish the connector sysfs
+	 * entries to userspace.  This will generate hotplug events and so
+	 * userspace will expect to be able to access DRM at this point.
+	 */
+	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+		ret = drm_sysfs_connector_add(connector);
+		if (ret) {
+			dev_err(drm->dev,
+				"[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
+				connector->base.id,
+				drm_get_connector_name(connector), ret);
+			goto err_unbind;
+		}
+	}
+
 	return 0;
 
+err_unbind:
+	component_unbind_all(drm->dev, drm);
 err_relock:
 	mutex_lock(&imxdrm->mutex);
 err_vblank:
-- 
1.7.4.4

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

* [PATCH RFC 29/46] imx-drm: delay publishing sysfs connector entries
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Delay publishing sysfs connector entries until all components have
initialised.  This reduces the probability of generating false hotplug
events when we're uncertain whether the driver can fully initialise.
This also pulls that code out of the individual imx-drm connector
drivers.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   22 +++++++++++++++++++++-
 1 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8ece15944569..d5bf4a4646a3 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -355,7 +355,7 @@ static int imx_drm_connector_register(
 			imx_drm_connector->connector->connector_type);
 	drm_mode_group_reinit(imxdrm->drm);
 
-	return drm_sysfs_connector_add(imx_drm_connector->connector);
+	return 0;
 }
 
 /*
@@ -379,6 +379,7 @@ static void imx_drm_connector_unregister(
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct drm_connector *connector;
 	int ret;
 
 	imxdrm->drm = drm;
@@ -431,8 +432,27 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	ret = component_bind_all(drm->dev, drm);
 	if (ret)
 		goto err_relock;
+
+	/*
+	 * All components are now added, we can publish the connector sysfs
+	 * entries to userspace.  This will generate hotplug events and so
+	 * userspace will expect to be able to access DRM at this point.
+	 */
+	list_for_each_entry(connector, &drm->mode_config.connector_list, head) {
+		ret = drm_sysfs_connector_add(connector);
+		if (ret) {
+			dev_err(drm->dev,
+				"[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n",
+				connector->base.id,
+				drm_get_connector_name(connector), ret);
+			goto err_unbind;
+		}
+	}
+
 	return 0;
 
+err_unbind:
+	component_unbind_all(drm->dev, drm);
 err_relock:
 	mutex_lock(&imxdrm->mutex);
 err_vblank:
-- 
1.7.4.4

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

* [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we know when the components of the imx-drm subsystem will be
initialised, we can move the fbdev helper initialisation and teardown
into imx-drm-core.  This gives us the required ordering that DRM wants
in both driver load and unload methods.

We can also stop exporting the imx_drm_device_get() and
imx_drm_device_put() methods; nothing but the fbdev helper was making
use of these.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile       |    1 -
 drivers/staging/imx-drm/imx-drm-core.c |   43 +++++++++++++-----
 drivers/staging/imx-drm/imx-drm.h      |    3 -
 drivers/staging/imx-drm/imx-fbdev.c    |   74 --------------------------------
 4 files changed, 31 insertions(+), 90 deletions(-)
 delete mode 100644 drivers/staging/imx-drm/imx-fbdev.c

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 4677585b5ad5..5239f908ceec 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_DRM_IMX) += imxdrm.o
 obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
 obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
 obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d5bf4a4646a3..31bc8d9c49be 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -70,6 +70,10 @@ struct imx_drm_connector {
 	struct module				*owner;
 };
 
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
+
+static void imx_drm_device_put(void);
 static struct imx_drm_device *__imx_drm_device(void);
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
@@ -82,14 +86,21 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
 }
 
 static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (imxdrm->fbhelper)
+		drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
 	component_unbind_all(drm->dev, drm);
 
 	imx_drm_device_put();
@@ -225,7 +236,7 @@ static struct imx_drm_device *__imx_drm_device(void)
 	return imx_drm_device;
 }
 
-struct drm_device *imx_drm_device_get(void)
+static struct drm_device *imx_drm_device_get(void)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
@@ -273,9 +284,8 @@ struct drm_device *imx_drm_device_get(void)
 	return NULL;
 
 }
-EXPORT_SYMBOL_GPL(imx_drm_device_get);
 
-void imx_drm_device_put(void)
+static void imx_drm_device_put(void)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
@@ -295,7 +305,6 @@ void imx_drm_device_put(void)
 
 	mutex_unlock(&imxdrm->mutex);
 }
-EXPORT_SYMBOL_GPL(imx_drm_device_put);
 
 static int drm_mode_group_reinit(struct drm_device *dev)
 {
@@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		}
 	}
 
+	/*
+	 * All components are now initialised, so setup the fb helper.
+	 * The fb helper takes copies of key hardware information, so the
+	 * crtcs/connectors/encoders must not change after this point.
+	 */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
+		legacyfb_depth = 16;
+	}
+	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+				drm->mode_config.num_crtc, 4);
+	if (IS_ERR(imxdrm->fbhelper)) {
+		ret = PTR_ERR(imxdrm->fbhelper);
+		imxdrm->fbhelper = NULL;
+		goto err_unbind;
+	}
+#endif
 	return 0;
 
 err_unbind:
@@ -766,14 +793,6 @@ int imx_drm_add_connector(struct drm_connector *connector,
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_connector);
 
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	imxdrm->fbhelper = fbdev_helper;
-}
-EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
-
 /*
  * imx_drm_remove_connector - remove a connector
  */
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index e3ca0c6b6a39..d1fb1146240e 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -54,13 +54,10 @@ void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
 
-struct drm_device *imx_drm_device_get(void);
-void imx_drm_device_put(void);
 int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
 int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
 struct device_node;
 
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
deleted file mode 100644
index 8331739c3d08..000000000000
--- a/drivers/staging/imx-drm/imx-fbdev.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
- * 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.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CONNECTOR		4
-#define PREFERRED_BPP		16
-
-static struct drm_fbdev_cma *fbdev_cma;
-
-static int legacyfb_depth = 16;
-
-module_param(legacyfb_depth, int, 0444);
-
-static int __init imx_fb_helper_init(void)
-{
-	struct drm_device *drm = imx_drm_device_get();
-
-	if (!drm)
-		return -EINVAL;
-
-	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
-		pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
-		legacyfb_depth = 16;
-	}
-
-	fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
-			drm->mode_config.num_crtc, MAX_CONNECTOR);
-
-	if (IS_ERR(fbdev_cma)) {
-		imx_drm_device_put();
-		return PTR_ERR(fbdev_cma);
-	}
-
-	imx_drm_fb_helper_set(fbdev_cma);
-
-	return 0;
-}
-
-static void __exit imx_fb_helper_exit(void)
-{
-	imx_drm_fb_helper_set(NULL);
-	drm_fbdev_cma_fini(fbdev_cma);
-	imx_drm_device_put();
-}
-
-late_initcall(imx_fb_helper_init);
-module_exit(imx_fb_helper_exit);
-
-MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-- 
1.7.4.4

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

* [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Now that we know when the components of the imx-drm subsystem will be
initialised, we can move the fbdev helper initialisation and teardown
into imx-drm-core.  This gives us the required ordering that DRM wants
in both driver load and unload methods.

We can also stop exporting the imx_drm_device_get() and
imx_drm_device_put() methods; nothing but the fbdev helper was making
use of these.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile       |    1 -
 drivers/staging/imx-drm/imx-drm-core.c |   43 +++++++++++++-----
 drivers/staging/imx-drm/imx-drm.h      |    3 -
 drivers/staging/imx-drm/imx-fbdev.c    |   74 --------------------------------
 4 files changed, 31 insertions(+), 90 deletions(-)
 delete mode 100644 drivers/staging/imx-drm/imx-fbdev.c

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 4677585b5ad5..5239f908ceec 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_DRM_IMX) += imxdrm.o
 obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o
 obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o
 obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
-obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o
 obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index d5bf4a4646a3..31bc8d9c49be 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -70,6 +70,10 @@ struct imx_drm_connector {
 	struct module				*owner;
 };
 
+static int legacyfb_depth = 16;
+module_param(legacyfb_depth, int, 0444);
+
+static void imx_drm_device_put(void);
 static struct imx_drm_device *__imx_drm_device(void);
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
@@ -82,14 +86,21 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+#endif
 }
 
 static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (imxdrm->fbhelper)
+		drm_fbdev_cma_fini(imxdrm->fbhelper);
+#endif
+
 	component_unbind_all(drm->dev, drm);
 
 	imx_drm_device_put();
@@ -225,7 +236,7 @@ static struct imx_drm_device *__imx_drm_device(void)
 	return imx_drm_device;
 }
 
-struct drm_device *imx_drm_device_get(void)
+static struct drm_device *imx_drm_device_get(void)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
@@ -273,9 +284,8 @@ struct drm_device *imx_drm_device_get(void)
 	return NULL;
 
 }
-EXPORT_SYMBOL_GPL(imx_drm_device_get);
 
-void imx_drm_device_put(void)
+static void imx_drm_device_put(void)
 {
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
@@ -295,7 +305,6 @@ void imx_drm_device_put(void)
 
 	mutex_unlock(&imxdrm->mutex);
 }
-EXPORT_SYMBOL_GPL(imx_drm_device_put);
 
 static int drm_mode_group_reinit(struct drm_device *dev)
 {
@@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		}
 	}
 
+	/*
+	 * All components are now initialised, so setup the fb helper.
+	 * The fb helper takes copies of key hardware information, so the
+	 * crtcs/connectors/encoders must not change after this point.
+	 */
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
+		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
+		legacyfb_depth = 16;
+	}
+	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
+				drm->mode_config.num_crtc, 4);
+	if (IS_ERR(imxdrm->fbhelper)) {
+		ret = PTR_ERR(imxdrm->fbhelper);
+		imxdrm->fbhelper = NULL;
+		goto err_unbind;
+	}
+#endif
 	return 0;
 
 err_unbind:
@@ -766,14 +793,6 @@ int imx_drm_add_connector(struct drm_connector *connector,
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_connector);
 
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	imxdrm->fbhelper = fbdev_helper;
-}
-EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set);
-
 /*
  * imx_drm_remove_connector - remove a connector
  */
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index e3ca0c6b6a39..d1fb1146240e 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -54,13 +54,10 @@ void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
 
-struct drm_device *imx_drm_device_get(void);
-void imx_drm_device_put(void);
 int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 		u32 interface_pix_fmt, int hsync_pin, int vsync_pin);
 int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
-void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper);
 
 struct device_node;
 
diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c
deleted file mode 100644
index 8331739c3d08..000000000000
--- a/drivers/staging/imx-drm/imx-fbdev.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
- * 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.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-#define MAX_CONNECTOR		4
-#define PREFERRED_BPP		16
-
-static struct drm_fbdev_cma *fbdev_cma;
-
-static int legacyfb_depth = 16;
-
-module_param(legacyfb_depth, int, 0444);
-
-static int __init imx_fb_helper_init(void)
-{
-	struct drm_device *drm = imx_drm_device_get();
-
-	if (!drm)
-		return -EINVAL;
-
-	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
-		pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n");
-		legacyfb_depth = 16;
-	}
-
-	fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth,
-			drm->mode_config.num_crtc, MAX_CONNECTOR);
-
-	if (IS_ERR(fbdev_cma)) {
-		imx_drm_device_put();
-		return PTR_ERR(fbdev_cma);
-	}
-
-	imx_drm_fb_helper_set(fbdev_cma);
-
-	return 0;
-}
-
-static void __exit imx_fb_helper_exit(void)
-{
-	imx_drm_fb_helper_set(NULL);
-	drm_fbdev_cma_fini(fbdev_cma);
-	imx_drm_device_put();
-}
-
-late_initcall(imx_fb_helper_init);
-module_exit(imx_fb_helper_exit);
-
-MODULE_DESCRIPTION("Freescale i.MX legacy fb driver");
-MODULE_AUTHOR("Sascha Hauer, Pengutronix");
-MODULE_LICENSE("GPL");
-- 
1.7.4.4

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

* [PATCH RFC 31/46] imx-drm: remove imx-fb.c
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

imx-fb.c doesn't need to be separate from imx-drm-core.c - all it is
doing is setting up the minimum and maximum sizes of the scanout
buffers, and setting up the mode_config function pointers.  Move the
contents into imx-drm-core.c and kill this file.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile       |    2 +-
 drivers/staging/imx-drm/imx-drm-core.c |   16 ++++++++++-
 drivers/staging/imx-drm/imx-fb.c       |   47 --------------------------------
 3 files changed, 16 insertions(+), 49 deletions(-)
 delete mode 100644 drivers/staging/imx-drm/imx-fb.c

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 5239f908ceec..129e3a3f59f1 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,5 @@
 
-imxdrm-objs := imx-drm-core.o imx-fb.o
+imxdrm-objs := imx-drm-core.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 31bc8d9c49be..08e7837d6134 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -381,6 +381,10 @@ static void imx_drm_connector_unregister(
 	drm_mode_group_reinit(imxdrm->drm);
 }
 
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+};
+
 /*
  * Main DRM initialisation. This binds, initialises and registers
  * with DRM the subcomponents of the driver.
@@ -406,8 +410,18 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->irq_enabled = true;
 
+	/*
+	 * set max width and height as default value(4096x4096).
+	 * this value would be used to check framebuffer size limitation
+	 * at drm_mode_addfb().
+	 */
+	drm->mode_config.min_width = 64;
+	drm->mode_config.min_height = 64;
+	drm->mode_config.max_width = 4096;
+	drm->mode_config.max_height = 4096;
+	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+
 	drm_mode_config_init(drm);
-	imx_drm_mode_config_init(drm);
 
 	mutex_lock(&imxdrm->mutex);
 
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
deleted file mode 100644
index 03a7b4e14f67..000000000000
--- a/drivers/staging/imx-drm/imx-fb.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
- * 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.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
-	.fb_create = drm_fb_cma_create,
-};
-
-void imx_drm_mode_config_init(struct drm_device *dev)
-{
-	dev->mode_config.min_width = 64;
-	dev->mode_config.min_height = 64;
-
-	/*
-	 * set max width and height as default value(4096x4096).
-	 * this value would be used to check framebuffer size limitation
-	 * at drm_mode_addfb().
-	 */
-	dev->mode_config.max_width = 4096;
-	dev->mode_config.max_height = 4096;
-
-	dev->mode_config.funcs = &imx_drm_mode_config_funcs;
-}
-- 
1.7.4.4

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

* [PATCH RFC 31/46] imx-drm: remove imx-fb.c
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

imx-fb.c doesn't need to be separate from imx-drm-core.c - all it is
doing is setting up the minimum and maximum sizes of the scanout
buffers, and setting up the mode_config function pointers.  Move the
contents into imx-drm-core.c and kill this file.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile       |    2 +-
 drivers/staging/imx-drm/imx-drm-core.c |   16 ++++++++++-
 drivers/staging/imx-drm/imx-fb.c       |   47 --------------------------------
 3 files changed, 16 insertions(+), 49 deletions(-)
 delete mode 100644 drivers/staging/imx-drm/imx-fb.c

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 5239f908ceec..129e3a3f59f1 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,5 @@
 
-imxdrm-objs := imx-drm-core.o imx-fb.o
+imxdrm-objs := imx-drm-core.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 31bc8d9c49be..08e7837d6134 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -381,6 +381,10 @@ static void imx_drm_connector_unregister(
 	drm_mode_group_reinit(imxdrm->drm);
 }
 
+static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
+	.fb_create = drm_fb_cma_create,
+};
+
 /*
  * Main DRM initialisation. This binds, initialises and registers
  * with DRM the subcomponents of the driver.
@@ -406,8 +410,18 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->irq_enabled = true;
 
+	/*
+	 * set max width and height as default value(4096x4096).
+	 * this value would be used to check framebuffer size limitation
+	 * at drm_mode_addfb().
+	 */
+	drm->mode_config.min_width = 64;
+	drm->mode_config.min_height = 64;
+	drm->mode_config.max_width = 4096;
+	drm->mode_config.max_height = 4096;
+	drm->mode_config.funcs = &imx_drm_mode_config_funcs;
+
 	drm_mode_config_init(drm);
-	imx_drm_mode_config_init(drm);
 
 	mutex_lock(&imxdrm->mutex);
 
diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c
deleted file mode 100644
index 03a7b4e14f67..000000000000
--- a/drivers/staging/imx-drm/imx-fb.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * i.MX drm driver
- *
- * Copyright (C) 2012 Sascha Hauer, Pengutronix
- *
- * Based on Samsung Exynos code
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- *
- * 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.
- * 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.
- *
- */
-#include <linux/module.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_gem_cma_helper.h>
-#include <drm/drm_fb_cma_helper.h>
-
-#include "imx-drm.h"
-
-static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
-	.fb_create = drm_fb_cma_create,
-};
-
-void imx_drm_mode_config_init(struct drm_device *dev)
-{
-	dev->mode_config.min_width = 64;
-	dev->mode_config.min_height = 64;
-
-	/*
-	 * set max width and height as default value(4096x4096).
-	 * this value would be used to check framebuffer size limitation
-	 * at drm_mode_addfb().
-	 */
-	dev->mode_config.max_width = 4096;
-	dev->mode_config.max_height = 4096;
-
-	dev->mode_config.funcs = &imx_drm_mode_config_funcs;
-}
-- 
1.7.4.4

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

* [PATCH RFC 32/46] imx-drm: use supplied drm_device where possible
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

The component helper provides us the drm_device which is being
registered.  Rather than having to reference a global in imx-drm-core,
use this to get the imxdrm device, and also use it to register the CRTC
against.

This means we never have CRTCs/encoders/connectors without the drivers
private data being accessible.

Remove the module owner field as well; this provides no protection
against the device being unbound.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   34 ++++---------------------------
 drivers/staging/imx-drm/imx-drm.h      |    4 +-
 drivers/staging/imx-drm/ipuv3-crtc.c   |    9 ++++---
 3 files changed, 12 insertions(+), 35 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 08e7837d6134..b11568d6444b 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -52,7 +52,6 @@ struct imx_drm_crtc {
 	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
-	struct module				*owner;
 	struct crtc_cookie			cookie;
 	int					mux_id;
 };
@@ -74,7 +73,6 @@ static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 
 static void imx_drm_device_put(void);
-static struct imx_drm_device *__imx_drm_device(void);
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
@@ -114,7 +112,7 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
 	unsigned i;
 
 	for (i = 0; i < MAX_CRTC; i++)
@@ -241,7 +239,6 @@ static struct drm_device *imx_drm_device_get(void)
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
 	struct imx_drm_connector *con;
-	struct imx_drm_crtc *crtc;
 
 	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
 		if (!try_module_get(enc->owner)) {
@@ -259,19 +256,8 @@ static struct drm_device *imx_drm_device_get(void)
 		}
 	}
 
-	list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
-		if (!try_module_get(crtc->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(crtc->owner));
-			goto unwind_crtc;
-		}
-	}
-
 	return imxdrm->drm;
 
-unwind_crtc:
-	list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
-		module_put(crtc->owner);
 unwind_con:
 	list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
 		module_put(con->owner);
@@ -290,13 +276,9 @@ static void imx_drm_device_put(void)
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
 	struct imx_drm_connector *con;
-	struct imx_drm_crtc *crtc;
 
 	mutex_lock(&imxdrm->mutex);
 
-	list_for_each_entry(crtc, &imxdrm->crtc_list, list)
-		module_put(crtc->owner);
-
 	list_for_each_entry(con, &imxdrm->connector_list, list)
 		module_put(con->owner);
 
@@ -535,12 +517,12 @@ static void imx_drm_update_possible_crtcs(void)
  * The return value if !NULL is a cookie for the caller to pass to
  * imx_drm_remove_crtc later.
  */
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
-		struct module *owner, void *cookie, int id)
+		void *cookie, int id)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm = drm->dev_private;
 	struct imx_drm_crtc *imx_drm_crtc;
 	int ret;
 
@@ -574,8 +556,6 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	imx_drm_crtc->crtc = crtc;
 	imx_drm_crtc->imxdrm = imxdrm;
 
-	imx_drm_crtc->owner = owner;
-
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
@@ -587,11 +567,9 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	drm_crtc_helper_add(crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
 
-	drm_crtc_init(imxdrm->drm, crtc,
+	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	drm_mode_group_reinit(imxdrm->drm);
-
 	imx_drm_update_possible_crtcs();
 
 	mutex_unlock(&imxdrm->mutex);
@@ -621,8 +599,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
-	drm_mode_group_reinit(imxdrm->drm);
-
 	mutex_unlock(&imxdrm->mutex);
 
 	kfree(imx_drm_crtc);
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index d1fb1146240e..78465239ed4c 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -25,10 +25,10 @@ struct imx_drm_crtc_helper_funcs {
 	const struct drm_crtc_funcs *crtc_funcs;
 };
 
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
-		struct module *owner, void *cookie, int id);
+		void *cookie, int id);
 int imx_drm_remove_crtc(struct imx_drm_crtc *);
 int imx_drm_init_drm(struct platform_device *pdev,
 		int preferred_bpp);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index eb9653a5a887..ed2423efc1d0 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -335,7 +335,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
 }
 
 static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
-		struct ipu_client_platformdata *pdata)
+	struct ipu_client_platformdata *pdata, struct drm_device *drm)
 {
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 	int dp = -EINVAL;
@@ -349,9 +349,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		return ret;
 	}
 
-	ret = imx_drm_add_crtc(&ipu_crtc->base,
+	ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
 			&ipu_crtc->imx_crtc,
-			&ipu_crtc_helper_funcs, THIS_MODULE,
+			&ipu_crtc_helper_funcs,
 			ipu_crtc->dev->parent->of_node, pdata->di);
 	if (ret) {
 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
@@ -403,6 +403,7 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 {
 	struct ipu_client_platformdata *pdata = dev->platform_data;
+	struct drm_device *drm = data;
 	struct ipu_crtc *ipu_crtc;
 	int ret;
 
@@ -412,7 +413,7 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 
 	ipu_crtc->dev = dev;
 
-	ret = ipu_crtc_init(ipu_crtc, pdata);
+	ret = ipu_crtc_init(ipu_crtc, pdata, drm);
 	if (ret)
 		return ret;
 
-- 
1.7.4.4

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

* [PATCH RFC 32/46] imx-drm: use supplied drm_device where possible
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The component helper provides us the drm_device which is being
registered.  Rather than having to reference a global in imx-drm-core,
use this to get the imxdrm device, and also use it to register the CRTC
against.

This means we never have CRTCs/encoders/connectors without the drivers
private data being accessible.

Remove the module owner field as well; this provides no protection
against the device being unbound.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   34 ++++---------------------------
 drivers/staging/imx-drm/imx-drm.h      |    4 +-
 drivers/staging/imx-drm/ipuv3-crtc.c   |    9 ++++---
 3 files changed, 12 insertions(+), 35 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 08e7837d6134..b11568d6444b 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -52,7 +52,6 @@ struct imx_drm_crtc {
 	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
-	struct module				*owner;
 	struct crtc_cookie			cookie;
 	int					mux_id;
 };
@@ -74,7 +73,6 @@ static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 
 static void imx_drm_device_put(void);
-static struct imx_drm_device *__imx_drm_device(void);
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
@@ -114,7 +112,7 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm = crtc->dev->dev_private;
 	unsigned i;
 
 	for (i = 0; i < MAX_CRTC; i++)
@@ -241,7 +239,6 @@ static struct drm_device *imx_drm_device_get(void)
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
 	struct imx_drm_connector *con;
-	struct imx_drm_crtc *crtc;
 
 	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
 		if (!try_module_get(enc->owner)) {
@@ -259,19 +256,8 @@ static struct drm_device *imx_drm_device_get(void)
 		}
 	}
 
-	list_for_each_entry(crtc, &imxdrm->crtc_list, list) {
-		if (!try_module_get(crtc->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(crtc->owner));
-			goto unwind_crtc;
-		}
-	}
-
 	return imxdrm->drm;
 
-unwind_crtc:
-	list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list)
-		module_put(crtc->owner);
 unwind_con:
 	list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
 		module_put(con->owner);
@@ -290,13 +276,9 @@ static void imx_drm_device_put(void)
 	struct imx_drm_device *imxdrm = __imx_drm_device();
 	struct imx_drm_encoder *enc;
 	struct imx_drm_connector *con;
-	struct imx_drm_crtc *crtc;
 
 	mutex_lock(&imxdrm->mutex);
 
-	list_for_each_entry(crtc, &imxdrm->crtc_list, list)
-		module_put(crtc->owner);
-
 	list_for_each_entry(con, &imxdrm->connector_list, list)
 		module_put(con->owner);
 
@@ -535,12 +517,12 @@ static void imx_drm_update_possible_crtcs(void)
  * The return value if !NULL is a cookie for the caller to pass to
  * imx_drm_remove_crtc later.
  */
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
-		struct module *owner, void *cookie, int id)
+		void *cookie, int id)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm = drm->dev_private;
 	struct imx_drm_crtc *imx_drm_crtc;
 	int ret;
 
@@ -574,8 +556,6 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	imx_drm_crtc->crtc = crtc;
 	imx_drm_crtc->imxdrm = imxdrm;
 
-	imx_drm_crtc->owner = owner;
-
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
 	*new_crtc = imx_drm_crtc;
@@ -587,11 +567,9 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
 	drm_crtc_helper_add(crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
 
-	drm_crtc_init(imxdrm->drm, crtc,
+	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	drm_mode_group_reinit(imxdrm->drm);
-
 	imx_drm_update_possible_crtcs();
 
 	mutex_unlock(&imxdrm->mutex);
@@ -621,8 +599,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
-	drm_mode_group_reinit(imxdrm->drm);
-
 	mutex_unlock(&imxdrm->mutex);
 
 	kfree(imx_drm_crtc);
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index d1fb1146240e..78465239ed4c 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -25,10 +25,10 @@ struct imx_drm_crtc_helper_funcs {
 	const struct drm_crtc_funcs *crtc_funcs;
 };
 
-int imx_drm_add_crtc(struct drm_crtc *crtc,
+int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
-		struct module *owner, void *cookie, int id);
+		void *cookie, int id);
 int imx_drm_remove_crtc(struct imx_drm_crtc *);
 int imx_drm_init_drm(struct platform_device *pdev,
 		int preferred_bpp);
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index eb9653a5a887..ed2423efc1d0 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -335,7 +335,7 @@ static int ipu_get_resources(struct ipu_crtc *ipu_crtc,
 }
 
 static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
-		struct ipu_client_platformdata *pdata)
+	struct ipu_client_platformdata *pdata, struct drm_device *drm)
 {
 	struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
 	int dp = -EINVAL;
@@ -349,9 +349,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		return ret;
 	}
 
-	ret = imx_drm_add_crtc(&ipu_crtc->base,
+	ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
 			&ipu_crtc->imx_crtc,
-			&ipu_crtc_helper_funcs, THIS_MODULE,
+			&ipu_crtc_helper_funcs,
 			ipu_crtc->dev->parent->of_node, pdata->di);
 	if (ret) {
 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
@@ -403,6 +403,7 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 {
 	struct ipu_client_platformdata *pdata = dev->platform_data;
+	struct drm_device *drm = data;
 	struct ipu_crtc *ipu_crtc;
 	int ret;
 
@@ -412,7 +413,7 @@ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
 
 	ipu_crtc->dev = dev;
 
-	ret = ipu_crtc_init(ipu_crtc, pdata);
+	ret = ipu_crtc_init(ipu_crtc, pdata, drm);
 	if (ret)
 		return ret;
 
-- 
1.7.4.4

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

* [PATCH RFC 33/46] imx-drm: imx-drm-core: provide helper function to parse possible crtcs
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Provide a helper function to parse possible crtcs before the encoder
is registered.  The crtc mask is derived from the position of the
CRTCs registered in the drm_device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   66 ++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-drm.h      |    2 +
 2 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index b11568d6444b..1cfb8a18d905 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -657,6 +657,72 @@ int imx_drm_add_encoder(struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
 
+/*
+ * Find the DRM CRTC possible mask for the device node cookie/id.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list.  This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
+ */
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+	void *cookie, int id)
+{
+	unsigned i;
+
+	for (i = 0; i < MAX_CRTC; i++) {
+		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+		if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
+		    imx_drm_crtc->cookie.cookie == cookie)
+			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
+	}
+
+	return 0;
+}
+
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+	struct drm_encoder *encoder, struct device_node *np)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+	uint32_t crtc_mask = 0;
+	int i, ret = 0;
+
+	for (i = 0; !ret; i++) {
+		struct of_phandle_args args;
+		uint32_t mask;
+		int id;
+
+		ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
+						 &args);
+		if (ret == -ENOENT)
+			break;
+		if (ret < 0)
+			return ret;
+
+		id = args.args_count > 0 ? args.args[0] : 0;
+		mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
+		of_node_put(args.np);
+
+		/*
+		 * If we failed to find the CRTC(s) which this encoder is
+		 * supposed to be connected to, it's because the CRTC has
+		 * not been registered yet.  Defer probing, and hope that
+		 * the required CRTC is added later.
+		 */
+		if (mask == 0)
+			return -EPROBE_DEFER;
+
+		crtc_mask |= mask;
+	}
+
+	encoder->possible_crtcs = crtc_mask;
+
+	/* FIXME: this is the mask of outputs which can clone this output. */
+	encoder->possible_clones = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
+
 int imx_drm_encoder_add_possible_crtcs(
 		struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 78465239ed4c..49d4aaf33f97 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,6 +64,8 @@ struct device_node;
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+	struct drm_encoder *encoder, struct device_node *np);
 
 int imx_drm_connector_mode_valid(struct drm_connector *connector,
 	struct drm_display_mode *mode);
-- 
1.7.4.4

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

* [PATCH RFC 33/46] imx-drm: imx-drm-core: provide helper function to parse possible crtcs
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Provide a helper function to parse possible crtcs before the encoder
is registered.  The crtc mask is derived from the position of the
CRTCs registered in the drm_device.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   66 ++++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-drm.h      |    2 +
 2 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index b11568d6444b..1cfb8a18d905 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -657,6 +657,72 @@ int imx_drm_add_encoder(struct drm_encoder *encoder,
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
 
+/*
+ * Find the DRM CRTC possible mask for the device node cookie/id.
+ *
+ * The encoder possible masks are defined by their position in the
+ * mode_config crtc_list.  This means that CRTCs must not be added
+ * or removed once the DRM device has been fully initialised.
+ */
+static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
+	void *cookie, int id)
+{
+	unsigned i;
+
+	for (i = 0; i < MAX_CRTC; i++) {
+		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+		if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
+		    imx_drm_crtc->cookie.cookie == cookie)
+			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
+	}
+
+	return 0;
+}
+
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+	struct drm_encoder *encoder, struct device_node *np)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+	uint32_t crtc_mask = 0;
+	int i, ret = 0;
+
+	for (i = 0; !ret; i++) {
+		struct of_phandle_args args;
+		uint32_t mask;
+		int id;
+
+		ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
+						 &args);
+		if (ret == -ENOENT)
+			break;
+		if (ret < 0)
+			return ret;
+
+		id = args.args_count > 0 ? args.args[0] : 0;
+		mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
+		of_node_put(args.np);
+
+		/*
+		 * If we failed to find the CRTC(s) which this encoder is
+		 * supposed to be connected to, it's because the CRTC has
+		 * not been registered yet.  Defer probing, and hope that
+		 * the required CRTC is added later.
+		 */
+		if (mask == 0)
+			return -EPROBE_DEFER;
+
+		crtc_mask |= mask;
+	}
+
+	encoder->possible_crtcs = crtc_mask;
+
+	/* FIXME: this is the mask of outputs which can clone this output. */
+	encoder->possible_clones = ~0;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
+
 int imx_drm_encoder_add_possible_crtcs(
 		struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 78465239ed4c..49d4aaf33f97 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -64,6 +64,8 @@ struct device_node;
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
 		struct device_node *np);
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+	struct drm_encoder *encoder, struct device_node *np);
 
 int imx_drm_connector_mode_valid(struct drm_connector *connector,
 	struct drm_display_mode *mode);
-- 
1.7.4.4

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

* [PATCH RFC 34/46] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Provide two helper functions to assist with cleaning up imx-drm
connectors and encoders.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   13 +++++++++++++
 drivers/staging/imx-drm/imx-drm.h      |    2 ++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 1cfb8a18d905..30d516cc76bb 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -363,6 +363,19 @@ static void imx_drm_connector_unregister(
 	drm_mode_group_reinit(imxdrm->drm);
 }
 
+void imx_drm_connector_destroy(struct drm_connector *connector)
+{
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+}
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
+
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+
 static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
 };
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 49d4aaf33f97..d13d518e8eb9 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -69,5 +69,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 
 int imx_drm_connector_mode_valid(struct drm_connector *connector,
 	struct drm_display_mode *mode);
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
 
 #endif /* _IMX_DRM_H_ */
-- 
1.7.4.4

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

* [PATCH RFC 34/46] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Provide two helper functions to assist with cleaning up imx-drm
connectors and encoders.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   13 +++++++++++++
 drivers/staging/imx-drm/imx-drm.h      |    2 ++
 2 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 1cfb8a18d905..30d516cc76bb 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -363,6 +363,19 @@ static void imx_drm_connector_unregister(
 	drm_mode_group_reinit(imxdrm->drm);
 }
 
+void imx_drm_connector_destroy(struct drm_connector *connector)
+{
+	drm_sysfs_connector_remove(connector);
+	drm_connector_cleanup(connector);
+}
+EXPORT_SYMBOL_GPL(imx_drm_connector_destroy);
+
+void imx_drm_encoder_destroy(struct drm_encoder *encoder)
+{
+	drm_encoder_cleanup(encoder);
+}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
+
 static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
 };
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 49d4aaf33f97..d13d518e8eb9 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -69,5 +69,7 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 
 int imx_drm_connector_mode_valid(struct drm_connector *connector,
 	struct drm_display_mode *mode);
+void imx_drm_connector_destroy(struct drm_connector *connector);
+void imx_drm_encoder_destroy(struct drm_encoder *encoder);
 
 #endif /* _IMX_DRM_H_ */
-- 
1.7.4.4

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

* [PATCH RFC 35/46] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Now that our bind function is only ever called during the main DRM
driver ->load callback, we don't need to have the imx_drm_connector or
imx_drm_encoder abstractions anymore.  So let's get rid of it, and move
the DRM connector and encoder setup into the connector support files.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-ldb.c          |   68 +++++++++-------------------
 drivers/staging/imx-drm/imx-tve.c          |   58 ++++++-----------------
 drivers/staging/imx-drm/parallel-display.c |   61 +++++++------------------
 3 files changed, 54 insertions(+), 133 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 5b71f49faa0a..601f9c5c5340 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -59,9 +59,8 @@ struct imx_ldb;
 struct imx_ldb_channel {
 	struct imx_ldb *ldb;
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
+	struct device_node *child;
 	int chno;
 	void *edid;
 	int edid_len;
@@ -92,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_ldb_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
@@ -309,16 +303,11 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
 	}
 }
 
-static void imx_ldb_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_ldb_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_ldb_connector_detect,
-	.destroy = imx_ldb_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
@@ -328,7 +317,7 @@ static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
-	.destroy = imx_ldb_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
@@ -355,45 +344,36 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
 	return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
 }
 
-static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch)
+static int imx_ldb_register(struct drm_device *drm,
+	struct imx_ldb_channel *imx_ldb_ch)
 {
-	int ret;
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
+	int ret;
+
+	ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+				       imx_ldb_ch->child);
+	if (ret)
+		return ret;
 
 	ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
 	if (ret)
 		return ret;
+
 	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-		ret |= imx_ldb_get_clk(ldb, 1);
+		ret = imx_ldb_get_clk(ldb, 1);
 		if (ret)
 			return ret;
 	}
 
-	imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs;
-	imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs;
-
-	imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS;
-	imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS;
-
 	drm_encoder_helper_add(&imx_ldb_ch->encoder,
 			&imx_ldb_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&imx_ldb_ch->encoder,
-			&imx_ldb_ch->imx_drm_encoder, THIS_MODULE);
-	if (ret) {
-		dev_err(ldb->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS);
 
 	drm_connector_helper_add(&imx_ldb_ch->connector,
 			&imx_ldb_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&imx_ldb_ch->connector,
-			&imx_ldb_ch->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder);
-		dev_err(ldb->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &imx_ldb_ch->connector,
+			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 
 	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
 			&imx_ldb_ch->encoder);
@@ -454,6 +434,7 @@ MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
 static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	const struct of_device_id *of_id =
 			of_match_device(imx_ldb_dt_ids, dev);
@@ -524,6 +505,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 		channel = &imx_ldb->channel[i];
 		channel->ldb = imx_ldb;
 		channel->chno = i;
+		channel->child = child;
 
 		edidp = of_get_property(child, "edid", &channel->edid_len);
 		if (edidp) {
@@ -566,11 +548,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 			return -EINVAL;
 		}
 
-		ret = imx_ldb_register(channel);
+		ret = imx_ldb_register(drm, channel);
 		if (ret)
 			return ret;
-
-		imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
 	}
 
 	dev_set_drvdata(dev, imx_ldb);
@@ -586,13 +566,9 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
 
 	for (i = 0; i < 2; i++) {
 		struct imx_ldb_channel *channel = &imx_ldb->channel[i];
-		struct drm_connector *connector = &channel->connector;
-		struct drm_encoder *encoder = &channel->encoder;
-
-		drm_mode_connector_detach_encoder(connector, encoder);
 
-		imx_drm_remove_connector(channel->imx_drm_connector);
-		imx_drm_remove_encoder(channel->imx_drm_encoder);
+		channel->connector.funcs->destroy(&channel->connector);
+		channel->encoder.funcs->destroy(&channel->encoder);
 	}
 }
 
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index f8720f1ef86e..5cb6339cac82 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -111,9 +111,7 @@ enum {
 
 struct imx_tve {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 	struct device *dev;
 	spinlock_t lock;	/* register lock */
 	bool enabled;
@@ -226,11 +224,6 @@ static enum drm_connector_status imx_tve_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_tve_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_tve_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_tve *tve = con_to_tve(connector);
@@ -368,16 +361,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
 	tve_disable(tve);
 }
 
-static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_tve_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_tve_connector_detect,
-	.destroy = imx_tve_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
@@ -387,7 +375,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_tve_encoder_funcs = {
-	.destroy = imx_tve_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
@@ -507,7 +495,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
 	return 0;
 }
 
-static int imx_tve_register(struct imx_tve *tve)
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
 {
 	int encoder_type;
 	int ret;
@@ -515,30 +503,19 @@ static int imx_tve_register(struct imx_tve *tve)
 	encoder_type = tve->mode == TVE_MODE_VGA ?
 				DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
 
-	tve->connector.funcs = &imx_tve_connector_funcs;
-	tve->encoder.funcs = &imx_tve_encoder_funcs;
-
-	tve->encoder.encoder_type = encoder_type;
-	tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+	ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+				       tve->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(tve->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+			 encoder_type);
 
 	drm_connector_helper_add(&tve->connector,
 			&imx_tve_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&tve->connector,
-			&tve->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(tve->imx_drm_encoder);
-		dev_err(tve->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+			   DRM_MODE_CONNECTOR_VGA);
 
 	drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
 
@@ -587,6 +564,7 @@ const int of_get_tve_mode(struct device_node *np)
 static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_tve *tve;
@@ -701,12 +679,10 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 	/* disable cable detection for VGA mode */
 	ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
 
-	ret = imx_tve_register(tve);
+	ret = imx_tve_register(drm, tve);
 	if (ret)
 		return ret;
 
-	ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, tve);
 
 	return 0;
@@ -716,13 +692,9 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_tve *tve = dev_get_drvdata(dev);
-	struct drm_connector *connector = &tve->connector;
-	struct drm_encoder *encoder = &tve->encoder;
-
-	drm_mode_connector_detach_encoder(connector, encoder);
 
-	imx_drm_remove_connector(tve->imx_drm_connector);
-	imx_drm_remove_encoder(tve->imx_drm_encoder);
+	tve->connector.funcs->destroy(&tve->connector);
+	tve->encoder.funcs->destroy(&tve->encoder);
 
 	if (!IS_ERR(tve->dac_reg))
 		regulator_disable(tve->dac_reg);
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 110c0021a797..72c17f0e80be 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -32,9 +32,7 @@
 
 struct imx_parallel_display {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 	struct device *dev;
 	void *edid;
 	int edid_len;
@@ -49,11 +47,6 @@ static enum drm_connector_status imx_pd_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_pd_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_pd_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_parallel_display *imxpd = con_to_imxpd(connector);
@@ -125,16 +118,11 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
 {
 }
 
-static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_pd_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_pd_connector_detect,
-	.destroy = imx_pd_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
@@ -144,7 +132,7 @@ static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_pd_encoder_funcs = {
-	.destroy = imx_pd_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
@@ -156,36 +144,26 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
 	.disable = imx_pd_encoder_disable,
 };
 
-static int imx_pd_register(struct imx_parallel_display *imxpd)
+static int imx_pd_register(struct drm_device *drm,
+	struct imx_parallel_display *imxpd)
 {
 	int ret;
 
-	drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
-	imxpd->connector.funcs = &imx_pd_connector_funcs;
-	imxpd->encoder.funcs = &imx_pd_encoder_funcs;
-
-	imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
-	imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+	ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+				       imxpd->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+			 DRM_MODE_ENCODER_NONE);
 
 	drm_connector_helper_add(&imxpd->connector,
 			&imx_pd_connector_helper_funcs);
+	drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+			   DRM_MODE_CONNECTOR_VGA);
 
-	ret = imx_drm_add_connector(&imxpd->connector,
-			&imxpd->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(imxpd->imx_drm_encoder);
-		dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
 
 	imxpd->connector.encoder = &imxpd->encoder;
 
@@ -194,6 +172,7 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
 
 static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 {
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	const u8 *edidp;
 	struct imx_parallel_display *imxpd;
@@ -220,12 +199,10 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 
 	imxpd->dev = dev;
 
-	ret = imx_pd_register(imxpd);
+	ret = imx_pd_register(drm, imxpd);
 	if (ret)
 		return ret;
 
-	ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, imxpd);
 
 	return 0;
@@ -235,13 +212,9 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
-	struct drm_connector *connector = &imxpd->connector;
-	struct drm_encoder *encoder = &imxpd->encoder;
-
-	drm_mode_connector_detach_encoder(connector, encoder);
 
-	imx_drm_remove_connector(imxpd->imx_drm_connector);
-	imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+	imxpd->encoder.funcs->destroy(&imxpd->encoder);
+	imxpd->connector.funcs->destroy(&imxpd->connector);
 }
 
 static const struct component_ops imx_pd_ops = {
-- 
1.7.4.4

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

* [PATCH RFC 35/46] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Now that our bind function is only ever called during the main DRM
driver ->load callback, we don't need to have the imx_drm_connector or
imx_drm_encoder abstractions anymore.  So let's get rid of it, and move
the DRM connector and encoder setup into the connector support files.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-ldb.c          |   68 +++++++++-------------------
 drivers/staging/imx-drm/imx-tve.c          |   58 ++++++-----------------
 drivers/staging/imx-drm/parallel-display.c |   61 +++++++------------------
 3 files changed, 54 insertions(+), 133 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c
index 5b71f49faa0a..601f9c5c5340 100644
--- a/drivers/staging/imx-drm/imx-ldb.c
+++ b/drivers/staging/imx-drm/imx-ldb.c
@@ -59,9 +59,8 @@ struct imx_ldb;
 struct imx_ldb_channel {
 	struct imx_ldb *ldb;
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
+	struct device_node *child;
 	int chno;
 	void *edid;
 	int edid_len;
@@ -92,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_ldb_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_ldb_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector);
@@ -309,16 +303,11 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder)
 	}
 }
 
-static void imx_ldb_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_ldb_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_ldb_connector_detect,
-	.destroy = imx_ldb_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
@@ -328,7 +317,7 @@ static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_ldb_encoder_funcs = {
-	.destroy = imx_ldb_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = {
@@ -355,45 +344,36 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno)
 	return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]);
 }
 
-static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch)
+static int imx_ldb_register(struct drm_device *drm,
+	struct imx_ldb_channel *imx_ldb_ch)
 {
-	int ret;
 	struct imx_ldb *ldb = imx_ldb_ch->ldb;
+	int ret;
+
+	ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder,
+				       imx_ldb_ch->child);
+	if (ret)
+		return ret;
 
 	ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno);
 	if (ret)
 		return ret;
+
 	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
-		ret |= imx_ldb_get_clk(ldb, 1);
+		ret = imx_ldb_get_clk(ldb, 1);
 		if (ret)
 			return ret;
 	}
 
-	imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs;
-	imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs;
-
-	imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS;
-	imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS;
-
 	drm_encoder_helper_add(&imx_ldb_ch->encoder,
 			&imx_ldb_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&imx_ldb_ch->encoder,
-			&imx_ldb_ch->imx_drm_encoder, THIS_MODULE);
-	if (ret) {
-		dev_err(ldb->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs,
+			 DRM_MODE_ENCODER_LVDS);
 
 	drm_connector_helper_add(&imx_ldb_ch->connector,
 			&imx_ldb_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&imx_ldb_ch->connector,
-			&imx_ldb_ch->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder);
-		dev_err(ldb->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &imx_ldb_ch->connector,
+			   &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
 
 	drm_mode_connector_attach_encoder(&imx_ldb_ch->connector,
 			&imx_ldb_ch->encoder);
@@ -454,6 +434,7 @@ MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids);
 
 static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 {
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	const struct of_device_id *of_id =
 			of_match_device(imx_ldb_dt_ids, dev);
@@ -524,6 +505,7 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 		channel = &imx_ldb->channel[i];
 		channel->ldb = imx_ldb;
 		channel->chno = i;
+		channel->child = child;
 
 		edidp = of_get_property(child, "edid", &channel->edid_len);
 		if (edidp) {
@@ -566,11 +548,9 @@ static int imx_ldb_bind(struct device *dev, struct device *master, void *data)
 			return -EINVAL;
 		}
 
-		ret = imx_ldb_register(channel);
+		ret = imx_ldb_register(drm, channel);
 		if (ret)
 			return ret;
-
-		imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child);
 	}
 
 	dev_set_drvdata(dev, imx_ldb);
@@ -586,13 +566,9 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
 
 	for (i = 0; i < 2; i++) {
 		struct imx_ldb_channel *channel = &imx_ldb->channel[i];
-		struct drm_connector *connector = &channel->connector;
-		struct drm_encoder *encoder = &channel->encoder;
-
-		drm_mode_connector_detach_encoder(connector, encoder);
 
-		imx_drm_remove_connector(channel->imx_drm_connector);
-		imx_drm_remove_encoder(channel->imx_drm_encoder);
+		channel->connector.funcs->destroy(&channel->connector);
+		channel->encoder.funcs->destroy(&channel->encoder);
 	}
 }
 
diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c
index f8720f1ef86e..5cb6339cac82 100644
--- a/drivers/staging/imx-drm/imx-tve.c
+++ b/drivers/staging/imx-drm/imx-tve.c
@@ -111,9 +111,7 @@ enum {
 
 struct imx_tve {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 	struct device *dev;
 	spinlock_t lock;	/* register lock */
 	bool enabled;
@@ -226,11 +224,6 @@ static enum drm_connector_status imx_tve_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_tve_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_tve_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_tve *tve = con_to_tve(connector);
@@ -368,16 +361,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder)
 	tve_disable(tve);
 }
 
-static void imx_tve_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_tve_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_tve_connector_detect,
-	.destroy = imx_tve_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
@@ -387,7 +375,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_tve_encoder_funcs = {
-	.destroy = imx_tve_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
@@ -507,7 +495,7 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base)
 	return 0;
 }
 
-static int imx_tve_register(struct imx_tve *tve)
+static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve)
 {
 	int encoder_type;
 	int ret;
@@ -515,30 +503,19 @@ static int imx_tve_register(struct imx_tve *tve)
 	encoder_type = tve->mode == TVE_MODE_VGA ?
 				DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC;
 
-	tve->connector.funcs = &imx_tve_connector_funcs;
-	tve->encoder.funcs = &imx_tve_encoder_funcs;
-
-	tve->encoder.encoder_type = encoder_type;
-	tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+	ret = imx_drm_encoder_parse_of(drm, &tve->encoder,
+				       tve->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(tve->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs,
+			 encoder_type);
 
 	drm_connector_helper_add(&tve->connector,
 			&imx_tve_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&tve->connector,
-			&tve->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(tve->imx_drm_encoder);
-		dev_err(tve->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs,
+			   DRM_MODE_CONNECTOR_VGA);
 
 	drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder);
 
@@ -587,6 +564,7 @@ const int of_get_tve_mode(struct device_node *np)
 static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 {
 	struct platform_device *pdev = to_platform_device(dev);
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_tve *tve;
@@ -701,12 +679,10 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
 	/* disable cable detection for VGA mode */
 	ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
 
-	ret = imx_tve_register(tve);
+	ret = imx_tve_register(drm, tve);
 	if (ret)
 		return ret;
 
-	ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, tve);
 
 	return 0;
@@ -716,13 +692,9 @@ static void imx_tve_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_tve *tve = dev_get_drvdata(dev);
-	struct drm_connector *connector = &tve->connector;
-	struct drm_encoder *encoder = &tve->encoder;
-
-	drm_mode_connector_detach_encoder(connector, encoder);
 
-	imx_drm_remove_connector(tve->imx_drm_connector);
-	imx_drm_remove_encoder(tve->imx_drm_encoder);
+	tve->connector.funcs->destroy(&tve->connector);
+	tve->encoder.funcs->destroy(&tve->encoder);
 
 	if (!IS_ERR(tve->dac_reg))
 		regulator_disable(tve->dac_reg);
diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c
index 110c0021a797..72c17f0e80be 100644
--- a/drivers/staging/imx-drm/parallel-display.c
+++ b/drivers/staging/imx-drm/parallel-display.c
@@ -32,9 +32,7 @@
 
 struct imx_parallel_display {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 	struct device *dev;
 	void *edid;
 	int edid_len;
@@ -49,11 +47,6 @@ static enum drm_connector_status imx_pd_connector_detect(
 	return connector_status_connected;
 }
 
-static void imx_pd_connector_destroy(struct drm_connector *connector)
-{
-	/* do not free here */
-}
-
 static int imx_pd_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_parallel_display *imxpd = con_to_imxpd(connector);
@@ -125,16 +118,11 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
 {
 }
 
-static void imx_pd_encoder_destroy(struct drm_encoder *encoder)
-{
-	/* do not free here */
-}
-
 static struct drm_connector_funcs imx_pd_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_pd_connector_detect,
-	.destroy = imx_pd_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
@@ -144,7 +132,7 @@ static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
 };
 
 static struct drm_encoder_funcs imx_pd_encoder_funcs = {
-	.destroy = imx_pd_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
@@ -156,36 +144,26 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
 	.disable = imx_pd_encoder_disable,
 };
 
-static int imx_pd_register(struct imx_parallel_display *imxpd)
+static int imx_pd_register(struct drm_device *drm,
+	struct imx_parallel_display *imxpd)
 {
 	int ret;
 
-	drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
-
-	imxpd->connector.funcs = &imx_pd_connector_funcs;
-	imxpd->encoder.funcs = &imx_pd_encoder_funcs;
-
-	imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE;
-	imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA;
+	ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
+				       imxpd->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(imxpd->dev, "adding encoder failed with %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
+			 DRM_MODE_ENCODER_NONE);
 
 	drm_connector_helper_add(&imxpd->connector,
 			&imx_pd_connector_helper_funcs);
+	drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
+			   DRM_MODE_CONNECTOR_VGA);
 
-	ret = imx_drm_add_connector(&imxpd->connector,
-			&imxpd->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(imxpd->imx_drm_encoder);
-		dev_err(imxpd->dev, "adding connector failed with %d\n", ret);
-		return ret;
-	}
+	drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
 
 	imxpd->connector.encoder = &imxpd->encoder;
 
@@ -194,6 +172,7 @@ static int imx_pd_register(struct imx_parallel_display *imxpd)
 
 static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 {
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	const u8 *edidp;
 	struct imx_parallel_display *imxpd;
@@ -220,12 +199,10 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
 
 	imxpd->dev = dev;
 
-	ret = imx_pd_register(imxpd);
+	ret = imx_pd_register(drm, imxpd);
 	if (ret)
 		return ret;
 
-	ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, imxpd);
 
 	return 0;
@@ -235,13 +212,9 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
-	struct drm_connector *connector = &imxpd->connector;
-	struct drm_encoder *encoder = &imxpd->encoder;
-
-	drm_mode_connector_detach_encoder(connector, encoder);
 
-	imx_drm_remove_connector(imxpd->imx_drm_connector);
-	imx_drm_remove_encoder(imxpd->imx_drm_encoder);
+	imxpd->encoder.funcs->destroy(&imxpd->encoder);
+	imxpd->connector.funcs->destroy(&imxpd->connector);
 }
 
 static const struct component_ops imx_pd_ops = {
-- 
1.7.4.4

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

* [PATCH RFC 36/46] imx-drm: imx-hdmi: initialise drm components directly
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   56 +++++++++--------------------------
 1 files changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index d81940a8904f..512b39710530 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -117,9 +117,7 @@ struct hdmi_data_info {
 
 struct imx_hdmi {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
@@ -1382,10 +1380,6 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 	return connector_status_connected;
 }
 
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
-{
-}
-
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
@@ -1471,13 +1465,8 @@ static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
 	imx_hdmi_poweron(hdmi);
 }
 
-static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
-{
-	return;
-}
-
 static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
-	.destroy = imx_hdmi_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1493,7 +1482,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_hdmi_connector_detect,
-	.destroy = imx_hdmi_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1533,34 +1522,23 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int imx_hdmi_register(struct imx_hdmi *hdmi)
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 {
 	int ret;
 
-	hdmi->connector.funcs = &imx_hdmi_connector_funcs;
-	hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
-
-	hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
-	hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+	ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+				       hdmi->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
 
 	drm_connector_helper_add(&hdmi->connector,
 			&imx_hdmi_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&hdmi->connector,
-			&hdmi->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(hdmi->imx_drm_encoder);
-		dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
 
 	hdmi->connector.encoder = &hdmi->encoder;
 
@@ -1592,6 +1570,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct of_device_id *of_id =
 				of_match_device(imx_hdmi_dt_ids, dev);
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
@@ -1699,12 +1678,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		goto err_iahb;
 
-	ret = imx_hdmi_register(hdmi);
+	ret = imx_hdmi_register(drm, hdmi);
 	if (ret)
 		goto err_iahb;
 
-	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1721,12 +1698,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-	struct drm_connector *connector = &hdmi->connector;
-	struct drm_encoder *encoder = &hdmi->encoder;
 
-	drm_mode_connector_detach_encoder(connector, encoder);
-	imx_drm_remove_connector(hdmi->imx_drm_connector);
-	imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
-- 
1.7.4.4

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

* [PATCH RFC 36/46] imx-drm: imx-hdmi: initialise drm components directly
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   56 +++++++++--------------------------
 1 files changed, 15 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index d81940a8904f..512b39710530 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -117,9 +117,7 @@ struct hdmi_data_info {
 
 struct imx_hdmi {
 	struct drm_connector connector;
-	struct imx_drm_connector *imx_drm_connector;
 	struct drm_encoder encoder;
-	struct imx_drm_encoder *imx_drm_encoder;
 
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
@@ -1382,10 +1380,6 @@ static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 	return connector_status_connected;
 }
 
-static void imx_hdmi_connector_destroy(struct drm_connector *connector)
-{
-}
-
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 {
 	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
@@ -1471,13 +1465,8 @@ static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
 	imx_hdmi_poweron(hdmi);
 }
 
-static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
-{
-	return;
-}
-
 static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
-	.destroy = imx_hdmi_encoder_destroy,
+	.destroy = imx_drm_encoder_destroy,
 };
 
 static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
@@ -1493,7 +1482,7 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = {
 	.dpms = drm_helper_connector_dpms,
 	.fill_modes = drm_helper_probe_single_connector_modes,
 	.detect = imx_hdmi_connector_detect,
-	.destroy = imx_hdmi_connector_destroy,
+	.destroy = imx_drm_connector_destroy,
 };
 
 static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
@@ -1533,34 +1522,23 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
-static int imx_hdmi_register(struct imx_hdmi *hdmi)
+static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 {
 	int ret;
 
-	hdmi->connector.funcs = &imx_hdmi_connector_funcs;
-	hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
-
-	hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
-	hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+	ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
+				       hdmi->dev->of_node);
+	if (ret)
+		return ret;
 
 	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
-	ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
-			THIS_MODULE);
-	if (ret) {
-		dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
-		return ret;
-	}
+	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
+			 DRM_MODE_ENCODER_TMDS);
 
 	drm_connector_helper_add(&hdmi->connector,
 			&imx_hdmi_connector_helper_funcs);
-
-	ret = imx_drm_add_connector(&hdmi->connector,
-			&hdmi->imx_drm_connector, THIS_MODULE);
-	if (ret) {
-		imx_drm_remove_encoder(hdmi->imx_drm_encoder);
-		dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
-		return ret;
-	}
+	drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
+			   DRM_MODE_CONNECTOR_HDMIA);
 
 	hdmi->connector.encoder = &hdmi->encoder;
 
@@ -1592,6 +1570,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	struct platform_device *pdev = to_platform_device(dev);
 	const struct of_device_id *of_id =
 				of_match_device(imx_hdmi_dt_ids, dev);
+	struct drm_device *drm = data;
 	struct device_node *np = dev->of_node;
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
@@ -1699,12 +1678,10 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		goto err_iahb;
 
-	ret = imx_hdmi_register(hdmi);
+	ret = imx_hdmi_register(drm, hdmi);
 	if (ret)
 		goto err_iahb;
 
-	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
-
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1721,12 +1698,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 	void *data)
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-	struct drm_connector *connector = &hdmi->connector;
-	struct drm_encoder *encoder = &hdmi->encoder;
 
-	drm_mode_connector_detach_encoder(connector, encoder);
-	imx_drm_remove_connector(hdmi->imx_drm_connector);
-	imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
 	clk_disable_unprepare(hdmi->iahb_clk);
 	clk_disable_unprepare(hdmi->isfr_clk);
-- 
1.7.4.4

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

* [PATCH RFC 37/46] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:28   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: linux-arm-kernel

The core imx_drm_connector and imx_drm_encoder code is no longer
required - the connectors and encoders are all using the component
support, so we can remove this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |  370 --------------------------------
 drivers/staging/imx-drm/imx-drm.h      |   14 --
 2 files changed, 0 insertions(+), 384 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 30d516cc76bb..7872d13689ea 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,8 +40,6 @@ struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
-	struct list_head			encoder_list;
-	struct list_head			connector_list;
 	struct mutex				mutex;
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
@@ -56,24 +54,9 @@ struct imx_drm_crtc {
 	int					mux_id;
 };
 
-struct imx_drm_encoder {
-	struct drm_encoder			*encoder;
-	struct list_head			list;
-	struct module				*owner;
-	struct list_head			possible_crtcs;
-};
-
-struct imx_drm_connector {
-	struct drm_connector			*connector;
-	struct list_head			list;
-	struct module				*owner;
-};
-
 static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 
-static void imx_drm_device_put(void);
-
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
 	return crtc->pipe;
@@ -101,8 +84,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 	component_unbind_all(drm->dev, drm);
 
-	imx_drm_device_put();
-
 	drm_vblank_cleanup(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
@@ -234,135 +215,6 @@ static struct imx_drm_device *__imx_drm_device(void)
 	return imx_drm_device;
 }
 
-static struct drm_device *imx_drm_device_get(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *enc;
-	struct imx_drm_connector *con;
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
-		if (!try_module_get(enc->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(enc->owner));
-			goto unwind_enc;
-		}
-	}
-
-	list_for_each_entry(con, &imxdrm->connector_list, list) {
-		if (!try_module_get(con->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(con->owner));
-			goto unwind_con;
-		}
-	}
-
-	return imxdrm->drm;
-
-unwind_con:
-	list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
-		module_put(con->owner);
-unwind_enc:
-	list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
-		module_put(enc->owner);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return NULL;
-
-}
-
-static void imx_drm_device_put(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *enc;
-	struct imx_drm_connector *con;
-
-	mutex_lock(&imxdrm->mutex);
-
-	list_for_each_entry(con, &imxdrm->connector_list, list)
-		module_put(con->owner);
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list)
-		module_put(enc->owner);
-
-	mutex_unlock(&imxdrm->mutex);
-}
-
-static int drm_mode_group_reinit(struct drm_device *dev)
-{
-	struct drm_mode_group *group = &dev->primary->mode_group;
-	uint32_t *id_list = group->id_list;
-	int ret;
-
-	ret = drm_mode_group_init_legacy_group(dev, group);
-	if (ret < 0)
-		return ret;
-
-	kfree(id_list);
-	return 0;
-}
-
-/*
- * register an encoder to the drm core
- */
-static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
-
-	drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
-			imx_drm_encoder->encoder->funcs,
-			imx_drm_encoder->encoder->encoder_type);
-
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
- * unregister an encoder from the drm core
- */
-static void imx_drm_encoder_unregister(struct imx_drm_encoder
-		*imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_encoder_cleanup(imx_drm_encoder->encoder);
-
-	drm_mode_group_reinit(imxdrm->drm);
-}
-
-/*
- * register a connector to the drm core
- */
-static int imx_drm_connector_register(
-		struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
-			imx_drm_connector->connector->funcs,
-			imx_drm_connector->connector->connector_type);
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
- * unregister a connector from the drm core
- */
-static void imx_drm_connector_unregister(
-		struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_sysfs_connector_remove(imx_drm_connector->connector);
-	drm_connector_cleanup(imx_drm_connector->connector);
-
-	drm_mode_group_reinit(imxdrm->drm);
-}
-
 void imx_drm_connector_destroy(struct drm_connector *connector)
 {
 	drm_sysfs_connector_remove(connector);
@@ -439,11 +291,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->vblank_disable_allowed = true;
 
-	if (!imx_drm_device_get()) {
-		ret = -EINVAL;
-		goto err_vblank;
-	}
-
 	mutex_unlock(&imxdrm->mutex);
 
 	/* Now try and bind all our sub-components */
@@ -491,7 +338,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	component_unbind_all(drm->dev, drm);
 err_relock:
 	mutex_lock(&imxdrm->mutex);
-err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
 	drm_kms_helper_poll_fini(drm);
@@ -501,29 +347,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	return ret;
 }
 
-static void imx_drm_update_possible_crtcs(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_crtc *imx_drm_crtc;
-	struct imx_drm_encoder *enc;
-	struct crtc_cookie *cookie;
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
-		u32 possible_crtcs = 0;
-
-		list_for_each_entry(cookie, &enc->possible_crtcs, list) {
-			list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
-				if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
-						imx_drm_crtc->cookie.id == cookie->id) {
-					possible_crtcs |= 1 << imx_drm_crtc->pipe;
-				}
-			}
-		}
-		enc->encoder->possible_crtcs = possible_crtcs;
-		enc->encoder->possible_clones = possible_crtcs;
-	}
-}
-
 /*
  * imx_drm_add_crtc - add a new crtc
  *
@@ -583,8 +406,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	imx_drm_update_possible_crtcs();
-
 	mutex_unlock(&imxdrm->mutex);
 
 	return 0;
@@ -621,56 +442,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
 
 /*
- * imx_drm_add_encoder - add a new encoder
- */
-int imx_drm_add_encoder(struct drm_encoder *encoder,
-		struct imx_drm_encoder **newenc, struct module *owner)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *imx_drm_encoder;
-	int ret;
-
-	mutex_lock(&imxdrm->mutex);
-
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
-
-	imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
-	if (!imx_drm_encoder) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	imx_drm_encoder->encoder = encoder;
-	imx_drm_encoder->owner = owner;
-
-	ret = imx_drm_encoder_register(imx_drm_encoder);
-	if (ret) {
-		ret = -ENOMEM;
-		goto err_register;
-	}
-
-	list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
-
-	*newenc = imx_drm_encoder;
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return 0;
-
-err_register:
-	kfree(imx_drm_encoder);
-err_alloc:
-err_busy:
-	mutex_unlock(&imxdrm->mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
-
-/*
  * Find the DRM CRTC possible mask for the device node cookie/id.
  *
  * The encoder possible masks are defined by their position in the
@@ -736,49 +507,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
 
-int imx_drm_encoder_add_possible_crtcs(
-		struct imx_drm_encoder *imx_drm_encoder,
-		struct device_node *np)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct of_phandle_args args;
-	struct crtc_cookie *c;
-	int ret = 0;
-	int i;
-
-	if (!list_empty(&imx_drm_encoder->possible_crtcs))
-		return -EBUSY;
-
-	for (i = 0; !ret; i++) {
-		ret = of_parse_phandle_with_args(np, "crtcs",
-				"#crtc-cells", i, &args);
-		if (ret < 0)
-			break;
-
-		c = kzalloc(sizeof(*c), GFP_KERNEL);
-		if (!c) {
-			of_node_put(args.np);
-			return -ENOMEM;
-		}
-
-		c->cookie = args.np;
-		c->id = args.args_count > 0 ? args.args[0] : 0;
-
-		of_node_put(args.np);
-
-		mutex_lock(&imxdrm->mutex);
-
-		list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
-
-		mutex_unlock(&imxdrm->mutex);
-	}
-
-	imx_drm_update_possible_crtcs();
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
-
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
@@ -787,102 +515,6 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
-/*
- * imx_drm_remove_encoder - remove an encoder
- */
-int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct crtc_cookie *c, *tmp;
-
-	mutex_lock(&imxdrm->mutex);
-
-	imx_drm_encoder_unregister(imx_drm_encoder);
-
-	list_del(&imx_drm_encoder->list);
-
-	list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
-			list)
-		kfree(c);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	kfree(imx_drm_encoder);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
-
-/*
- * imx_drm_add_connector - add a connector
- */
-int imx_drm_add_connector(struct drm_connector *connector,
-		struct imx_drm_connector **new_con,
-		struct module *owner)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_connector *imx_drm_connector;
-	int ret;
-
-	mutex_lock(&imxdrm->mutex);
-
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
-
-	imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
-	if (!imx_drm_connector) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	imx_drm_connector->connector = connector;
-	imx_drm_connector->owner = owner;
-
-	ret = imx_drm_connector_register(imx_drm_connector);
-	if (ret)
-		goto err_register;
-
-	list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
-
-	*new_con = imx_drm_connector;
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return 0;
-
-err_register:
-	kfree(imx_drm_connector);
-err_alloc:
-err_busy:
-	mutex_unlock(&imxdrm->mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-
-/*
- * imx_drm_remove_connector - remove a connector
- */
-int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	mutex_lock(&imxdrm->mutex);
-
-	imx_drm_connector_unregister(imx_drm_connector);
-
-	list_del(&imx_drm_connector->list);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	kfree(imx_drm_connector);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
-
 static const struct drm_ioctl_desc imx_drm_ioctls[] = {
 	/* none so far */
 };
@@ -1030,8 +662,6 @@ static int __init imx_drm_init(void)
 		return -ENOMEM;
 
 	mutex_init(&imx_drm_device->mutex);
-	INIT_LIST_HEAD(&imx_drm_device->connector_list);
-	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index d13d518e8eb9..c5b97e9ce9a0 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -38,18 +38,6 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
 
-struct imx_drm_encoder;
-int imx_drm_add_encoder(struct drm_encoder *encoder,
-		struct imx_drm_encoder **new_enc,
-		struct module *owner);
-int imx_drm_remove_encoder(struct imx_drm_encoder *);
-
-struct imx_drm_connector;
-int imx_drm_add_connector(struct drm_connector *connector,
-		struct imx_drm_connector **new_con,
-		struct module *owner);
-int imx_drm_remove_connector(struct imx_drm_connector *);
-
 void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
@@ -62,8 +50,6 @@ int imx_drm_panel_format(struct drm_encoder *encoder,
 struct device_node;
 
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
-int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
-		struct device_node *np);
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np);
 
-- 
1.7.4.4

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

* [PATCH RFC 37/46] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code
@ 2014-01-02 21:28   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:28 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

The core imx_drm_connector and imx_drm_encoder code is no longer
required - the connectors and encoders are all using the component
support, so we can remove this.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |  370 --------------------------------
 drivers/staging/imx-drm/imx-drm.h      |   14 --
 2 files changed, 0 insertions(+), 384 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 30d516cc76bb..7872d13689ea 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,8 +40,6 @@ struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
-	struct list_head			encoder_list;
-	struct list_head			connector_list;
 	struct mutex				mutex;
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
@@ -56,24 +54,9 @@ struct imx_drm_crtc {
 	int					mux_id;
 };
 
-struct imx_drm_encoder {
-	struct drm_encoder			*encoder;
-	struct list_head			list;
-	struct module				*owner;
-	struct list_head			possible_crtcs;
-};
-
-struct imx_drm_connector {
-	struct drm_connector			*connector;
-	struct list_head			list;
-	struct module				*owner;
-};
-
 static int legacyfb_depth = 16;
 module_param(legacyfb_depth, int, 0444);
 
-static void imx_drm_device_put(void);
-
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
 	return crtc->pipe;
@@ -101,8 +84,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 
 	component_unbind_all(drm->dev, drm);
 
-	imx_drm_device_put();
-
 	drm_vblank_cleanup(drm);
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
@@ -234,135 +215,6 @@ static struct imx_drm_device *__imx_drm_device(void)
 	return imx_drm_device;
 }
 
-static struct drm_device *imx_drm_device_get(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *enc;
-	struct imx_drm_connector *con;
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
-		if (!try_module_get(enc->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(enc->owner));
-			goto unwind_enc;
-		}
-	}
-
-	list_for_each_entry(con, &imxdrm->connector_list, list) {
-		if (!try_module_get(con->owner)) {
-			dev_err(imxdrm->dev, "could not get module %s\n",
-					module_name(con->owner));
-			goto unwind_con;
-		}
-	}
-
-	return imxdrm->drm;
-
-unwind_con:
-	list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list)
-		module_put(con->owner);
-unwind_enc:
-	list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list)
-		module_put(enc->owner);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return NULL;
-
-}
-
-static void imx_drm_device_put(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *enc;
-	struct imx_drm_connector *con;
-
-	mutex_lock(&imxdrm->mutex);
-
-	list_for_each_entry(con, &imxdrm->connector_list, list)
-		module_put(con->owner);
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list)
-		module_put(enc->owner);
-
-	mutex_unlock(&imxdrm->mutex);
-}
-
-static int drm_mode_group_reinit(struct drm_device *dev)
-{
-	struct drm_mode_group *group = &dev->primary->mode_group;
-	uint32_t *id_list = group->id_list;
-	int ret;
-
-	ret = drm_mode_group_init_legacy_group(dev, group);
-	if (ret < 0)
-		return ret;
-
-	kfree(id_list);
-	return 0;
-}
-
-/*
- * register an encoder to the drm core
- */
-static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs);
-
-	drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder,
-			imx_drm_encoder->encoder->funcs,
-			imx_drm_encoder->encoder->encoder_type);
-
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
- * unregister an encoder from the drm core
- */
-static void imx_drm_encoder_unregister(struct imx_drm_encoder
-		*imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_encoder_cleanup(imx_drm_encoder->encoder);
-
-	drm_mode_group_reinit(imxdrm->drm);
-}
-
-/*
- * register a connector to the drm core
- */
-static int imx_drm_connector_register(
-		struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_connector_init(imxdrm->drm, imx_drm_connector->connector,
-			imx_drm_connector->connector->funcs,
-			imx_drm_connector->connector->connector_type);
-	drm_mode_group_reinit(imxdrm->drm);
-
-	return 0;
-}
-
-/*
- * unregister a connector from the drm core
- */
-static void imx_drm_connector_unregister(
-		struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	drm_sysfs_connector_remove(imx_drm_connector->connector);
-	drm_connector_cleanup(imx_drm_connector->connector);
-
-	drm_mode_group_reinit(imxdrm->drm);
-}
-
 void imx_drm_connector_destroy(struct drm_connector *connector)
 {
 	drm_sysfs_connector_remove(connector);
@@ -439,11 +291,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->vblank_disable_allowed = true;
 
-	if (!imx_drm_device_get()) {
-		ret = -EINVAL;
-		goto err_vblank;
-	}
-
 	mutex_unlock(&imxdrm->mutex);
 
 	/* Now try and bind all our sub-components */
@@ -491,7 +338,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	component_unbind_all(drm->dev, drm);
 err_relock:
 	mutex_lock(&imxdrm->mutex);
-err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
 	drm_kms_helper_poll_fini(drm);
@@ -501,29 +347,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	return ret;
 }
 
-static void imx_drm_update_possible_crtcs(void)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_crtc *imx_drm_crtc;
-	struct imx_drm_encoder *enc;
-	struct crtc_cookie *cookie;
-
-	list_for_each_entry(enc, &imxdrm->encoder_list, list) {
-		u32 possible_crtcs = 0;
-
-		list_for_each_entry(cookie, &enc->possible_crtcs, list) {
-			list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) {
-				if (imx_drm_crtc->cookie.cookie == cookie->cookie &&
-						imx_drm_crtc->cookie.id == cookie->id) {
-					possible_crtcs |= 1 << imx_drm_crtc->pipe;
-				}
-			}
-		}
-		enc->encoder->possible_crtcs = possible_crtcs;
-		enc->encoder->possible_clones = possible_crtcs;
-	}
-}
-
 /*
  * imx_drm_add_crtc - add a new crtc
  *
@@ -583,8 +406,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	imx_drm_update_possible_crtcs();
-
 	mutex_unlock(&imxdrm->mutex);
 
 	return 0;
@@ -621,56 +442,6 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
 
 /*
- * imx_drm_add_encoder - add a new encoder
- */
-int imx_drm_add_encoder(struct drm_encoder *encoder,
-		struct imx_drm_encoder **newenc, struct module *owner)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_encoder *imx_drm_encoder;
-	int ret;
-
-	mutex_lock(&imxdrm->mutex);
-
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
-
-	imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL);
-	if (!imx_drm_encoder) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	imx_drm_encoder->encoder = encoder;
-	imx_drm_encoder->owner = owner;
-
-	ret = imx_drm_encoder_register(imx_drm_encoder);
-	if (ret) {
-		ret = -ENOMEM;
-		goto err_register;
-	}
-
-	list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list);
-
-	*newenc = imx_drm_encoder;
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return 0;
-
-err_register:
-	kfree(imx_drm_encoder);
-err_alloc:
-err_busy:
-	mutex_unlock(&imxdrm->mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_encoder);
-
-/*
  * Find the DRM CRTC possible mask for the device node cookie/id.
  *
  * The encoder possible masks are defined by their position in the
@@ -736,49 +507,6 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
 
-int imx_drm_encoder_add_possible_crtcs(
-		struct imx_drm_encoder *imx_drm_encoder,
-		struct device_node *np)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct of_phandle_args args;
-	struct crtc_cookie *c;
-	int ret = 0;
-	int i;
-
-	if (!list_empty(&imx_drm_encoder->possible_crtcs))
-		return -EBUSY;
-
-	for (i = 0; !ret; i++) {
-		ret = of_parse_phandle_with_args(np, "crtcs",
-				"#crtc-cells", i, &args);
-		if (ret < 0)
-			break;
-
-		c = kzalloc(sizeof(*c), GFP_KERNEL);
-		if (!c) {
-			of_node_put(args.np);
-			return -ENOMEM;
-		}
-
-		c->cookie = args.np;
-		c->id = args.args_count > 0 ? args.args[0] : 0;
-
-		of_node_put(args.np);
-
-		mutex_lock(&imxdrm->mutex);
-
-		list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs);
-
-		mutex_unlock(&imxdrm->mutex);
-	}
-
-	imx_drm_update_possible_crtcs();
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
-
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
@@ -787,102 +515,6 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
-/*
- * imx_drm_remove_encoder - remove an encoder
- */
-int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct crtc_cookie *c, *tmp;
-
-	mutex_lock(&imxdrm->mutex);
-
-	imx_drm_encoder_unregister(imx_drm_encoder);
-
-	list_del(&imx_drm_encoder->list);
-
-	list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs,
-			list)
-		kfree(c);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	kfree(imx_drm_encoder);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_encoder);
-
-/*
- * imx_drm_add_connector - add a connector
- */
-int imx_drm_add_connector(struct drm_connector *connector,
-		struct imx_drm_connector **new_con,
-		struct module *owner)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-	struct imx_drm_connector *imx_drm_connector;
-	int ret;
-
-	mutex_lock(&imxdrm->mutex);
-
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
-
-	imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL);
-	if (!imx_drm_connector) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
-
-	imx_drm_connector->connector = connector;
-	imx_drm_connector->owner = owner;
-
-	ret = imx_drm_connector_register(imx_drm_connector);
-	if (ret)
-		goto err_register;
-
-	list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list);
-
-	*new_con = imx_drm_connector;
-
-	mutex_unlock(&imxdrm->mutex);
-
-	return 0;
-
-err_register:
-	kfree(imx_drm_connector);
-err_alloc:
-err_busy:
-	mutex_unlock(&imxdrm->mutex);
-
-	return ret;
-}
-EXPORT_SYMBOL_GPL(imx_drm_add_connector);
-
-/*
- * imx_drm_remove_connector - remove a connector
- */
-int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector)
-{
-	struct imx_drm_device *imxdrm = __imx_drm_device();
-
-	mutex_lock(&imxdrm->mutex);
-
-	imx_drm_connector_unregister(imx_drm_connector);
-
-	list_del(&imx_drm_connector->list);
-
-	mutex_unlock(&imxdrm->mutex);
-
-	kfree(imx_drm_connector);
-
-	return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_remove_connector);
-
 static const struct drm_ioctl_desc imx_drm_ioctls[] = {
 	/* none so far */
 };
@@ -1030,8 +662,6 @@ static int __init imx_drm_init(void)
 		return -ENOMEM;
 
 	mutex_init(&imx_drm_device->mutex);
-	INIT_LIST_HEAD(&imx_drm_device->connector_list);
-	INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index d13d518e8eb9..c5b97e9ce9a0 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -38,18 +38,6 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc);
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc);
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc);
 
-struct imx_drm_encoder;
-int imx_drm_add_encoder(struct drm_encoder *encoder,
-		struct imx_drm_encoder **new_enc,
-		struct module *owner);
-int imx_drm_remove_encoder(struct imx_drm_encoder *);
-
-struct imx_drm_connector;
-int imx_drm_add_connector(struct drm_connector *connector,
-		struct imx_drm_connector **new_con,
-		struct module *owner);
-int imx_drm_remove_connector(struct imx_drm_connector *);
-
 void imx_drm_mode_config_init(struct drm_device *drm);
 
 struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb);
@@ -62,8 +50,6 @@ int imx_drm_panel_format(struct drm_encoder *encoder,
 struct device_node;
 
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
-int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
-		struct device_node *np);
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np);
 
-- 
1.7.4.4

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

* [PATCH RFC 38/46] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group()
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Since we're now operating like a conventional DRM driver, doing all
the initialisation within the driver's ->load callback, we don't
need to mess around with the mode groups - we can rely on the one
in the DRM platform code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 7872d13689ea..10cfea0e948a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -274,12 +274,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_kms_helper_poll_init(drm);
 
-	/* setup the grouping for the legacy output */
-	ret = drm_mode_group_init_legacy_group(drm,
-			&drm->primary->mode_group);
-	if (ret)
-		goto err_kms;
-
 	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
-- 
1.7.4.4

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

* [PATCH RFC 38/46] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group()
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Since we're now operating like a conventional DRM driver, doing all
the initialisation within the driver's ->load callback, we don't
need to mess around with the mode groups - we can rely on the one
in the DRM platform code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |    6 ------
 1 files changed, 0 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 7872d13689ea..10cfea0e948a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -274,12 +274,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_kms_helper_poll_init(drm);
 
-	/* setup the grouping for the legacy output */
-	ret = drm_mode_group_init_legacy_group(drm,
-			&drm->primary->mode_group);
-	if (ret)
-		goto err_kms;
-
 	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
-- 
1.7.4.4

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

* [PATCH RFC 39/46] imx-drm: imx-drm-core: kill off mutex
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

This mutex doesn't protect anything anymore; get rid of it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   26 +++-----------------------
 1 files changed, 3 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 10cfea0e948a..0172739a00fe 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,14 +40,12 @@ struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
-	struct mutex				mutex;
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
 };
 
 struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
-	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	struct crtc_cookie			cookie;
@@ -270,8 +268,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_mode_config_init(drm);
 
-	mutex_lock(&imxdrm->mutex);
-
 	drm_kms_helper_poll_init(drm);
 
 	ret = drm_vblank_init(drm, MAX_CRTC);
@@ -285,12 +281,10 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->vblank_disable_allowed = true;
 
-	mutex_unlock(&imxdrm->mutex);
-
 	/* Now try and bind all our sub-components */
 	ret = component_bind_all(drm->dev, drm);
 	if (ret)
-		goto err_relock;
+		goto err_vblank;
 
 	/*
 	 * All components are now added, we can publish the connector sysfs
@@ -330,13 +324,11 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 err_unbind:
 	component_unbind_all(drm->dev, drm);
-err_relock:
-	mutex_lock(&imxdrm->mutex);
+err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
-	mutex_unlock(&imxdrm->mutex);
 
 	return ret;
 }
@@ -356,8 +348,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	struct imx_drm_crtc *imx_drm_crtc;
 	int ret;
 
-	mutex_lock(&imxdrm->mutex);
-
 	/*
 	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
 	 * pass IDs greater than this to those functions.
@@ -384,7 +374,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	imx_drm_crtc->cookie.id = id;
 	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
-	imx_drm_crtc->imxdrm = imxdrm;
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
@@ -400,8 +389,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	mutex_unlock(&imxdrm->mutex);
-
 	return 0;
 
 err_register:
@@ -409,7 +396,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	kfree(imx_drm_crtc);
 err_alloc:
 err_busy:
-	mutex_unlock(&imxdrm->mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -419,16 +405,12 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
  */
 int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 {
-	struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
-
-	mutex_lock(&imxdrm->mutex);
+	struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
 
 	drm_crtc_cleanup(imx_drm_crtc->crtc);
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
-	mutex_unlock(&imxdrm->mutex);
-
 	kfree(imx_drm_crtc);
 
 	return 0;
@@ -655,8 +637,6 @@ static int __init imx_drm_init(void)
 	if (!imx_drm_device)
 		return -ENOMEM;
 
-	mutex_init(&imx_drm_device->mutex);
-
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
 		goto err_pdrv;
-- 
1.7.4.4

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

* [PATCH RFC 39/46] imx-drm: imx-drm-core: kill off mutex
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

This mutex doesn't protect anything anymore; get rid of it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   26 +++-----------------------
 1 files changed, 3 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 10cfea0e948a..0172739a00fe 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -40,14 +40,12 @@ struct imx_drm_device {
 	struct drm_device			*drm;
 	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
-	struct mutex				mutex;
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
 };
 
 struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
-	struct imx_drm_device			*imxdrm;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	struct crtc_cookie			cookie;
@@ -270,8 +268,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_mode_config_init(drm);
 
-	mutex_lock(&imxdrm->mutex);
-
 	drm_kms_helper_poll_init(drm);
 
 	ret = drm_vblank_init(drm, MAX_CRTC);
@@ -285,12 +281,10 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 	 */
 	drm->vblank_disable_allowed = true;
 
-	mutex_unlock(&imxdrm->mutex);
-
 	/* Now try and bind all our sub-components */
 	ret = component_bind_all(drm->dev, drm);
 	if (ret)
-		goto err_relock;
+		goto err_vblank;
 
 	/*
 	 * All components are now added, we can publish the connector sysfs
@@ -330,13 +324,11 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 err_unbind:
 	component_unbind_all(drm->dev, drm);
-err_relock:
-	mutex_lock(&imxdrm->mutex);
+err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
 	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
-	mutex_unlock(&imxdrm->mutex);
 
 	return ret;
 }
@@ -356,8 +348,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	struct imx_drm_crtc *imx_drm_crtc;
 	int ret;
 
-	mutex_lock(&imxdrm->mutex);
-
 	/*
 	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
 	 * pass IDs greater than this to those functions.
@@ -384,7 +374,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	imx_drm_crtc->cookie.id = id;
 	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
-	imx_drm_crtc->imxdrm = imxdrm;
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
@@ -400,8 +389,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	drm_crtc_init(drm, crtc,
 			imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
 
-	mutex_unlock(&imxdrm->mutex);
-
 	return 0;
 
 err_register:
@@ -409,7 +396,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	kfree(imx_drm_crtc);
 err_alloc:
 err_busy:
-	mutex_unlock(&imxdrm->mutex);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -419,16 +405,12 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
  */
 int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 {
-	struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm;
-
-	mutex_lock(&imxdrm->mutex);
+	struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private;
 
 	drm_crtc_cleanup(imx_drm_crtc->crtc);
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
-	mutex_unlock(&imxdrm->mutex);
-
 	kfree(imx_drm_crtc);
 
 	return 0;
@@ -655,8 +637,6 @@ static int __init imx_drm_init(void)
 	if (!imx_drm_device)
 		return -ENOMEM;
 
-	mutex_init(&imx_drm_device->mutex);
-
 	ret = platform_driver_register(&imx_drm_pdrv);
 	if (ret)
 		goto err_pdrv;
-- 
1.7.4.4

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

* [PATCH RFC 40/46] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

It is now no longer necessary to keep this structure around; we can
allocate it upon DRM driver load and destroy it thereafter without
affecting the other components now.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   47 ++++---------------------------
 1 files changed, 6 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 0172739a00fe..8e257c5fb041 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -38,7 +38,6 @@ struct imx_drm_crtc;
 
 struct imx_drm_device {
 	struct drm_device			*drm;
-	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
@@ -206,13 +205,6 @@ int imx_drm_connector_mode_valid(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(imx_drm_connector_mode_valid);
 
-static struct imx_drm_device *imx_drm_device;
-
-static struct imx_drm_device *__imx_drm_device(void)
-{
-	return imx_drm_device;
-}
-
 void imx_drm_connector_destroy(struct drm_connector *connector)
 {
 	drm_sysfs_connector_remove(connector);
@@ -236,10 +228,14 @@ static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
  */
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm;
 	struct drm_connector *connector;
 	int ret;
 
+	imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+	if (!imxdrm)
+		return -ENOMEM;
+
 	imxdrm->drm = drm;
 
 	drm->dev_private = imxdrm;
@@ -602,8 +598,6 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	imx_drm_device->dev = &pdev->dev;
-
 	return component_master_add(&pdev->dev, &imx_drm_ops);
 }
 
@@ -628,36 +622,7 @@ static struct platform_driver imx_drm_pdrv = {
 		.of_match_table = imx_drm_dt_ids,
 	},
 };
-
-static int __init imx_drm_init(void)
-{
-	int ret;
-
-	imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
-	if (!imx_drm_device)
-		return -ENOMEM;
-
-	ret = platform_driver_register(&imx_drm_pdrv);
-	if (ret)
-		goto err_pdrv;
-
-	return 0;
-
-err_pdrv:
-	kfree(imx_drm_device);
-
-	return ret;
-}
-
-static void __exit imx_drm_exit(void)
-{
-	platform_driver_unregister(&imx_drm_pdrv);
-
-	kfree(imx_drm_device);
-}
-
-module_init(imx_drm_init);
-module_exit(imx_drm_exit);
+module_platform_driver(imx_drm_pdrv);
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("i.MX drm driver core");
-- 
1.7.4.4

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

* [PATCH RFC 40/46] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

It is now no longer necessary to keep this structure around; we can
allocate it upon DRM driver load and destroy it thereafter without
affecting the other components now.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   47 ++++---------------------------
 1 files changed, 6 insertions(+), 41 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 0172739a00fe..8e257c5fb041 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -38,7 +38,6 @@ struct imx_drm_crtc;
 
 struct imx_drm_device {
 	struct drm_device			*drm;
-	struct device				*dev;
 	struct imx_drm_crtc			*crtc[MAX_CRTC];
 	int					pipes;
 	struct drm_fbdev_cma			*fbhelper;
@@ -206,13 +205,6 @@ int imx_drm_connector_mode_valid(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(imx_drm_connector_mode_valid);
 
-static struct imx_drm_device *imx_drm_device;
-
-static struct imx_drm_device *__imx_drm_device(void)
-{
-	return imx_drm_device;
-}
-
 void imx_drm_connector_destroy(struct drm_connector *connector)
 {
 	drm_sysfs_connector_remove(connector);
@@ -236,10 +228,14 @@ static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
  */
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
-	struct imx_drm_device *imxdrm = __imx_drm_device();
+	struct imx_drm_device *imxdrm;
 	struct drm_connector *connector;
 	int ret;
 
+	imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL);
+	if (!imxdrm)
+		return -ENOMEM;
+
 	imxdrm->drm = drm;
 
 	drm->dev_private = imxdrm;
@@ -602,8 +598,6 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	imx_drm_device->dev = &pdev->dev;
-
 	return component_master_add(&pdev->dev, &imx_drm_ops);
 }
 
@@ -628,36 +622,7 @@ static struct platform_driver imx_drm_pdrv = {
 		.of_match_table = imx_drm_dt_ids,
 	},
 };
-
-static int __init imx_drm_init(void)
-{
-	int ret;
-
-	imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL);
-	if (!imx_drm_device)
-		return -ENOMEM;
-
-	ret = platform_driver_register(&imx_drm_pdrv);
-	if (ret)
-		goto err_pdrv;
-
-	return 0;
-
-err_pdrv:
-	kfree(imx_drm_device);
-
-	return ret;
-}
-
-static void __exit imx_drm_exit(void)
-{
-	platform_driver_unregister(&imx_drm_pdrv);
-
-	kfree(imx_drm_device);
-}
-
-module_init(imx_drm_init);
-module_exit(imx_drm_exit);
+module_platform_driver(imx_drm_pdrv);
 
 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
 MODULE_DESCRIPTION("i.MX drm driver core");
-- 
1.7.4.4

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

* [PATCH RFC 41/46] imx-drm: imx-drm-core: various cleanups
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Various cleanups are possible after the previous round of changes; these
have no real functional bearing other than tidying up the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   47 +++++++++++--------------------
 drivers/staging/imx-drm/imx-drm.h      |    5 +--
 2 files changed, 19 insertions(+), 33 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8e257c5fb041..33c020867ed0 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -15,12 +15,12 @@
  */
 #include <linux/component.h>
 #include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/module.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
@@ -28,12 +28,6 @@
 
 #define MAX_CRTC	4
 
-struct crtc_cookie {
-	void *cookie;
-	int id;
-	struct list_head list;
-};
-
 struct imx_drm_crtc;
 
 struct imx_drm_device {
@@ -47,7 +41,8 @@ struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
-	struct crtc_cookie			cookie;
+	void					*cookie;
+	int					id;
 	int					mux_id;
 };
 
@@ -271,9 +266,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		goto err_kms;
 
 	/*
-	 * with vblank_disable_allowed = true, 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)
+	 * with vblank_disable_allowed = true, 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->vblank_disable_allowed = true;
 
@@ -348,26 +343,20 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
 	 * pass IDs greater than this to those functions.
 	 */
-	if (imxdrm->pipes >= MAX_CRTC) {
-		ret = -EINVAL;
-		goto err_busy;
-	}
+	if (imxdrm->pipes >= MAX_CRTC)
+		return -EINVAL;
 
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
+	if (imxdrm->drm->open_count)
+		return -EBUSY;
 
 	imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
-	if (!imx_drm_crtc) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
+	if (!imx_drm_crtc)
+		return -ENOMEM;
 
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
 	imx_drm_crtc->pipe = imxdrm->pipes++;
-	imx_drm_crtc->cookie.cookie = cookie;
-	imx_drm_crtc->cookie.id = id;
+	imx_drm_crtc->cookie = cookie;
+	imx_drm_crtc->id = id;
 	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
 
@@ -390,8 +379,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 err_register:
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 	kfree(imx_drm_crtc);
-err_alloc:
-err_busy:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -427,8 +414,8 @@ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-		if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
-		    imx_drm_crtc->cookie.cookie == cookie)
+		if (imx_drm_crtc && imx_drm_crtc->id == id &&
+		    imx_drm_crtc->cookie == cookie)
 			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
 	}
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index c5b97e9ce9a0..0a26222ec539 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -5,13 +5,14 @@
 
 #define IPU_PIX_FMT_GBR24	v4l2_fourcc('G', 'B', 'R', '3')
 
+struct device_node;
 struct drm_crtc;
 struct drm_connector;
 struct drm_device;
 struct drm_encoder;
-struct imx_drm_crtc;
 struct drm_fbdev_cma;
 struct drm_framebuffer;
+struct imx_drm_crtc;
 struct platform_device;
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
@@ -47,8 +48,6 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
 
-struct device_node;
-
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np);
-- 
1.7.4.4

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

* [PATCH RFC 41/46] imx-drm: imx-drm-core: various cleanups
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Various cleanups are possible after the previous round of changes; these
have no real functional bearing other than tidying up the code.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   47 +++++++++++--------------------
 drivers/staging/imx-drm/imx-drm.h      |    5 +--
 2 files changed, 19 insertions(+), 33 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 8e257c5fb041..33c020867ed0 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -15,12 +15,12 @@
  */
 #include <linux/component.h>
 #include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_crtc_helper.h>
-#include <linux/fb.h>
-#include <linux/module.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
@@ -28,12 +28,6 @@
 
 #define MAX_CRTC	4
 
-struct crtc_cookie {
-	void *cookie;
-	int id;
-	struct list_head list;
-};
-
 struct imx_drm_crtc;
 
 struct imx_drm_device {
@@ -47,7 +41,8 @@ struct imx_drm_crtc {
 	struct drm_crtc				*crtc;
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
-	struct crtc_cookie			cookie;
+	void					*cookie;
+	int					id;
 	int					mux_id;
 };
 
@@ -271,9 +266,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		goto err_kms;
 
 	/*
-	 * with vblank_disable_allowed = true, 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)
+	 * with vblank_disable_allowed = true, 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->vblank_disable_allowed = true;
 
@@ -348,26 +343,20 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	 * The vblank arrays are dimensioned by MAX_CRTC - we can't
 	 * pass IDs greater than this to those functions.
 	 */
-	if (imxdrm->pipes >= MAX_CRTC) {
-		ret = -EINVAL;
-		goto err_busy;
-	}
+	if (imxdrm->pipes >= MAX_CRTC)
+		return -EINVAL;
 
-	if (imxdrm->drm->open_count) {
-		ret = -EBUSY;
-		goto err_busy;
-	}
+	if (imxdrm->drm->open_count)
+		return -EBUSY;
 
 	imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL);
-	if (!imx_drm_crtc) {
-		ret = -ENOMEM;
-		goto err_alloc;
-	}
+	if (!imx_drm_crtc)
+		return -ENOMEM;
 
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
 	imx_drm_crtc->pipe = imxdrm->pipes++;
-	imx_drm_crtc->cookie.cookie = cookie;
-	imx_drm_crtc->cookie.id = id;
+	imx_drm_crtc->cookie = cookie;
+	imx_drm_crtc->id = id;
 	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
 	imx_drm_crtc->crtc = crtc;
 
@@ -390,8 +379,6 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 err_register:
 	imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 	kfree(imx_drm_crtc);
-err_alloc:
-err_busy:
 	return ret;
 }
 EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
@@ -427,8 +414,8 @@ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-		if (imx_drm_crtc && imx_drm_crtc->cookie.id == id &&
-		    imx_drm_crtc->cookie.cookie == cookie)
+		if (imx_drm_crtc && imx_drm_crtc->id == id &&
+		    imx_drm_crtc->cookie == cookie)
 			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
 	}
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index c5b97e9ce9a0..0a26222ec539 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -5,13 +5,14 @@
 
 #define IPU_PIX_FMT_GBR24	v4l2_fourcc('G', 'B', 'R', '3')
 
+struct device_node;
 struct drm_crtc;
 struct drm_connector;
 struct drm_device;
 struct drm_encoder;
-struct imx_drm_crtc;
 struct drm_fbdev_cma;
 struct drm_framebuffer;
+struct imx_drm_crtc;
 struct platform_device;
 
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
@@ -47,8 +48,6 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
 int imx_drm_panel_format(struct drm_encoder *encoder,
 		u32 interface_pix_fmt);
 
-struct device_node;
-
 int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
 int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np);
-- 
1.7.4.4

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

* [PATCH RFC 42/46] imx-drm: imx-drm-core: add core hotplug connector support
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Add core imx-drm support for hotplug connector support.  We need to
setup the poll helper after we've setup the connectors; the helper
scans the connectors to determine their capabilities.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 33c020867ed0..6b86bfeb091f 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -69,6 +69,8 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+	drm_kms_helper_poll_fini(drm);
+
 #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_fini(imxdrm->fbhelper);
@@ -77,7 +79,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 	component_unbind_all(drm->dev, drm);
 
 	drm_vblank_cleanup(drm);
-	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 
 	return 0;
@@ -213,8 +214,19 @@ void imx_drm_encoder_destroy(struct drm_encoder *encoder)
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
 
+static void imx_drm_output_poll_changed(struct drm_device *drm)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (imxdrm->fbhelper)
+		drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
+}
+
 static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
+	.output_poll_changed = imx_drm_output_poll_changed,
 };
 
 /*
@@ -259,8 +271,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_mode_config_init(drm);
 
-	drm_kms_helper_poll_init(drm);
-
 	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
@@ -311,6 +321,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		goto err_unbind;
 	}
 #endif
+
+	drm_kms_helper_poll_init(drm);
+
 	return 0;
 
 err_unbind:
@@ -318,7 +331,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
-	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 
 	return ret;
-- 
1.7.4.4

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

* [PATCH RFC 42/46] imx-drm: imx-drm-core: add core hotplug connector support
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Add core imx-drm support for hotplug connector support.  We need to
setup the poll helper after we've setup the connectors; the helper
scans the connectors to determine their capabilities.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c |   20 ++++++++++++++++----
 1 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 33c020867ed0..6b86bfeb091f 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -69,6 +69,8 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 
+	drm_kms_helper_poll_fini(drm);
+
 #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
 	if (imxdrm->fbhelper)
 		drm_fbdev_cma_fini(imxdrm->fbhelper);
@@ -77,7 +79,6 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 	component_unbind_all(drm->dev, drm);
 
 	drm_vblank_cleanup(drm);
-	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 
 	return 0;
@@ -213,8 +214,19 @@ void imx_drm_encoder_destroy(struct drm_encoder *encoder)
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy);
 
+static void imx_drm_output_poll_changed(struct drm_device *drm)
+{
+	struct imx_drm_device *imxdrm = drm->dev_private;
+
+#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+	if (imxdrm->fbhelper)
+		drm_fbdev_cma_hotplug_event(imxdrm->fbhelper);
+#endif
+}
+
 static struct drm_mode_config_funcs imx_drm_mode_config_funcs = {
 	.fb_create = drm_fb_cma_create,
+	.output_poll_changed = imx_drm_output_poll_changed,
 };
 
 /*
@@ -259,8 +271,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
 	drm_mode_config_init(drm);
 
-	drm_kms_helper_poll_init(drm);
-
 	ret = drm_vblank_init(drm, MAX_CRTC);
 	if (ret)
 		goto err_kms;
@@ -311,6 +321,9 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 		goto err_unbind;
 	}
 #endif
+
+	drm_kms_helper_poll_init(drm);
+
 	return 0;
 
 err_unbind:
@@ -318,7 +331,6 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 err_vblank:
 	drm_vblank_cleanup(drm);
 err_kms:
-	drm_kms_helper_poll_fini(drm);
 	drm_mode_config_cleanup(drm);
 
 	return ret;
-- 
1.7.4.4

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

* [PATCH RFC 43/46] imx-drm: imx-hdmi: add hotplug support to HDMI component
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Add hotplug support.  We have to make the interrupt handler threaded so
we can call drm_helper_hpd_irq_event().  Keeping in mind that we will
want to share the interrupt with other HDMI interface drivers (eg, audio
and CEC) put the groundwork in now for that, rather than just using
IRQF_ONESHOT.

Also, we must not call drm_helper_hpd_irq_event() until we have fully
setup the connector; keep the interrupt(s) muted until after that point.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   40 +++++++++++++++++++++++++++++------
 1 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 512b39710530..097403a602d8 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -124,6 +124,8 @@ struct imx_hdmi {
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
 
+	enum drm_connector_status connector_status;
+
 	struct hdmi_data_info hdmi_data;
 	int vic;
 
@@ -1305,9 +1307,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Clear Hotplug interrupts */
 	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
 
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
 	return 0;
 }
 
@@ -1376,8 +1375,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
 static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 							*connector, bool force)
 {
-	/* FIXME */
-	return connector_status_connected;
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+	return hdmi->connector_status;
 }
 
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1491,6 +1491,18 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
 	.best_encoder = imx_hdmi_connector_best_encoder,
 };
 
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+	struct imx_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+	if (intr_stat)
+		hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
 static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 {
 	struct imx_hdmi *hdmi = dev_id;
@@ -1507,17 +1519,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 
 			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
+			hdmi->connector_status = connector_status_connected;
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
 			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
+			hdmi->connector_status = connector_status_disconnected;
 			imx_hdmi_poweroff(hdmi);
 		}
+		drm_helper_hpd_irq_event(hdmi->connector.dev);
 	}
 
 	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
 	return IRQ_HANDLED;
 }
@@ -1531,6 +1547,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 	if (ret)
 		return ret;
 
+	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
 	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
 	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS);
@@ -1582,6 +1600,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	hdmi->dev = dev;
+	hdmi->connector_status = connector_status_disconnected;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
@@ -1605,8 +1624,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (irq < 0)
 		return -EINVAL;
 
-	ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
-			       dev_name(dev), hdmi);
+	ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+					imx_hdmi_irq, IRQF_SHARED,
+					dev_name(dev), hdmi);
 	if (ret)
 		return ret;
 
@@ -1682,6 +1702,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		goto err_iahb;
 
+	/* Unmute interrupts */
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1699,6 +1722,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 
+	/* Disable all interrupts */
+	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
 	hdmi->connector.funcs->destroy(&hdmi->connector);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
-- 
1.7.4.4

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

* [PATCH RFC 43/46] imx-drm: imx-hdmi: add hotplug support to HDMI component
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Add hotplug support.  We have to make the interrupt handler threaded so
we can call drm_helper_hpd_irq_event().  Keeping in mind that we will
want to share the interrupt with other HDMI interface drivers (eg, audio
and CEC) put the groundwork in now for that, rather than just using
IRQF_ONESHOT.

Also, we must not call drm_helper_hpd_irq_event() until we have fully
setup the connector; keep the interrupt(s) muted until after that point.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-hdmi.c |   40 +++++++++++++++++++++++++++++------
 1 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 512b39710530..097403a602d8 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -124,6 +124,8 @@ struct imx_hdmi {
 	struct clk *isfr_clk;
 	struct clk *iahb_clk;
 
+	enum drm_connector_status connector_status;
+
 	struct hdmi_data_info hdmi_data;
 	int vic;
 
@@ -1305,9 +1307,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 	/* Clear Hotplug interrupts */
 	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
 
-	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
 	return 0;
 }
 
@@ -1376,8 +1375,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
 static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
 							*connector, bool force)
 {
-	/* FIXME */
-	return connector_status_connected;
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+	return hdmi->connector_status;
 }
 
 static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -1491,6 +1491,18 @@ static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
 	.best_encoder = imx_hdmi_connector_best_encoder,
 };
 
+static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
+{
+	struct imx_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+	if (intr_stat)
+		hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
 static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 {
 	struct imx_hdmi *hdmi = dev_id;
@@ -1507,17 +1519,21 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 
 			hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
+			hdmi->connector_status = connector_status_connected;
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
 			hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0);
 
+			hdmi->connector_status = connector_status_disconnected;
 			imx_hdmi_poweroff(hdmi);
 		}
+		drm_helper_hpd_irq_event(hdmi->connector.dev);
 	}
 
 	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
 	return IRQ_HANDLED;
 }
@@ -1531,6 +1547,8 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
 	if (ret)
 		return ret;
 
+	hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
 	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
 	drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
 			 DRM_MODE_ENCODER_TMDS);
@@ -1582,6 +1600,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		return -ENOMEM;
 
 	hdmi->dev = dev;
+	hdmi->connector_status = connector_status_disconnected;
 	hdmi->sample_rate = 48000;
 	hdmi->ratio = 100;
 
@@ -1605,8 +1624,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (irq < 0)
 		return -EINVAL;
 
-	ret = devm_request_irq(dev, irq, imx_hdmi_irq, 0,
-			       dev_name(dev), hdmi);
+	ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
+					imx_hdmi_irq, IRQF_SHARED,
+					dev_name(dev), hdmi);
 	if (ret)
 		return ret;
 
@@ -1682,6 +1702,9 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	if (ret)
 		goto err_iahb;
 
+	/* Unmute interrupts */
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
@@ -1699,6 +1722,9 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 
+	/* Disable all interrupts */
+	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
 	hdmi->connector.funcs->destroy(&hdmi->connector);
 	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 
-- 
1.7.4.4

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

* [PATCH RFC 44/46] imx-drm: dw-hdmi-audio: add audio driver
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Add ALSA based HDMI audio driver for imx-hdmi.  The imx-hdmi is a
Synopsis DesignWare module, so let's name it after that.  The only
buffer format supported is its own special IEC958 based format, which
is not compatible with any ALSA format.  To avoid doing too much data
manipulation within the driver, we support only ALSAs IEC958 LE, and
24-bit PCM formats for 2 to 6 channels.

This allows us to modify the buffer in place as each period is passed
for DMA without needing a separate buffer.

A more desirable solution would be to have this conversion in userspace,
but ALSA does not appear to allow such transformations outside of
libasound itself.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile        |    3 +-
 drivers/staging/imx-drm/dw-hdmi-audio.c |  500 +++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h |   13 +
 drivers/staging/imx-drm/imx-hdmi.c      |   21 ++
 drivers/staging/imx-drm/imx-hdmi.h      |    4 +
 5 files changed, 540 insertions(+), 1 deletions(-)
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 129e3a3f59f1..f554aa631993 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,6 @@
 
 imxdrm-objs := imx-drm-core.o
+imxhdmi-objs := imx-hdmi.o dw-hdmi-audio.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
@@ -10,4 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imxhdmi.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
new file mode 100644
index 000000000000..946055d2a975
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -0,0 +1,500 @@
+/*
+ * DesignWare HDMI audio driver
+ *
+ * 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.
+ *
+ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#include "imx-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-audio"
+
+/* Provide some bits rather than bit offsets */
+enum {
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST = HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK = HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK,
+	HDMI_AHB_DMA_START_START = BIT(HDMI_AHB_DMA_START_START_OFFSET),
+	HDMI_AHB_DMA_STOP_STOP = BIT(HDMI_AHB_DMA_STOP_STOP_OFFSET),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
+	HDMI_IH_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
+};
+
+struct snd_dw_hdmi {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	void __iomem *base;
+	int irq;
+	struct imx_hdmi *hdmi;
+	struct snd_pcm_substream *substream;
+	void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
+	void *buf_base;
+	dma_addr_t buf_addr;
+	unsigned buf_offset;
+	unsigned buf_period;
+	unsigned buf_size;
+	unsigned channels;
+	uint8_t revision;
+	uint8_t iec_offset;
+	uint8_t cs[192][8];
+};
+
+static void dw_hdmi_writeb(unsigned long val, void __iomem *ptr)
+{
+	writeb(val, ptr);
+}
+
+static unsigned dw_hdmi_readb(void __iomem *ptr)
+{
+	return readb(ptr);
+}
+
+static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
+{
+	writeb_relaxed(val, ptr);
+	writeb_relaxed(val >> 8, ptr + 1);
+	writeb_relaxed(val >> 16, ptr + 2);
+	writeb_relaxed(val >> 24, ptr + 3);
+}
+
+/*
+ * Convert to hardware format: The userspace buffer contains IEC958 samples,
+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4.  We
+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
+ * samples in 23..0.
+ *
+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
+ *
+ * Ideally, we could do with having the data properly formatted in userspace.
+ */
+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *ptr = dw->buf_base + offset;
+	uint32_t *end = dw->buf_base + offset + bytes;
+
+	do {
+		uint32_t b, sample = *ptr;
+
+		b = (sample & 8) << (28 - 3);
+
+		sample >>= 4;
+
+		*ptr++ = sample | b;
+	} while (ptr < end);
+}
+
+static uint32_t parity(uint32_t sample)
+{
+	sample ^= sample >> 16;
+	sample ^= sample >> 8;
+	sample ^= sample >> 4;
+	sample ^= sample >> 2;
+	sample ^= sample >> 1;
+	return (sample & 1) << 27;
+}
+
+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *ptr = dw->buf_base + offset;
+	uint32_t *end = dw->buf_base + offset + bytes;
+
+	do {
+		unsigned i;
+		uint8_t *cs;
+
+		cs = dw->cs[dw->iec_offset++];
+		if (dw->iec_offset >= 192)
+			dw->iec_offset = 0;
+
+		i = dw->channels;
+		do {
+			uint32_t sample = *ptr;
+
+			sample &= ~0xff000000;
+			sample |= *cs++ << 24;
+			sample |= parity(sample & ~0xf8000000);
+
+			*ptr++ = sample;
+		} while (--i);
+	} while (ptr < end);
+}
+
+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
+	struct snd_pcm_runtime *runtime)
+{
+	uint8_t cs[3];
+	unsigned ch, i, j;
+
+	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+	cs[1] = IEC958_AES1_CON_GENERAL;
+	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
+	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+
+	switch (runtime->rate) {
+	case 32000:
+		cs[3] |= IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		cs[3] |= IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		cs[3] |= IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		cs[3] |= IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		cs[3] |= IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		cs[3] |= IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		cs[3] |= IEC958_AES3_CON_FS_192000;
+		break;
+	}
+
+	memset(dw->cs, 0, sizeof(dw->cs));
+
+	for (ch = 0; ch < 8; ch++) {
+		cs[2] &= ~IEC958_AES2_CON_CHANNEL;
+		cs[2] |= (ch + 1) << 4;
+
+		for (i = 0; i < ARRAY_SIZE(cs); i++) {
+			unsigned c = cs[i];
+
+			for (j = 0; j < 8; j++, c >>= 1)
+				dw->cs[i * 8 + j][ch] = (c & 1) << 2;
+		}
+	}
+	dw->cs[0][0] |= BIT(4);
+}
+
+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
+{
+	unsigned long start, stop;
+
+	start = dw->buf_addr + dw->buf_offset;
+	stop = start + dw->buf_period - 1;
+
+	dw->reformat(dw, dw->buf_offset, dw->buf_period);
+
+	/* Setup the hardware start/stop addresses */
+	dw_hdmi_writel(start, dw->base + HDMI_AHB_DMA_STRADDR0);
+	dw_hdmi_writel(stop, dw->base + HDMI_AHB_DMA_STPADDR0);
+
+	/* Clear all irqs before enabling irqs and starting DMA */
+	dw_hdmi_writeb(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+		       dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+	dw_hdmi_writeb(~HDMI_AHB_DMA_DONE, dw->base + HDMI_AHB_DMA_MASK);
+	dw_hdmi_writeb(HDMI_AHB_DMA_START_START, dw->base + HDMI_AHB_DMA_START);
+}
+
+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
+{
+	dw->substream = NULL;
+
+	/* Disable interrupts before disabling DMA */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+	dw_hdmi_writeb(HDMI_AHB_DMA_STOP_STOP, dw->base + HDMI_AHB_DMA_STOP);
+}
+
+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
+{
+	struct snd_dw_hdmi *dw = data;
+	struct snd_pcm_substream *substream;
+	unsigned stat;
+
+	stat = dw_hdmi_readb(dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+	if (!stat)
+		return IRQ_NONE;
+
+	dw_hdmi_writeb(stat, dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+
+	substream = dw->substream;
+	if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
+		dw->buf_offset += dw->buf_period;
+		if (dw->buf_offset >= dw->buf_size)
+			dw->buf_offset = 0;
+
+		snd_pcm_period_elapsed(substream);
+		if (dw->substream) {
+			dw_hdmi_start_dma(dw);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct snd_pcm_hardware dw_hdmi_hw = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE,
+	.rates = SNDRV_PCM_RATE_32000 |
+		 SNDRV_PCM_RATE_44100 |
+		 SNDRV_PCM_RATE_48000 |
+		 SNDRV_PCM_RATE_88200 |
+		 SNDRV_PCM_RATE_96000 |
+		 SNDRV_PCM_RATE_176400 |
+		 SNDRV_PCM_RATE_192000,
+	.channels_min = 2,
+	.channels_max = 8,
+	.buffer_bytes_max = 64 * 1024,
+	.period_bytes_min = 256,
+	.period_bytes_max = 8192,	/* ERR004323: must limit to 8k */
+	.periods_min = 2,
+	.periods_max = 16,
+	.fifo_size = 0,
+};
+
+static int dw_hdmi_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	int ret;
+
+	/* Clear FIFO */
+	dw_hdmi_writeb(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+		       dw->base + HDMI_AHB_DMA_CONF0);
+
+	/* Configure interrupt polarities */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_POL);
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_BUFFPOL);
+
+	/* Keep interrupts masked */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+
+	ret = request_irq(dw->irq, snd_dw_hdmi_irq, IRQF_SHARED,
+			  "dw-hdmi-audio", dw);
+	if (ret)
+		return ret;
+
+	/* Un-mute done interrupt */
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+		       ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	runtime->hw = dw_hdmi_hw;
+	snd_pcm_limit_hw_rates(runtime);
+
+	return 0;
+}
+
+static int dw_hdmi_close(struct snd_pcm_substream *substream)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	/* Mute all interrupts */
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	free_irq(dw->irq, dw);
+
+	return 0;
+}
+
+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(params));
+}
+
+static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	uint8_t threshold, conf0, conf1;
+
+	/* Setup as per 3.0.5 FSL 4.1.0 BSP */
+	switch (dw->revision) {
+	case 0x0a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR4;
+		if (runtime->channels == 2)
+			threshold = 126;
+		else
+			threshold = 124;
+		break;
+	case 0x1a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR8;
+		threshold = 128;
+		break;
+	default:
+		/* NOTREACHED */
+		return -EINVAL;
+	}
+
+	imx_hdmi_set_sample_rate(dw->hdmi, runtime->rate);
+
+	/* Minimum number of bytes in the fifo. */
+	runtime->hw.fifo_size = threshold * 32;
+
+	conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
+	conf1 = (1 << runtime->channels) - 1;
+
+	dw_hdmi_writeb(threshold, dw->base + HDMI_AHB_DMA_THRSLD);
+	dw_hdmi_writeb(conf0, dw->base + HDMI_AHB_DMA_CONF0);
+	dw_hdmi_writeb(conf1, dw->base + HDMI_AHB_DMA_CONF1);
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		dw->reformat = dw_hdmi_reformat_iec958;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dw_hdmi_create_cs(dw, runtime);
+		dw->reformat = dw_hdmi_reformat_s24;
+		break;
+	}
+	dw->iec_offset = 0;
+	dw->channels = runtime->channels;
+	dw->buf_base = runtime->dma_area;
+	dw->buf_addr = runtime->dma_addr;
+	dw->buf_period = snd_pcm_lib_period_bytes(substream);
+	dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
+
+	return 0;
+}
+
+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dw->buf_offset = 0;
+		dw->substream = substream;
+		dw_hdmi_start_dma(dw);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		dw_hdmi_stop_dma(dw);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	return bytes_to_frames(runtime, dw->buf_offset);
+}
+
+static struct snd_pcm_ops snd_dw_hdmi_ops = {
+	.open = dw_hdmi_open,
+	.close = dw_hdmi_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = dw_hdmi_hw_params,
+	.hw_free = dw_hdmi_hw_free,
+	.prepare = dw_hdmi_prepare,
+	.trigger = dw_hdmi_trigger,
+	.pointer = dw_hdmi_pointer,
+};
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *dev,
+	void __iomem *base, int irq, struct imx_hdmi *hdmi)
+{
+	struct snd_dw_hdmi *dw;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	unsigned revision;
+	int ret;
+
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+	revision = dw_hdmi_readb(base + HDMI_REVISION_ID);
+	if (revision != 0x0a && revision != 0x1a) {
+		dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
+			revision);
+		return -ENXIO;
+	}
+
+	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			      THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
+	if (ret < 0)
+		return ret;
+
+	snd_card_set_dev(card, dev);
+
+	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+	strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s rev 0x%02x, irq %d", card->shortname, revision, irq);
+
+	dw = card->private_data;
+	dw->card = card;
+	dw->base = base;
+	dw->irq = irq;
+	dw->hdmi = hdmi;
+	dw->revision = revision;
+
+	ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
+	if (ret < 0)
+		goto err;
+
+	dw->pcm = pcm;
+	pcm->private_data = dw;
+	strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+			NULL, 0, 64 * 1024);
+
+	ret = snd_card_register(card);
+	if (ret < 0)
+		goto err;
+
+	*dwp = dw;
+
+	return 0;
+
+err:
+	snd_card_free(card);
+	return ret;
+}
+
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw)
+{
+	snd_card_free(dw->card);
+}
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
new file mode 100644
index 000000000000..82a709c9f612
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
@@ -0,0 +1,13 @@
+#ifndef DW_HDMI_AUDIO_H
+#define DW_HDMI_AUDIO_H
+
+#include <linux/irqreturn.h>
+
+struct snd_dw_hdmi;
+struct imx_hdmi;
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *,
+	void __iomem *, int, struct imx_hdmi *);
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw);
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 097403a602d8..eb196c0862c8 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -27,6 +27,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 
+#include "dw-hdmi-audio.h"
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-hdmi.h"
 #include "imx-drm.h"
@@ -119,6 +120,7 @@ struct imx_hdmi {
 	struct drm_connector connector;
 	struct drm_encoder encoder;
 
+	struct snd_dw_hdmi *audio;
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
 	struct clk *isfr_clk;
@@ -366,6 +368,13 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
 	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
 }
 
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
+{
+	hdmi->sample_rate = rate;
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
+
 /*
  * this submodule is responsible for the video data synchronization.
  * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1705,10 +1714,20 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
+	ret = snd_dw_hdmi_probe(&hdmi->audio, dev, hdmi->regs, irq, hdmi);
+	if (ret)
+		goto err_audio;
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
 
+err_audio:
+	/* Disable all interrupts */
+	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 err_iahb:
 	clk_disable_unprepare(hdmi->iahb_clk);
 err_isfr:
@@ -1722,6 +1741,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 
+	snd_dw_hdmi_remove(hdmi->audio);
+
 	/* Disable all interrupts */
 	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b677689db6..8029febdbabe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,8 @@ enum {
 	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
 	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
 };
+
+struct imx_hdmi;
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+
 #endif /* __IMX_HDMI_H__ */
-- 
1.7.4.4

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

* [PATCH RFC 44/46] imx-drm: dw-hdmi-audio: add audio driver
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Add ALSA based HDMI audio driver for imx-hdmi.  The imx-hdmi is a
Synopsis DesignWare module, so let's name it after that.  The only
buffer format supported is its own special IEC958 based format, which
is not compatible with any ALSA format.  To avoid doing too much data
manipulation within the driver, we support only ALSAs IEC958 LE, and
24-bit PCM formats for 2 to 6 channels.

This allows us to modify the buffer in place as each period is passed
for DMA without needing a separate buffer.

A more desirable solution would be to have this conversion in userspace,
but ALSA does not appear to allow such transformations outside of
libasound itself.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Makefile        |    3 +-
 drivers/staging/imx-drm/dw-hdmi-audio.c |  500 +++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/dw-hdmi-audio.h |   13 +
 drivers/staging/imx-drm/imx-hdmi.c      |   21 ++
 drivers/staging/imx-drm/imx-hdmi.h      |    4 +
 5 files changed, 540 insertions(+), 1 deletions(-)
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.c
 create mode 100644 drivers/staging/imx-drm/dw-hdmi-audio.h

diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 129e3a3f59f1..f554aa631993 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -1,5 +1,6 @@
 
 imxdrm-objs := imx-drm-core.o
+imxhdmi-objs := imx-hdmi.o dw-hdmi-audio.o
 
 obj-$(CONFIG_DRM_IMX) += imxdrm.o
 
@@ -10,4 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imxhdmi.o
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
new file mode 100644
index 000000000000..946055d2a975
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -0,0 +1,500 @@
+/*
+ * DesignWare HDMI audio driver
+ *
+ * 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.
+ *
+ * Written and tested against the (alleged) DW HDMI Tx found in iMX6S.
+ */
+#include <linux/io.h>
+#include <linux/interrupt.h>
+
+#include <sound/asoundef.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+
+#include "imx-hdmi.h"
+#include "dw-hdmi-audio.h"
+
+#define DRIVER_NAME "dw-hdmi-audio"
+
+/* Provide some bits rather than bit offsets */
+enum {
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST = HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK = HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK,
+	HDMI_AHB_DMA_START_START = BIT(HDMI_AHB_DMA_START_START_OFFSET),
+	HDMI_AHB_DMA_STOP_STOP = BIT(HDMI_AHB_DMA_STOP_STOP_OFFSET),
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY,
+	HDMI_IH_AHBDMAAUD_STAT0_ALL =
+		HDMI_IH_AHBDMAAUD_STAT0_ERROR |
+		HDMI_IH_AHBDMAAUD_STAT0_LOST |
+		HDMI_IH_AHBDMAAUD_STAT0_RETRY |
+		HDMI_IH_AHBDMAAUD_STAT0_DONE |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL |
+		HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY,
+};
+
+struct snd_dw_hdmi {
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	void __iomem *base;
+	int irq;
+	struct imx_hdmi *hdmi;
+	struct snd_pcm_substream *substream;
+	void (*reformat)(struct snd_dw_hdmi *, size_t, size_t);
+	void *buf_base;
+	dma_addr_t buf_addr;
+	unsigned buf_offset;
+	unsigned buf_period;
+	unsigned buf_size;
+	unsigned channels;
+	uint8_t revision;
+	uint8_t iec_offset;
+	uint8_t cs[192][8];
+};
+
+static void dw_hdmi_writeb(unsigned long val, void __iomem *ptr)
+{
+	writeb(val, ptr);
+}
+
+static unsigned dw_hdmi_readb(void __iomem *ptr)
+{
+	return readb(ptr);
+}
+
+static void dw_hdmi_writel(unsigned long val, void __iomem *ptr)
+{
+	writeb_relaxed(val, ptr);
+	writeb_relaxed(val >> 8, ptr + 1);
+	writeb_relaxed(val >> 16, ptr + 2);
+	writeb_relaxed(val >> 24, ptr + 3);
+}
+
+/*
+ * Convert to hardware format: The userspace buffer contains IEC958 samples,
+ * with the PCUV bits in bits 31..28 and audio samples in bits 27..4.  We
+ * need these to be in bits 27..24, with the IEC B bit in bit 28, and audio
+ * samples in 23..0.
+ *
+ * Default preamble in bits 3..0: 8 = block start, 4 = even 2 = odd
+ *
+ * Ideally, we could do with having the data properly formatted in userspace.
+ */
+static void dw_hdmi_reformat_iec958(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *ptr = dw->buf_base + offset;
+	uint32_t *end = dw->buf_base + offset + bytes;
+
+	do {
+		uint32_t b, sample = *ptr;
+
+		b = (sample & 8) << (28 - 3);
+
+		sample >>= 4;
+
+		*ptr++ = sample | b;
+	} while (ptr < end);
+}
+
+static uint32_t parity(uint32_t sample)
+{
+	sample ^= sample >> 16;
+	sample ^= sample >> 8;
+	sample ^= sample >> 4;
+	sample ^= sample >> 2;
+	sample ^= sample >> 1;
+	return (sample & 1) << 27;
+}
+
+static void dw_hdmi_reformat_s24(struct snd_dw_hdmi *dw,
+	size_t offset, size_t bytes)
+{
+	uint32_t *ptr = dw->buf_base + offset;
+	uint32_t *end = dw->buf_base + offset + bytes;
+
+	do {
+		unsigned i;
+		uint8_t *cs;
+
+		cs = dw->cs[dw->iec_offset++];
+		if (dw->iec_offset >= 192)
+			dw->iec_offset = 0;
+
+		i = dw->channels;
+		do {
+			uint32_t sample = *ptr;
+
+			sample &= ~0xff000000;
+			sample |= *cs++ << 24;
+			sample |= parity(sample & ~0xf8000000);
+
+			*ptr++ = sample;
+		} while (--i);
+	} while (ptr < end);
+}
+
+static void dw_hdmi_create_cs(struct snd_dw_hdmi *dw,
+	struct snd_pcm_runtime *runtime)
+{
+	uint8_t cs[3];
+	unsigned ch, i, j;
+
+	cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
+	cs[1] = IEC958_AES1_CON_GENERAL;
+	cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC;
+	cs[3] = IEC958_AES3_CON_CLOCK_1000PPM;
+
+	switch (runtime->rate) {
+	case 32000:
+		cs[3] |= IEC958_AES3_CON_FS_32000;
+		break;
+	case 44100:
+		cs[3] |= IEC958_AES3_CON_FS_44100;
+		break;
+	case 48000:
+		cs[3] |= IEC958_AES3_CON_FS_48000;
+		break;
+	case 88200:
+		cs[3] |= IEC958_AES3_CON_FS_88200;
+		break;
+	case 96000:
+		cs[3] |= IEC958_AES3_CON_FS_96000;
+		break;
+	case 176400:
+		cs[3] |= IEC958_AES3_CON_FS_176400;
+		break;
+	case 192000:
+		cs[3] |= IEC958_AES3_CON_FS_192000;
+		break;
+	}
+
+	memset(dw->cs, 0, sizeof(dw->cs));
+
+	for (ch = 0; ch < 8; ch++) {
+		cs[2] &= ~IEC958_AES2_CON_CHANNEL;
+		cs[2] |= (ch + 1) << 4;
+
+		for (i = 0; i < ARRAY_SIZE(cs); i++) {
+			unsigned c = cs[i];
+
+			for (j = 0; j < 8; j++, c >>= 1)
+				dw->cs[i * 8 + j][ch] = (c & 1) << 2;
+		}
+	}
+	dw->cs[0][0] |= BIT(4);
+}
+
+static void dw_hdmi_start_dma(struct snd_dw_hdmi *dw)
+{
+	unsigned long start, stop;
+
+	start = dw->buf_addr + dw->buf_offset;
+	stop = start + dw->buf_period - 1;
+
+	dw->reformat(dw, dw->buf_offset, dw->buf_period);
+
+	/* Setup the hardware start/stop addresses */
+	dw_hdmi_writel(start, dw->base + HDMI_AHB_DMA_STRADDR0);
+	dw_hdmi_writel(stop, dw->base + HDMI_AHB_DMA_STPADDR0);
+
+	/* Clear all irqs before enabling irqs and starting DMA */
+	dw_hdmi_writeb(HDMI_IH_AHBDMAAUD_STAT0_ALL,
+		       dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+	dw_hdmi_writeb(~HDMI_AHB_DMA_DONE, dw->base + HDMI_AHB_DMA_MASK);
+	dw_hdmi_writeb(HDMI_AHB_DMA_START_START, dw->base + HDMI_AHB_DMA_START);
+}
+
+static void dw_hdmi_stop_dma(struct snd_dw_hdmi *dw)
+{
+	dw->substream = NULL;
+
+	/* Disable interrupts before disabling DMA */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+	dw_hdmi_writeb(HDMI_AHB_DMA_STOP_STOP, dw->base + HDMI_AHB_DMA_STOP);
+}
+
+static irqreturn_t snd_dw_hdmi_irq(int irq, void *data)
+{
+	struct snd_dw_hdmi *dw = data;
+	struct snd_pcm_substream *substream;
+	unsigned stat;
+
+	stat = dw_hdmi_readb(dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+	if (!stat)
+		return IRQ_NONE;
+
+	dw_hdmi_writeb(stat, dw->base + HDMI_IH_AHBDMAAUD_STAT0);
+
+	substream = dw->substream;
+	if (stat & HDMI_IH_AHBDMAAUD_STAT0_DONE && substream) {
+		dw->buf_offset += dw->buf_period;
+		if (dw->buf_offset >= dw->buf_size)
+			dw->buf_offset = 0;
+
+		snd_pcm_period_elapsed(substream);
+		if (dw->substream) {
+			dw_hdmi_start_dma(dw);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+static struct snd_pcm_hardware dw_hdmi_hw = {
+	.info = SNDRV_PCM_INFO_INTERLEAVED |
+		SNDRV_PCM_INFO_BLOCK_TRANSFER |
+		SNDRV_PCM_INFO_MMAP |
+		SNDRV_PCM_INFO_MMAP_VALID,
+	.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE |
+		   SNDRV_PCM_FMTBIT_S24_LE,
+	.rates = SNDRV_PCM_RATE_32000 |
+		 SNDRV_PCM_RATE_44100 |
+		 SNDRV_PCM_RATE_48000 |
+		 SNDRV_PCM_RATE_88200 |
+		 SNDRV_PCM_RATE_96000 |
+		 SNDRV_PCM_RATE_176400 |
+		 SNDRV_PCM_RATE_192000,
+	.channels_min = 2,
+	.channels_max = 8,
+	.buffer_bytes_max = 64 * 1024,
+	.period_bytes_min = 256,
+	.period_bytes_max = 8192,	/* ERR004323: must limit to 8k */
+	.periods_min = 2,
+	.periods_max = 16,
+	.fifo_size = 0,
+};
+
+static int dw_hdmi_open(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	int ret;
+
+	/* Clear FIFO */
+	dw_hdmi_writeb(HDMI_AHB_DMA_CONF0_SW_FIFO_RST,
+		       dw->base + HDMI_AHB_DMA_CONF0);
+
+	/* Configure interrupt polarities */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_POL);
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_BUFFPOL);
+
+	/* Keep interrupts masked */
+	dw_hdmi_writeb(~0, dw->base + HDMI_AHB_DMA_MASK);
+
+	ret = request_irq(dw->irq, snd_dw_hdmi_irq, IRQF_SHARED,
+			  "dw-hdmi-audio", dw);
+	if (ret)
+		return ret;
+
+	/* Un-mute done interrupt */
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL &
+		       ~HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE,
+		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	runtime->hw = dw_hdmi_hw;
+	snd_pcm_limit_hw_rates(runtime);
+
+	return 0;
+}
+
+static int dw_hdmi_close(struct snd_pcm_substream *substream)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	/* Mute all interrupts */
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	free_irq(dw->irq, dw);
+
+	return 0;
+}
+
+static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+
+static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+					params_buffer_bytes(params));
+}
+
+static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+	uint8_t threshold, conf0, conf1;
+
+	/* Setup as per 3.0.5 FSL 4.1.0 BSP */
+	switch (dw->revision) {
+	case 0x0a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR4;
+		if (runtime->channels == 2)
+			threshold = 126;
+		else
+			threshold = 124;
+		break;
+	case 0x1a:
+		conf0 = HDMI_AHB_DMA_CONF0_BURST_MODE |
+			HDMI_AHB_DMA_CONF0_INCR8;
+		threshold = 128;
+		break;
+	default:
+		/* NOTREACHED */
+		return -EINVAL;
+	}
+
+	imx_hdmi_set_sample_rate(dw->hdmi, runtime->rate);
+
+	/* Minimum number of bytes in the fifo. */
+	runtime->hw.fifo_size = threshold * 32;
+
+	conf0 |= HDMI_AHB_DMA_CONF0_EN_HLOCK;
+	conf1 = (1 << runtime->channels) - 1;
+
+	dw_hdmi_writeb(threshold, dw->base + HDMI_AHB_DMA_THRSLD);
+	dw_hdmi_writeb(conf0, dw->base + HDMI_AHB_DMA_CONF0);
+	dw_hdmi_writeb(conf1, dw->base + HDMI_AHB_DMA_CONF1);
+
+	switch (runtime->format) {
+	case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE:
+		dw->reformat = dw_hdmi_reformat_iec958;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		dw_hdmi_create_cs(dw, runtime);
+		dw->reformat = dw_hdmi_reformat_s24;
+		break;
+	}
+	dw->iec_offset = 0;
+	dw->channels = runtime->channels;
+	dw->buf_base = runtime->dma_area;
+	dw->buf_addr = runtime->dma_addr;
+	dw->buf_period = snd_pcm_lib_period_bytes(substream);
+	dw->buf_size = snd_pcm_lib_buffer_bytes(substream);
+
+	return 0;
+}
+
+static int dw_hdmi_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct snd_dw_hdmi *dw = substream->private_data;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		dw->buf_offset = 0;
+		dw->substream = substream;
+		dw_hdmi_start_dma(dw);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+		dw_hdmi_stop_dma(dw);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t dw_hdmi_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_dw_hdmi *dw = substream->private_data;
+
+	return bytes_to_frames(runtime, dw->buf_offset);
+}
+
+static struct snd_pcm_ops snd_dw_hdmi_ops = {
+	.open = dw_hdmi_open,
+	.close = dw_hdmi_close,
+	.ioctl = snd_pcm_lib_ioctl,
+	.hw_params = dw_hdmi_hw_params,
+	.hw_free = dw_hdmi_hw_free,
+	.prepare = dw_hdmi_prepare,
+	.trigger = dw_hdmi_trigger,
+	.pointer = dw_hdmi_pointer,
+};
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *dev,
+	void __iomem *base, int irq, struct imx_hdmi *hdmi)
+{
+	struct snd_dw_hdmi *dw;
+	struct snd_card *card;
+	struct snd_pcm *pcm;
+	unsigned revision;
+	int ret;
+
+	dw_hdmi_writeb(HDMI_IH_MUTE_AHBDMAAUD_STAT0_ALL,
+		       base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+	revision = dw_hdmi_readb(base + HDMI_REVISION_ID);
+	if (revision != 0x0a && revision != 0x1a) {
+		dev_err(dev, "dw-hdmi-audio: unknown revision 0x%02x\n",
+			revision);
+		return -ENXIO;
+	}
+
+	ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			      THIS_MODULE, sizeof(struct snd_dw_hdmi), &card);
+	if (ret < 0)
+		return ret;
+
+	snd_card_set_dev(card, dev);
+
+	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
+	strlcpy(card->shortname, "DW-HDMI", sizeof(card->shortname));
+	snprintf(card->longname, sizeof(card->longname),
+		 "%s rev 0x%02x, irq %d", card->shortname, revision, irq);
+
+	dw = card->private_data;
+	dw->card = card;
+	dw->base = base;
+	dw->irq = irq;
+	dw->hdmi = hdmi;
+	dw->revision = revision;
+
+	ret = snd_pcm_new(card, "DW HDMI", 0, 1, 0, &pcm);
+	if (ret < 0)
+		goto err;
+
+	dw->pcm = pcm;
+	pcm->private_data = dw;
+	strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_dw_hdmi_ops);
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+			NULL, 0, 64 * 1024);
+
+	ret = snd_card_register(card);
+	if (ret < 0)
+		goto err;
+
+	*dwp = dw;
+
+	return 0;
+
+err:
+	snd_card_free(card);
+	return ret;
+}
+
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw)
+{
+	snd_card_free(dw->card);
+}
diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.h b/drivers/staging/imx-drm/dw-hdmi-audio.h
new file mode 100644
index 000000000000..82a709c9f612
--- /dev/null
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.h
@@ -0,0 +1,13 @@
+#ifndef DW_HDMI_AUDIO_H
+#define DW_HDMI_AUDIO_H
+
+#include <linux/irqreturn.h>
+
+struct snd_dw_hdmi;
+struct imx_hdmi;
+
+int snd_dw_hdmi_probe(struct snd_dw_hdmi **dwp, struct device *,
+	void __iomem *, int, struct imx_hdmi *);
+void snd_dw_hdmi_remove(struct snd_dw_hdmi *dw);
+
+#endif
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 097403a602d8..eb196c0862c8 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -27,6 +27,7 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_encoder_slave.h>
 
+#include "dw-hdmi-audio.h"
 #include "ipu-v3/imx-ipu-v3.h"
 #include "imx-hdmi.h"
 #include "imx-drm.h"
@@ -119,6 +120,7 @@ struct imx_hdmi {
 	struct drm_connector connector;
 	struct drm_encoder encoder;
 
+	struct snd_dw_hdmi *audio;
 	enum imx_hdmi_devtype dev_type;
 	struct device *dev;
 	struct clk *isfr_clk;
@@ -366,6 +368,13 @@ static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
 	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
 }
 
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
+{
+	hdmi->sample_rate = rate;
+	hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
+
 /*
  * this submodule is responsible for the video data synchronization.
  * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1705,10 +1714,20 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	/* Unmute interrupts */
 	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
 
+	ret = snd_dw_hdmi_probe(&hdmi->audio, dev, hdmi->regs, irq, hdmi);
+	if (ret)
+		goto err_audio;
+
 	dev_set_drvdata(dev, hdmi);
 
 	return 0;
 
+err_audio:
+	/* Disable all interrupts */
+	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+	hdmi->connector.funcs->destroy(&hdmi->connector);
+	hdmi->encoder.funcs->destroy(&hdmi->encoder);
 err_iahb:
 	clk_disable_unprepare(hdmi->iahb_clk);
 err_isfr:
@@ -1722,6 +1741,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
 {
 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
 
+	snd_dw_hdmi_remove(hdmi->audio);
+
 	/* Disable all interrupts */
 	hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
 
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 39b677689db6..8029febdbabe 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1029,4 +1029,8 @@ enum {
 	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
 	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
 };
+
+struct imx_hdmi;
+void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+
 #endif /* __IMX_HDMI_H__ */
-- 
1.7.4.4

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

* [PATCH RFC 45/46] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

Parse the ELD (EDID like data) stored from the HDMI driver to restrict
the sample rates and channels which are available to ALSA.  This causes
the ALSA device to reflect the capabilities of the overall audio path,
not just what is supported at the HDMI source interface level.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c |   50 +++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.c      |    8 +++++
 drivers/staging/imx-drm/imx-hdmi.h      |    1 +
 3 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 946055d2a975..8f70e6565d22 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -274,6 +274,55 @@ static struct snd_pcm_hardware dw_hdmi_hw = {
 	.fifo_size = 0,
 };
 
+static unsigned rates_mask[] = {
+	SNDRV_PCM_RATE_32000,
+	SNDRV_PCM_RATE_44100,
+	SNDRV_PCM_RATE_48000,
+	SNDRV_PCM_RATE_88200,
+	SNDRV_PCM_RATE_96000,
+	SNDRV_PCM_RATE_176400,
+	SNDRV_PCM_RATE_192000,
+};
+
+static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw, struct snd_pcm_runtime *runtime)
+{
+	uint8_t *sad, *eld = imx_hdmi_get_eld(dw->hdmi);
+	unsigned eld_ver,  mnl, sad_count, rates, rate_mask, i;
+	unsigned max_channels;
+
+	eld_ver = eld[0] >> 3;
+	if (eld_ver != 2 && eld_ver != 31)
+		return;
+
+	mnl = eld[4] & 0x1f;
+	if (mnl > 16)
+		return;
+
+	sad_count = eld[5] >> 4;
+	sad = eld + 20 + mnl;
+
+	/* Start from the basic audio settings */
+	max_channels = 2;
+	rates = 7;
+	while (sad_count > 0) {
+		switch (sad[0] & 0x78) {
+		case 0x08: /* PCM */
+			max_channels = max(max_channels, (sad[0] & 7) + 1u);
+			rates |= sad[1];
+			break;
+		}
+		sad += 3;
+		sad_count -= 1;
+	}
+
+	for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
+		if (rates & 1 << i)
+			rate_mask |= rates_mask[i];
+
+	runtime->hw.rates &= rate_mask;
+	runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
+}
+
 static int dw_hdmi_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -302,6 +351,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
 		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
 
 	runtime->hw = dw_hdmi_hw;
+	dw_hdmi_parse_eld(dw, runtime);
 	snd_pcm_limit_hw_rates(runtime);
 
 	return 0;
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index eb196c0862c8..949dd7c25166 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -375,6 +375,12 @@ void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
 }
 EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
 
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi)
+{
+	return hdmi->connector.eld;
+}
+EXPORT_SYMBOL(imx_hdmi_get_eld);
+
 /*
  * this submodule is responsible for the video data synchronization.
  * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1406,6 +1412,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 
 		drm_mode_connector_update_edid_property(connector, edid);
 		ret = drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
 		kfree(edid);
 	} else {
 		dev_dbg(hdmi->dev, "failed to get edid\n");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 8029febdbabe..5baaa9cba943 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1032,5 +1032,6 @@ enum {
 
 struct imx_hdmi;
 void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi);
 
 #endif /* __IMX_HDMI_H__ */
-- 
1.7.4.4

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

* [PATCH RFC 45/46] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

Parse the ELD (EDID like data) stored from the HDMI driver to restrict
the sample rates and channels which are available to ALSA.  This causes
the ALSA device to reflect the capabilities of the overall audio path,
not just what is supported at the HDMI source interface level.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/dw-hdmi-audio.c |   50 +++++++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.c      |    8 +++++
 drivers/staging/imx-drm/imx-hdmi.h      |    1 +
 3 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
index 946055d2a975..8f70e6565d22 100644
--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
+++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
@@ -274,6 +274,55 @@ static struct snd_pcm_hardware dw_hdmi_hw = {
 	.fifo_size = 0,
 };
 
+static unsigned rates_mask[] = {
+	SNDRV_PCM_RATE_32000,
+	SNDRV_PCM_RATE_44100,
+	SNDRV_PCM_RATE_48000,
+	SNDRV_PCM_RATE_88200,
+	SNDRV_PCM_RATE_96000,
+	SNDRV_PCM_RATE_176400,
+	SNDRV_PCM_RATE_192000,
+};
+
+static void dw_hdmi_parse_eld(struct snd_dw_hdmi *dw, struct snd_pcm_runtime *runtime)
+{
+	uint8_t *sad, *eld = imx_hdmi_get_eld(dw->hdmi);
+	unsigned eld_ver,  mnl, sad_count, rates, rate_mask, i;
+	unsigned max_channels;
+
+	eld_ver = eld[0] >> 3;
+	if (eld_ver != 2 && eld_ver != 31)
+		return;
+
+	mnl = eld[4] & 0x1f;
+	if (mnl > 16)
+		return;
+
+	sad_count = eld[5] >> 4;
+	sad = eld + 20 + mnl;
+
+	/* Start from the basic audio settings */
+	max_channels = 2;
+	rates = 7;
+	while (sad_count > 0) {
+		switch (sad[0] & 0x78) {
+		case 0x08: /* PCM */
+			max_channels = max(max_channels, (sad[0] & 7) + 1u);
+			rates |= sad[1];
+			break;
+		}
+		sad += 3;
+		sad_count -= 1;
+	}
+
+	for (rate_mask = i = 0; i < ARRAY_SIZE(rates_mask); i++)
+		if (rates & 1 << i)
+			rate_mask |= rates_mask[i];
+
+	runtime->hw.rates &= rate_mask;
+	runtime->hw.channels_max = min(runtime->hw.channels_max, max_channels);
+}
+
 static int dw_hdmi_open(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
@@ -302,6 +351,7 @@ static int dw_hdmi_open(struct snd_pcm_substream *substream)
 		       dw->base + HDMI_IH_MUTE_AHBDMAAUD_STAT0);
 
 	runtime->hw = dw_hdmi_hw;
+	dw_hdmi_parse_eld(dw, runtime);
 	snd_pcm_limit_hw_rates(runtime);
 
 	return 0;
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index eb196c0862c8..949dd7c25166 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -375,6 +375,12 @@ void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate)
 }
 EXPORT_SYMBOL(imx_hdmi_set_sample_rate);
 
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi)
+{
+	return hdmi->connector.eld;
+}
+EXPORT_SYMBOL(imx_hdmi_get_eld);
+
 /*
  * this submodule is responsible for the video data synchronization.
  * for example, for RGB 4:4:4 input, the data map is defined as
@@ -1406,6 +1412,8 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
 
 		drm_mode_connector_update_edid_property(connector, edid);
 		ret = drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
 		kfree(edid);
 	} else {
 		dev_dbg(hdmi->dev, "failed to get edid\n");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
index 8029febdbabe..5baaa9cba943 100644
--- a/drivers/staging/imx-drm/imx-hdmi.h
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -1032,5 +1032,6 @@ enum {
 
 struct imx_hdmi;
 void imx_hdmi_set_sample_rate(struct imx_hdmi *hdmi, unsigned int rate);
+uint8_t *imx_hdmi_get_eld(struct imx_hdmi *hdmi);
 
 #endif /* __IMX_HDMI_H__ */
-- 
1.7.4.4

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

* [PATCH RFC 46/46] imx-drm: pass an IPU ID to crtc and core (needs work)
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-02 21:29   ` Russell King
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: linux-arm-kernel

On IMX6D/Q devices, the display bridge muxes can select either display
interface on either of the IPUs.  Therefore, we need to positively know
which IPU each CRTC is.

We partially solve this by passing an IPU ID from the IPUv3 driver into
the DRM CRTC driver, which also passes it into the core code.  This
gives a method by which we can try to solve this.

However, we're still stuck with trying to guess the IPU ID in the IPU
driver as we don't have a positive way to identify this.  This needs to
be resolved.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c      |   14 +++++++-------
 drivers/staging/imx-drm/imx-drm.h           |    2 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |    1 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   15 +++++++++++----
 drivers/staging/imx-drm/ipuv3-crtc.c        |    7 +++----
 5 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 6b86bfeb091f..2490dc32df4a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -42,8 +42,8 @@ struct imx_drm_crtc {
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	void					*cookie;
-	int					id;
-	int					mux_id;
+	int					di_id;
+	int					ipu_id;
 };
 
 static int legacyfb_depth = 16;
@@ -345,7 +345,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
-		void *cookie, int id)
+		void *cookie, int ipu_id, int di_id)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 	struct imx_drm_crtc *imx_drm_crtc;
@@ -368,8 +368,8 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
 	imx_drm_crtc->pipe = imxdrm->pipes++;
 	imx_drm_crtc->cookie = cookie;
-	imx_drm_crtc->id = id;
-	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
+	imx_drm_crtc->di_id = di_id;
+	imx_drm_crtc->ipu_id = ipu_id;
 	imx_drm_crtc->crtc = crtc;
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
@@ -426,7 +426,7 @@ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-		if (imx_drm_crtc && imx_drm_crtc->id == id &&
+		if (imx_drm_crtc && imx_drm_crtc->di_id == id &&
 		    imx_drm_crtc->cookie == cookie)
 			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
 	}
@@ -482,7 +482,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
 
-	return imx_crtc ? imx_crtc->mux_id : -EINVAL;
+	return imx_crtc ? imx_crtc->ipu_id * 2 + imx_crtc->di_id : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 0a26222ec539..7d8d9634a4db 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -29,7 +29,7 @@ struct imx_drm_crtc_helper_funcs {
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
-		void *cookie, int id);
+		void *cookie, int ipu_id, int di_id);
 int imx_drm_remove_crtc(struct imx_drm_crtc *);
 int imx_drm_init_drm(struct platform_device *pdev,
 		int preferred_bpp);
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 4826b5c0249d..7b879ace4feb 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -319,6 +319,7 @@ struct ipu_client_platformdata {
 	int dp;
 	int dmfc;
 	int dma[2];
+	int ipu;
 };
 
 #endif /* __DRM_IPU_H__ */
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 97ca6924dbb3..96b1135b1181 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1003,19 +1003,26 @@ static int ipu_add_client_devices(struct ipu_soc *ipu)
 {
 	struct device *dev = ipu->dev;
 	unsigned i;
-	int id, ret;
+	int ipu_id, id, ret;
 
 	mutex_lock(&ipu_client_id_mutex);
-	id = ipu_client_id;
-	ipu_client_id += ARRAY_SIZE(client_reg);
+	id = ipu_client_id++;
 	mutex_unlock(&ipu_client_id_mutex);
 
+	/* FIXME: this needs a better solution */
+	ipu_id = id;
+
+	id *= ARRAY_SIZE(client_reg);
+
 	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
 		const struct ipu_platform_reg *reg = &client_reg[i];
+		struct ipu_client_platformdata pdata = reg->pdata;
 		struct platform_device *pdev;
 
+		pdata.ipu = ipu_id;
+
 		pdev = platform_device_register_data(dev, reg->name,
-			id++, &reg->pdata, sizeof(reg->pdata));
+			id++, &pdata, sizeof(pdata));
 
 		if (IS_ERR(pdev))
 			goto err_register;
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ed2423efc1d0..b2de40b1fb2c 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -349,10 +349,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		return ret;
 	}
 
-	ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
-			&ipu_crtc->imx_crtc,
-			&ipu_crtc_helper_funcs,
-			ipu_crtc->dev->parent->of_node, pdata->di);
+	ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+			&ipu_crtc_helper_funcs, ipu_crtc->dev->parent->of_node,
+			pdata->ipu, pdata->di);
 	if (ret) {
 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
 		goto err_put_resources;
-- 
1.7.4.4

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

* [PATCH RFC 46/46] imx-drm: pass an IPU ID to crtc and core (needs work)
@ 2014-01-02 21:29   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:29 UTC (permalink / raw)
  To: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo
  Cc: devel, dri-devel, linux-arm-kernel

On IMX6D/Q devices, the display bridge muxes can select either display
interface on either of the IPUs.  Therefore, we need to positively know
which IPU each CRTC is.

We partially solve this by passing an IPU ID from the IPUv3 driver into
the DRM CRTC driver, which also passes it into the core code.  This
gives a method by which we can try to solve this.

However, we're still stuck with trying to guess the IPU ID in the IPU
driver as we don't have a positive way to identify this.  This needs to
be resolved.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/imx-drm-core.c      |   14 +++++++-------
 drivers/staging/imx-drm/imx-drm.h           |    2 +-
 drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h |    1 +
 drivers/staging/imx-drm/ipu-v3/ipu-common.c |   15 +++++++++++----
 drivers/staging/imx-drm/ipuv3-crtc.c        |    7 +++----
 5 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 6b86bfeb091f..2490dc32df4a 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -42,8 +42,8 @@ struct imx_drm_crtc {
 	int					pipe;
 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
 	void					*cookie;
-	int					id;
-	int					mux_id;
+	int					di_id;
+	int					ipu_id;
 };
 
 static int legacyfb_depth = 16;
@@ -345,7 +345,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
-		void *cookie, int id)
+		void *cookie, int ipu_id, int di_id)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
 	struct imx_drm_crtc *imx_drm_crtc;
@@ -368,8 +368,8 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 	imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
 	imx_drm_crtc->pipe = imxdrm->pipes++;
 	imx_drm_crtc->cookie = cookie;
-	imx_drm_crtc->id = id;
-	imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
+	imx_drm_crtc->di_id = di_id;
+	imx_drm_crtc->ipu_id = ipu_id;
 	imx_drm_crtc->crtc = crtc;
 
 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
@@ -426,7 +426,7 @@ static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
-		if (imx_drm_crtc && imx_drm_crtc->id == id &&
+		if (imx_drm_crtc && imx_drm_crtc->di_id == id &&
 		    imx_drm_crtc->cookie == cookie)
 			return drm_helper_crtc_possible_mask(imx_drm_crtc->crtc);
 	}
@@ -482,7 +482,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
 	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
 
-	return imx_crtc ? imx_crtc->mux_id : -EINVAL;
+	return imx_crtc ? imx_crtc->ipu_id * 2 + imx_crtc->di_id : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
index 0a26222ec539..7d8d9634a4db 100644
--- a/drivers/staging/imx-drm/imx-drm.h
+++ b/drivers/staging/imx-drm/imx-drm.h
@@ -29,7 +29,7 @@ struct imx_drm_crtc_helper_funcs {
 int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
 		struct imx_drm_crtc **new_crtc,
 		const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
-		void *cookie, int id);
+		void *cookie, int ipu_id, int di_id);
 int imx_drm_remove_crtc(struct imx_drm_crtc *);
 int imx_drm_init_drm(struct platform_device *pdev,
 		int preferred_bpp);
diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
index 4826b5c0249d..7b879ace4feb 100644
--- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
+++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h
@@ -319,6 +319,7 @@ struct ipu_client_platformdata {
 	int dp;
 	int dmfc;
 	int dma[2];
+	int ipu;
 };
 
 #endif /* __DRM_IPU_H__ */
diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
index 97ca6924dbb3..96b1135b1181 100644
--- a/drivers/staging/imx-drm/ipu-v3/ipu-common.c
+++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c
@@ -1003,19 +1003,26 @@ static int ipu_add_client_devices(struct ipu_soc *ipu)
 {
 	struct device *dev = ipu->dev;
 	unsigned i;
-	int id, ret;
+	int ipu_id, id, ret;
 
 	mutex_lock(&ipu_client_id_mutex);
-	id = ipu_client_id;
-	ipu_client_id += ARRAY_SIZE(client_reg);
+	id = ipu_client_id++;
 	mutex_unlock(&ipu_client_id_mutex);
 
+	/* FIXME: this needs a better solution */
+	ipu_id = id;
+
+	id *= ARRAY_SIZE(client_reg);
+
 	for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
 		const struct ipu_platform_reg *reg = &client_reg[i];
+		struct ipu_client_platformdata pdata = reg->pdata;
 		struct platform_device *pdev;
 
+		pdata.ipu = ipu_id;
+
 		pdev = platform_device_register_data(dev, reg->name,
-			id++, &reg->pdata, sizeof(reg->pdata));
+			id++, &pdata, sizeof(pdata));
 
 		if (IS_ERR(pdev))
 			goto err_register;
diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
index ed2423efc1d0..b2de40b1fb2c 100644
--- a/drivers/staging/imx-drm/ipuv3-crtc.c
+++ b/drivers/staging/imx-drm/ipuv3-crtc.c
@@ -349,10 +349,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
 		return ret;
 	}
 
-	ret = imx_drm_add_crtc(drm, &ipu_crtc->base,
-			&ipu_crtc->imx_crtc,
-			&ipu_crtc_helper_funcs,
-			ipu_crtc->dev->parent->of_node, pdata->di);
+	ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
+			&ipu_crtc_helper_funcs, ipu_crtc->dev->parent->of_node,
+			pdata->ipu, pdata->di);
 	if (ret) {
 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
 		goto err_put_resources;
-- 
1.7.4.4

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

* [PATCH RFC 07/46] imx-drm: Add mx6 hdmi transmitter support
@ 2014-01-02 21:34   ` Russell King
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King @ 2014-01-02 21:34 UTC (permalink / raw)
  To: linux-arm-kernel

From: Fabio Estevam <fabio.estevam@freescale.com>
To: David Airlie <airlied@linux.ie>,Greg Kroah-Hartman <gregkh@linuxfoundation.org>,Sascha Hauer <kernel@pengutronix.de>,Shawn Guo <shawn.guo@linaro.org>

This is based on the initial work done by Sascha Hauer and Tony Prisk.

Tested on a mx6qsabresd.

Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/imx-drm/Kconfig             |    6 +
 drivers/staging/imx-drm/Makefile            |    1 +
 drivers/staging/imx-drm/imx-hdmi.c          | 1928 +++++++++++++++++++++++++++
 drivers/staging/imx-drm/imx-hdmi.h          | 1032 ++++++++++++++
 include/linux/mfd/syscon/imx6q-iomuxc-gpr.h |    1 +
 5 files changed, 2968 insertions(+), 0 deletions(-)
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.c
 create mode 100644 drivers/staging/imx-drm/imx-hdmi.h

diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
index 5032ff7c2259..0faf52c4c5f1 100644
--- a/drivers/staging/imx-drm/Kconfig
+++ b/drivers/staging/imx-drm/Kconfig
@@ -53,3 +53,9 @@ config DRM_IMX_IPUV3
 	depends on DRM_IMX_IPUV3_CORE
 	help
 	  Choose this if you have a i.MX5 or i.MX6 processor.
+
+config DRM_IMX_HDMI
+	tristate "Freescale i.MX DRM HDMI "
+	depends on DRM_IMX
+	help
+	  Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
index 8742432d7b01..4677585b5ad5 100644
--- a/drivers/staging/imx-drm/Makefile
+++ b/drivers/staging/imx-drm/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/
 
 imx-ipuv3-crtc-objs  := ipuv3-crtc.o ipuv3-plane.o
 obj-$(CONFIG_DRM_IMX_IPUV3)	+= imx-ipuv3-crtc.o
+obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
new file mode 100644
index 000000000000..2022635fffdf
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -0,0 +1,1928 @@
+/*
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
+ * for SLISHDMI13T and SLIPHDMIT IP cores
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ */
+
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+
+#include <linux/of_device.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "ipu-v3/imx-ipu-v3.h"
+#include "imx-hdmi.h"
+#include "imx-drm.h"
+
+#define HDMI_EDID_LEN		512
+
+#define RGB			0
+#define YCBCR444		1
+#define YCBCR422_16BITS		2
+#define YCBCR422_8BITS		3
+#define	XVYCC444		4
+
+enum hdmi_datamap {
+	RGB444_8B = 0x01,
+	RGB444_10B = 0x03,
+	RGB444_12B = 0x05,
+	RGB444_16B = 0x07,
+	YCbCr444_8B = 0x09,
+	YCbCr444_10B = 0x0B,
+	YCbCr444_12B = 0x0D,
+	YCbCr444_16B = 0x0F,
+	YCbCr422_8B = 0x16,
+	YCbCr422_10B = 0x14,
+	YCbCr422_12B = 0x12,
+};
+
+enum hdmi_colorimetry {
+	ITU601,
+	ITU709,
+};
+
+enum imx_hdmi_devtype {
+	IMX6Q_HDMI,
+	IMX6DL_HDMI,
+};
+
+static const u16 csc_coeff_default[3][4] = {
+	{ 0x2000, 0x0000, 0x0000, 0x0000 },
+	{ 0x0000, 0x2000, 0x0000, 0x0000 },
+	{ 0x0000, 0x0000, 0x2000, 0x0000 }
+};
+
+static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
+	{ 0x2000, 0x6926, 0x74fd, 0x010e },
+	{ 0x2000, 0x2cdd, 0x0000, 0x7e9a },
+	{ 0x2000, 0x0000, 0x38b4, 0x7e3b }
+};
+
+static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
+	{ 0x2000, 0x7106, 0x7a02, 0x00a7 },
+	{ 0x2000, 0x3264, 0x0000, 0x7e6d },
+	{ 0x2000, 0x0000, 0x3b61, 0x7e25 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
+	{ 0x2591, 0x1322, 0x074b, 0x0000 },
+	{ 0x6535, 0x2000, 0x7acc, 0x0200 },
+	{ 0x6acd, 0x7534, 0x2000, 0x0200 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
+	{ 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
+	{ 0x62f0, 0x2000, 0x7d11, 0x0200 },
+	{ 0x6756, 0x78ab, 0x2000, 0x0200 }
+};
+
+struct hdmi_vmode {
+	bool mdvi;
+	bool mhsyncpolarity;
+	bool mvsyncpolarity;
+	bool minterlaced;
+	bool mdataenablepolarity;
+
+	unsigned int mpixelclock;
+	unsigned int mpixelrepetitioninput;
+	unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+	unsigned int enc_in_format;
+	unsigned int enc_out_format;
+	unsigned int enc_color_depth;
+	unsigned int colorimetry;
+	unsigned int pix_repet_factor;
+	unsigned int hdcp_enable;
+	struct hdmi_vmode video_mode;
+};
+
+struct imx_hdmi {
+	struct drm_connector connector;
+	struct imx_drm_connector *imx_drm_connector;
+	struct drm_encoder encoder;
+	struct imx_drm_encoder *imx_drm_encoder;
+
+	enum imx_hdmi_devtype dev_type;
+	struct device *dev;
+	struct clk *isfr_clk;
+	struct clk *iahb_clk;
+
+	struct hdmi_data_info hdmi_data;
+	int vic;
+
+	u8 edid[HDMI_EDID_LEN];
+	bool fb_reg;
+	bool cable_plugin;
+
+	bool phy_enabled;
+	struct drm_display_mode previous_mode;
+
+	struct regmap *regmap;
+	struct i2c_adapter *ddc;
+	void __iomem *regs;
+
+	unsigned long pixel_clk_rate;
+	unsigned int sample_rate;
+	int ratio;
+};
+
+static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
+{
+	regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
+			   IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+			   ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+}
+
+static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
+{
+	writeb(val, hdmi->regs + offset);
+}
+
+static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
+{
+	return readb(hdmi->regs + offset);
+}
+
+static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
+		      u8 shift, u8 mask)
+{
+	u8 value = hdmi_readb(hdmi, reg) & ~mask;
+	value |= (data << shift) & mask;
+	hdmi_writeb(hdmi, value, reg);
+}
+
+static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
+					 unsigned int value)
+{
+	u8 val;
+
+	hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
+	hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+	hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+
+	/* nshift factor = 0 */
+	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
+	val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK;
+	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+}
+
+static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
+{
+	u8 val;
+
+	/* Must be set/cleared first */
+	val = hdmi_readb(hdmi, HDMI_AUD_CTS3);
+	val &= ~HDMI_AUD_CTS3_CTS_MANUAL;
+	hdmi_writeb(hdmi, val, HDMI_AUD_CTS3);
+
+	hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+	hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+	hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+		    HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+				   unsigned int ratio)
+{
+	unsigned int n = (128 * freq) / 1000;
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 4576;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 4096;
+		else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+			n = 11648;
+		else
+			n = 4096;
+		break;
+
+	case 44100:
+		if (pixel_clk == 25170000)
+			n = 7007;
+		else if (pixel_clk == 74170000)
+			n = 17836;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 17836 : 8918;
+		else
+			n = 6272;
+		break;
+
+	case 48000:
+		if (pixel_clk == 25170000)
+			n = (ratio == 150) ? 9152 : 6864;
+		else if (pixel_clk == 27020000)
+			n = (ratio == 150) ? 8192 : 6144;
+		else if (pixel_clk == 74170000)
+			n = 11648;
+		else if (pixel_clk == 148350000)
+			n = (ratio == 150) ? 11648 : 5824;
+		else
+			n = 6144;
+		break;
+
+	case 88200:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+		break;
+
+	case 96000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+		break;
+
+	case 176400:
+		n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+		break;
+
+	case 192000:
+		n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+		break;
+
+	default:
+		break;
+	}
+
+	return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+				     unsigned int ratio)
+{
+	unsigned int cts = 0;
+
+	pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
+		 pixel_clk, ratio);
+
+	switch (freq) {
+	case 32000:
+		if (pixel_clk == 297000000) {
+			cts = 222750;
+			break;
+		}
+	case 48000:
+	case 96000:
+	case 192000:
+		switch (pixel_clk) {
+		case 25200000:
+		case 27000000:
+		case 54000000:
+		case 74250000:
+		case 148500000:
+			cts = pixel_clk / 1000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		/*
+		 * All other TMDS clocks are not supported by
+		 * DWC_hdmi_tx. The TMDS clocks divided or
+		 * multiplied by 1,001 coefficients are not
+		 * supported.
+		 */
+		default:
+			break;
+		}
+		break;
+	case 44100:
+	case 88200:
+	case 176400:
+		switch (pixel_clk) {
+		case 25200000:
+			cts = 28000;
+			break;
+		case 27000000:
+			cts = 30000;
+			break;
+		case 54000000:
+			cts = 60000;
+			break;
+		case 74250000:
+			cts = 82500;
+			break;
+		case 148500000:
+			cts = 165000;
+			break;
+		case 297000000:
+			cts = 247500;
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	if (ratio == 100)
+		return cts;
+	else
+		return (cts * ratio) / 100;
+}
+
+static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi)
+{
+	unsigned long rate;
+
+	rate = 65000000; /* FIXME */
+
+	if (rate)
+		hdmi->pixel_clk_rate = rate;
+}
+
+static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi)
+{
+	unsigned int clk_n, clk_cts;
+
+	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+			       hdmi->ratio);
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+				   hdmi->ratio);
+
+	if (!clk_cts) {
+		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+			 __func__, hdmi->pixel_clk_rate);
+		return;
+	}
+
+	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+		__func__, hdmi->sample_rate, hdmi->ratio,
+		hdmi->pixel_clk_rate, clk_n, clk_cts);
+
+	hdmi_set_clock_regenerator_n(hdmi, clk_n);
+	hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
+{
+	unsigned int clk_n, clk_cts;
+
+	clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate,
+			       hdmi->ratio);
+	clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate,
+				   hdmi->ratio);
+
+	if (!clk_cts) {
+		dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+			 __func__, hdmi->pixel_clk_rate);
+		return;
+	}
+
+	dev_dbg(hdmi->dev, "%s: samplerate=%d  ratio=%d  pixelclk=%lu  N=%d cts=%d\n",
+		__func__, hdmi->sample_rate, hdmi->ratio,
+		hdmi->pixel_clk_rate, clk_n, clk_cts);
+
+	hdmi_set_clock_regenerator_n(hdmi, clk_n);
+	hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
+{
+	/* Get pixel clock from ipu */
+	hdmi_get_pixel_clk(hdmi);
+	hdmi_set_clk_regenerator(hdmi);
+}
+
+/*
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ *			pin{47~40} <==> R[7:0]
+ *			pin{31~24} <==> G[7:0]
+ *			pin{15~8}  <==> B[7:0]
+ */
+static void hdmi_video_sample(struct imx_hdmi *hdmi)
+{
+	int color_format = 0;
+	u8 val;
+
+	if (hdmi->hdmi_data.enc_in_format == RGB) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x01;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x03;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x05;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x07;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x09;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x0B;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x0D;
+		else if (hdmi->hdmi_data.enc_color_depth == 16)
+			color_format = 0x0F;
+		else
+			return;
+	} else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+		if (hdmi->hdmi_data.enc_color_depth == 8)
+			color_format = 0x16;
+		else if (hdmi->hdmi_data.enc_color_depth == 10)
+			color_format = 0x14;
+		else if (hdmi->hdmi_data.enc_color_depth == 12)
+			color_format = 0x12;
+		else
+			return;
+	}
+
+	val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+		((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+		HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+	hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+
+	/* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+	val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+		HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+	hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
+	hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+}
+
+static int is_color_space_conversion(struct imx_hdmi *hdmi)
+{
+	return (hdmi->hdmi_data.enc_in_format !=
+		hdmi->hdmi_data.enc_out_format);
+}
+
+static int is_color_space_decimation(struct imx_hdmi *hdmi)
+{
+	return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) &&
+		(hdmi->hdmi_data.enc_in_format == RGB ||
+		hdmi->hdmi_data.enc_in_format == YCBCR444));
+}
+
+static int is_color_space_interpolation(struct imx_hdmi *hdmi)
+{
+	return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) &&
+		(hdmi->hdmi_data.enc_out_format == RGB ||
+		hdmi->hdmi_data.enc_out_format == YCBCR444));
+}
+
+static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
+{
+	const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+	u32 csc_scale = 1;
+	u8 val;
+
+	if (is_color_space_conversion(hdmi)) {
+		if (hdmi->hdmi_data.enc_out_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry == ITU601)
+				csc_coeff = &csc_coeff_rgb_out_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_out_eitu709;
+		} else if (hdmi->hdmi_data.enc_in_format == RGB) {
+			if (hdmi->hdmi_data.colorimetry == ITU601)
+				csc_coeff = &csc_coeff_rgb_in_eitu601;
+			else
+				csc_coeff = &csc_coeff_rgb_in_eitu709;
+			csc_scale = 0;
+		}
+	}
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB);
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB);
+
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB);
+	hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB);
+
+	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
+	val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK;
+	val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK;
+	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct imx_hdmi *hdmi)
+{
+	int color_depth = 0;
+	int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+	int decimation = 0;
+	u8 val;
+
+	/* YCC422 interpolation to 444 mode */
+	if (is_color_space_interpolation(hdmi))
+		interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+	else if (is_color_space_decimation(hdmi))
+		decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+	if (hdmi->hdmi_data.enc_color_depth == 8)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 10)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 12)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+	else if (hdmi->hdmi_data.enc_color_depth == 16)
+		color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+	else
+		return;
+
+	/* Configure the CSC registers */
+	hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+	val = hdmi_readb(hdmi, HDMI_CSC_SCALE);
+	val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK;
+	val |= color_depth;
+	hdmi_writeb(hdmi, val, HDMI_CSC_SCALE);
+
+	imx_hdmi_update_csc_coeffs(hdmi);
+}
+
+/*
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct imx_hdmi *hdmi)
+{
+	unsigned int color_depth = 0;
+	unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+	unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+	struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+	u8 val;
+
+	if (hdmi_data->enc_out_format == RGB
+		|| hdmi_data->enc_out_format == YCBCR444) {
+		if (!hdmi_data->enc_color_depth)
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		else if (hdmi_data->enc_color_depth == 8) {
+			color_depth = 4;
+			output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+		} else if (hdmi_data->enc_color_depth == 10)
+			color_depth = 5;
+		else if (hdmi_data->enc_color_depth == 12)
+			color_depth = 6;
+		else if (hdmi_data->enc_color_depth == 16)
+			color_depth = 7;
+		else
+			return;
+	} else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+		if (!hdmi_data->enc_color_depth ||
+		    hdmi_data->enc_color_depth == 8)
+			remap_size = HDMI_VP_REMAP_YCC422_16bit;
+		else if (hdmi_data->enc_color_depth == 10)
+			remap_size = HDMI_VP_REMAP_YCC422_20bit;
+		else if (hdmi_data->enc_color_depth == 12)
+			remap_size = HDMI_VP_REMAP_YCC422_24bit;
+		else
+			return;
+		output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+	} else
+		return;
+
+	/* set the packetizer registers */
+	val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+		HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+		((hdmi_data->pix_repet_factor <<
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+		HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK;
+	val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	/* Data from pixel repeater block */
+	if (hdmi_data->pix_repet_factor > 1) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+			HDMI_VP_CONF_BYPASS_SELECT_MASK);
+		val |= HDMI_VP_CONF_PR_EN_ENABLE |
+			HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else { /* data from packetizer block */
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_PR_EN_MASK |
+			HDMI_VP_CONF_BYPASS_SELECT_MASK);
+		val |= HDMI_VP_CONF_PR_EN_DISABLE |
+			HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	}
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK;
+	val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+
+	if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			HDMI_VP_CONF_PP_EN_ENABLE |
+			HDMI_VP_CONF_YCC422_EN_DISABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_DISABLE |
+			HDMI_VP_CONF_PP_EN_DISABLE |
+			HDMI_VP_CONF_YCC422_EN_ENABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+		val = hdmi_readb(hdmi, HDMI_VP_CONF);
+		val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK |
+			HDMI_VP_CONF_PP_EN_ENMASK |
+			HDMI_VP_CONF_YCC422_EN_MASK);
+		val |= HDMI_VP_CONF_BYPASS_EN_ENABLE |
+			HDMI_VP_CONF_PP_EN_DISABLE |
+			HDMI_VP_CONF_YCC422_EN_DISABLE;
+		hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+	} else {
+		return;
+	}
+
+	val = hdmi_readb(hdmi, HDMI_VP_STUFF);
+	val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK |
+		HDMI_VP_STUFF_YCC422_STUFFING_MASK);
+	val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+		HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE;
+	hdmi_writeb(hdmi, val, HDMI_VP_STUFF);
+
+	val = hdmi_readb(hdmi, HDMI_VP_CONF);
+	val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK;
+	val |= output_select;
+	hdmi_writeb(hdmi, val, HDMI_VP_CONF);
+}
+
+static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTCLR_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) &
+		HDMI_PHY_TST0_TSTCLR_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTEN_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) &
+		HDMI_PHY_TST0_TSTEN_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0);
+	val &= ~HDMI_PHY_TST0_TSTCLK_MASK;
+	val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) &
+		HDMI_PHY_TST0_TSTCLK_MASK;
+	hdmi_writeb(hdmi, val, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
+						unsigned char bit)
+{
+	hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
+{
+	unsigned char val = 0;
+	val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
+	while (!val) {
+		udelay(1000);
+		if (msec-- == 0)
+			return false;
+		val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3;
+	}
+	return true;
+}
+
+static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+			      unsigned char addr)
+{
+	hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 8),
+		HDMI_PHY_I2CM_DATAO_1_ADDR);
+	hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+		HDMI_PHY_I2CM_DATAO_0_ADDR);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+		HDMI_PHY_I2CM_OPERATION_ADDR);
+	hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
+				     unsigned char addr)
+{
+	__hdmi_phy_i2c_write(hdmi, data, addr);
+	return 0;
+}
+
+static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_PDZ_OFFSET,
+			 HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_ENTMDS_OFFSET,
+			 HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+			 HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+			 HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
+{
+	hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+			 HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+			 HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
+			      unsigned char res, int cscon)
+{
+	u8 val, msec;
+
+	/* color resolution 0 is 8 bit colour depth */
+	if (!res)
+		res = 8;
+
+	if (prep)
+		return -EINVAL;
+	else if (res != 8 && res != 12)
+		return -EINVAL;
+
+	/* Enable csc path */
+	if (cscon)
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+	else
+		val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+	hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+
+	/* gen2 tx power off */
+	imx_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+	/* gen2 pddq */
+	imx_hdmi_phy_gen2_pddq(hdmi, 1);
+
+	/* PHY reset */
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+	hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+	hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+	hdmi_phy_test_clear(hdmi, 1);
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+			HDMI_PHY_I2CM_SLAVE_ADDR);
+	hdmi_phy_test_clear(hdmi, 0);
+
+	if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) {
+		switch (res) {
+		case 8:
+			/* PLL/MPLL Cfg */
+			hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);  /* GMPCTRL */
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x0140, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x2141, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x4142, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+		default:
+			return -EINVAL;
+		}
+	} else {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x2001, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x4002, 0x06);
+			hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+		default:
+			return -EINVAL;
+		}
+	}
+
+	if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);  /* CURRCTRL */
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) {
+		switch (res) {
+		case 8:
+			hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10);
+			break;
+		case 10:
+			hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10);
+			break;
+		case 12:
+			hdmi_phy_i2c_write(hdmi, 0x091c, 0x10);
+			break;
+		default:
+			return -EINVAL;
+		}
+	} else {
+		dev_err(hdmi->dev,
+				"Pixel clock %d - unsupported by HDMI\n",
+				hdmi->hdmi_data.video_mode.mpixelclock);
+		return -EINVAL;
+	}
+
+	hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);  /* PLLPHBYCTRL */
+	hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+	/* RESISTANCE TERM 133Ohm Cfg */
+	hdmi_phy_i2c_write(hdmi, 0x0005, 0x19);  /* TXTERM */
+	/* PREEMP Cgf 0.00 */
+	hdmi_phy_i2c_write(hdmi, 0x800d, 0x09);  /* CKSYMTXCTRL */
+	/* TX/CK LVL 10 */
+	hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E);  /* VLEVCTRL */
+	/* REMOVE CLK TERM */
+	hdmi_phy_i2c_write(hdmi, 0x8000, 0x05);  /* CKCALCTRL */
+
+	imx_hdmi_phy_enable_power(hdmi, 1);
+
+	/* toggle TMDS enable */
+	imx_hdmi_phy_enable_tmds(hdmi, 0);
+	imx_hdmi_phy_enable_tmds(hdmi, 1);
+
+	/* gen2 tx power on */
+	imx_hdmi_phy_gen2_txpwron(hdmi, 1);
+	imx_hdmi_phy_gen2_pddq(hdmi, 0);
+
+	/*Wait for PHY PLL lock */
+	msec = 4;
+	val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+	while (!val) {
+		udelay(1000);
+		if (msec-- == 0) {
+			dev_dbg(hdmi->dev, "PHY PLL not locked\n");
+			return -EINVAL;
+		}
+		val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+	}
+
+	return 0;
+}
+
+static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
+{
+	int i, ret;
+	bool cscon = false;
+
+	/*check csc whether needed activated in HDMI mode */
+	cscon = (is_color_space_conversion(hdmi) &&
+			!hdmi->hdmi_data.video_mode.mdvi);
+
+	/* HDMI Phy spec says to do the phy initialization sequence twice */
+	for (i = 0; i < 2; i++) {
+		imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
+		imx_hdmi_phy_sel_interface_control(hdmi, 0);
+		imx_hdmi_phy_enable_tmds(hdmi, 0);
+		imx_hdmi_phy_enable_power(hdmi, 0);
+
+		/* Enable CSC */
+		ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+		if (ret)
+			return ret;
+	}
+
+	hdmi->phy_enabled = true;
+	return 0;
+}
+
+static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
+{
+	u8 de, val;
+
+	if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+	else
+		de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+	/* disable rx detect */
+	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0);
+	val &= HDMI_A_HDCPCFG0_RXDETECT_MASK;
+	val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE;
+	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0);
+
+	val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG);
+	val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK;
+	val |= de;
+	hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG);
+
+	val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1);
+	val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK;
+	val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE;
+	hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1);
+}
+
+static void hdmi_config_AVI(struct imx_hdmi *hdmi)
+{
+	u8 val, pix_fmt, under_scan;
+	u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+	bool aspect_16_9;
+
+	aspect_16_9 = false; /* FIXME */
+
+	/* AVI Data Byte 1 */
+	if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+	else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+	else
+		pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+		under_scan =  HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+	/*
+	 * Active format identification data is present in the AVI InfoFrame.
+	 * Under scan info, no bar data
+	 */
+	val = pix_fmt | under_scan |
+		HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+		HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+
+	/* AVI Data Byte 2 -Set the Aspect Ratio */
+	if (aspect_16_9) {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+	} else {
+		act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+		coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+	}
+
+	/* Set up colorimetry */
+	if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+		if (hdmi->hdmi_data.colorimetry == ITU601)
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+		else /* hdmi->hdmi_data.colorimetry == ITU709 */
+			ext_colorimetry =
+				HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+	} else if (hdmi->hdmi_data.enc_out_format != RGB) {
+		if (hdmi->hdmi_data.colorimetry == ITU601)
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+		else /* hdmi->hdmi_data.colorimetry == ITU709 */
+			colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	} else { /* Carries no data */
+		colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+		ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+	}
+
+	val = colorimetry | coded_ratio | act_ratio;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+
+	/* AVI Data Byte 3 */
+	val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+		HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+		HDMI_FC_AVICONF2_SCALING_NONE;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+
+	/* AVI Data Byte 4 */
+	hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+
+	/* AVI Data Byte 5- set up input and output pixel repetition */
+	val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+		((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+		HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+	hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+
+	/* IT Content and quantization range = don't care */
+	val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+		HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+	hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+
+	/* AVI Data Bytes 6-13 */
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
+	hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+}
+
+static void hdmi_av_composer(struct imx_hdmi *hdmi,
+			     const struct drm_display_mode *mode)
+{
+	u8 inv_val;
+	struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+	int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+
+	vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+	vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+	vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+	vmode->mpixelclock = mode->htotal * mode->vtotal *
+			     drm_mode_vrefresh(mode);
+
+	dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+	/* Set up HDMI_FC_INVIDCONF */
+	inv_val = (hdmi->hdmi_data.hdcp_enable ?
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+		HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+	inv_val |= (vmode->mvsyncpolarity ?
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mhsyncpolarity ?
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+	inv_val |= (vmode->mdataenablepolarity ?
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+		HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+	if (hdmi->vic == 39)
+		inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+	else
+		inv_val |= (vmode->minterlaced ?
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+			HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+	inv_val |= (vmode->minterlaced ?
+		HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+		HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+	inv_val |= (vmode->mdvi ?
+		HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+		HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+	hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
+	/* Set up horizontal active pixel width */
+	hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+	hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+
+	/* Set up vertical active lines */
+	hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+	hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+
+	/* Set up horizontal blanking pixel region width */
+	hblank = mode->htotal - mode->hdisplay;
+	hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+	hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+	/* Set up vertical blanking pixel region width */
+	vblank = mode->vtotal - mode->vdisplay;
+	hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+	/* Set up HSYNC active edge delay width (in pixel clks) */
+	h_de_hs = mode->hsync_start - mode->hdisplay;
+	hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+	hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+	/* Set up VSYNC active edge delay (in lines) */
+	v_de_vs = mode->vsync_start - mode->vdisplay;
+	hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+	/* Set up HSYNC active pulse width (in pixel clks) */
+	hsync_len = mode->hsync_end - mode->hsync_start;
+	hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+	hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+	/* Set up VSYNC active edge delay (in pixel clks) */
+	vsync_len = mode->vsync_end - mode->vsync_start;
+	hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+}
+
+static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+{
+	if (!hdmi->phy_enabled)
+		return;
+
+	imx_hdmi_phy_enable_tmds(hdmi, 0);
+	imx_hdmi_phy_enable_power(hdmi, 0);
+
+	hdmi->phy_enabled = false;
+}
+
+/* HDMI Initialization Step B.4 */
+static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+{
+	u8 clkdis;
+
+	/* control period minimum duration */
+	hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
+	hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
+	hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+
+	/* Set to fill TMDS data channels */
+	hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+	hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
+	hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+
+	/* Enable pixel clock and tmds data path */
+	clkdis = 0x7F;
+	clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+	/* Enable csc path */
+	if (is_color_space_conversion(hdmi)) {
+		clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+		hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+	}
+}
+
+static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+{
+	u8 clkdis;
+
+	clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS);
+	clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
+	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
+{
+	int count;
+	u8 val;
+
+	/* TMDS software reset */
+	hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+	val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+	if (hdmi->dev_type == IMX6DL_HDMI) {
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+		return;
+	}
+
+	for (count = 0; count < 5; count++)
+		hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
+{
+	hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+		    HDMI_IH_MUTE_FC_STAT2);
+}
+
+static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
+{
+	int ret;
+
+	hdmi_disable_overflow_interrupts(hdmi);
+
+	hdmi->vic = drm_match_cea_mode(mode);
+
+	if (!hdmi->vic) {
+		dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
+		hdmi->hdmi_data.video_mode.mdvi = true;
+	} else {
+		dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+		hdmi->hdmi_data.video_mode.mdvi = false;
+	}
+
+	if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+		(hdmi->vic == 21) || (hdmi->vic == 22) ||
+		(hdmi->vic == 2) || (hdmi->vic == 3) ||
+		(hdmi->vic == 17) || (hdmi->vic == 18))
+		hdmi->hdmi_data.colorimetry = ITU601;
+	else
+		hdmi->hdmi_data.colorimetry = ITU709;
+
+	if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+		(hdmi->vic == 12) || (hdmi->vic == 13) ||
+		(hdmi->vic == 14) || (hdmi->vic == 15) ||
+		(hdmi->vic == 25) || (hdmi->vic == 26) ||
+		(hdmi->vic == 27) || (hdmi->vic == 28) ||
+		(hdmi->vic == 29) || (hdmi->vic == 30) ||
+		(hdmi->vic == 35) || (hdmi->vic == 36) ||
+		(hdmi->vic == 37) || (hdmi->vic == 38))
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
+	else
+		hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
+
+	hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+	/* TODO: Get input format from IPU (via FB driver interface) */
+	hdmi->hdmi_data.enc_in_format = RGB;
+
+	hdmi->hdmi_data.enc_out_format = RGB;
+
+	hdmi->hdmi_data.enc_color_depth = 8;
+	hdmi->hdmi_data.pix_repet_factor = 0;
+	hdmi->hdmi_data.hdcp_enable = 0;
+	hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
+
+	/* HDMI Initialization Step B.1 */
+	hdmi_av_composer(hdmi, mode);
+
+	/* HDMI Initializateion Step B.2 */
+	ret = imx_hdmi_phy_init(hdmi);
+	if (ret)
+		return ret;
+
+	/* HDMI Initialization Step B.3 */
+	imx_hdmi_enable_video_path(hdmi);
+
+	/* not for DVI mode */
+	if (hdmi->hdmi_data.video_mode.mdvi)
+		dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
+	else {
+		dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+
+		/* HDMI Initialization Step E - Configure audio */
+		hdmi_clk_regenerator_update_pixel_clock(hdmi);
+		hdmi_enable_audio_clk(hdmi);
+
+		/* HDMI Initialization Step F - Configure AVI InfoFrame */
+		hdmi_config_AVI(hdmi);
+	}
+
+	hdmi_video_packetize(hdmi);
+	hdmi_video_csc(hdmi);
+	hdmi_video_sample(hdmi);
+	hdmi_tx_hdcp_config(hdmi);
+
+	imx_hdmi_clear_overflow(hdmi);
+	if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+		hdmi_enable_overflow_interrupts(hdmi);
+
+	return 0;
+}
+
+/* Wait until we are registered to enable interrupts */
+static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
+{
+	int ret;
+
+	if (hdmi->fb_reg)
+		return 0;
+
+	ret = clk_prepare_enable(hdmi->iahb_clk);
+	if (ret)
+		return ret;
+
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+		    HDMI_PHY_I2CM_INT_ADDR);
+
+	hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+		    HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+		    HDMI_PHY_I2CM_CTLINT_ADDR);
+
+	/* enable cable hot plug irq */
+	hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	/* Unmute interrupts */
+	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+	hdmi->fb_reg = true;
+
+	clk_disable_unprepare(hdmi->iahb_clk);
+
+	return 0;
+}
+
+static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
+{
+	u8 ih_mute;
+
+	/*
+	 * Boot up defaults are:
+	 * HDMI_IH_MUTE   = 0x03 (disabled)
+	 * HDMI_IH_MUTE_* = 0x00 (enabled)
+	 *
+	 * Disable top level interrupt bits in HDMI block
+	 */
+	ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+		  HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		  HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+	/* by default mask all interrupts */
+	hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+	hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+	hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+	hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
+	hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+
+	/* Disable interrupts in the IH_MUTE_* registers */
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+	hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+	/* Enable top level interrupt bits in HDMI block */
+	ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+		    HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+	hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
+
+static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
+{
+	imx_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
+{
+	imx_hdmi_phy_disable(hdmi);
+}
+
+static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
+							*connector, bool force)
+{
+	/* FIXME */
+	return connector_status_connected;
+}
+
+static void imx_hdmi_connector_destroy(struct drm_connector *connector)
+{
+}
+
+static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+	struct edid *edid;
+	int ret;
+
+	if (!hdmi->ddc)
+		return 0;
+
+	edid = drm_get_edid(connector, hdmi->ddc);
+	if (edid) {
+		dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		drm_mode_connector_update_edid_property(connector, edid);
+		ret = drm_add_edid_modes(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(hdmi->dev, "failed to get edid\n");
+	}
+
+	return 0;
+}
+
+static int imx_hdmi_connector_mode_valid(struct drm_connector *connector,
+			  struct drm_display_mode *mode)
+{
+
+	return MODE_OK;
+}
+
+static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
+							   *connector)
+{
+	struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
+					     connector);
+
+	return &hdmi->encoder;
+}
+
+static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+			struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	imx_hdmi_setup(hdmi, mode);
+
+	/* Store the display mode for plugin/DKMS poweron events */
+	memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
+			const struct drm_display_mode *mode,
+			struct drm_display_mode *adjusted_mode)
+{
+	return true;
+}
+
+static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	if (mode)
+		imx_hdmi_poweroff(hdmi);
+	else
+		imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+
+	imx_hdmi_poweroff(hdmi);
+	imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE,
+				  V4L2_PIX_FMT_RGB24);
+}
+
+static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
+{
+	struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+	int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder,
+					     encoder->crtc);
+
+	imx_hdmi_set_ipu_di_mux(hdmi, mux);
+
+	imx_hdmi_poweron(hdmi);
+}
+
+static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder)
+{
+	return;
+}
+
+static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
+	.destroy = imx_hdmi_encoder_destroy,
+};
+
+static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
+	.dpms = imx_hdmi_encoder_dpms,
+	.prepare = imx_hdmi_encoder_prepare,
+	.commit = imx_hdmi_encoder_commit,
+	.mode_set = imx_hdmi_encoder_mode_set,
+	.mode_fixup = imx_hdmi_encoder_mode_fixup,
+	.disable = imx_hdmi_encoder_disable,
+};
+
+static struct drm_connector_funcs imx_hdmi_connector_funcs = {
+	.dpms = drm_helper_connector_dpms,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = imx_hdmi_connector_detect,
+	.destroy = imx_hdmi_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
+	.get_modes = imx_hdmi_connector_get_modes,
+	.mode_valid = imx_hdmi_connector_mode_valid,
+	.best_encoder = imx_hdmi_connector_best_encoder,
+};
+
+static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
+{
+	struct imx_hdmi *hdmi = dev_id;
+	u8 intr_stat;
+	u8 phy_int_pol;
+	u8 val;
+
+	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+
+	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+
+	if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+		if (phy_int_pol & HDMI_PHY_HPD) {
+			dev_dbg(hdmi->dev, "EVENT=plugin\n");
+
+			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
+			val &= ~HDMI_PHY_HPD;
+			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+
+			imx_hdmi_poweron(hdmi);
+		} else {
+			dev_dbg(hdmi->dev, "EVENT=plugout\n");
+
+			val = hdmi_readb(hdmi, HDMI_PHY_POL0);
+			val |= HDMI_PHY_HPD;
+			hdmi_writeb(hdmi, val, HDMI_PHY_POL0);
+
+			imx_hdmi_poweroff(hdmi);
+		}
+	}
+
+	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+
+	return IRQ_HANDLED;
+}
+
+static int imx_hdmi_register(struct imx_hdmi *hdmi)
+{
+	int ret;
+
+	hdmi->connector.funcs = &imx_hdmi_connector_funcs;
+	hdmi->encoder.funcs = &imx_hdmi_encoder_funcs;
+
+	hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS;
+	hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA;
+
+	drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
+	ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder,
+			THIS_MODULE);
+	if (ret) {
+		dev_err(hdmi->dev, "adding encoder failed: %d\n", ret);
+		return ret;
+	}
+
+	drm_connector_helper_add(&hdmi->connector,
+			&imx_hdmi_connector_helper_funcs);
+
+	ret = imx_drm_add_connector(&hdmi->connector,
+			&hdmi->imx_drm_connector, THIS_MODULE);
+	if (ret) {
+		imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+		dev_err(hdmi->dev, "adding connector failed: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->connector.encoder = &hdmi->encoder;
+
+	drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
+
+	return 0;
+}
+
+static struct platform_device_id imx_hdmi_devtype[] = {
+	{
+		.name = "imx6q-hdmi",
+		.driver_data = IMX6Q_HDMI,
+	}, {
+		.name = "imx6dl-hdmi",
+		.driver_data = IMX6DL_HDMI,
+	}, { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
+
+static const struct of_device_id imx_hdmi_dt_ids[] = {
+{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
+{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
+{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+
+static int imx_hdmi_platform_probe(struct platform_device *pdev)
+{
+	const struct of_device_id *of_id =
+				of_match_device(imx_hdmi_dt_ids, &pdev->dev);
+	struct device_node *np = pdev->dev.of_node;
+	struct device_node *ddc_node;
+	struct imx_hdmi *hdmi;
+	int ret, irq;
+	struct resource *iores;
+
+	hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+	if (!hdmi)
+		return -ENOMEM;
+
+	hdmi->dev = &pdev->dev;
+
+	if (of_id) {
+		const struct platform_device_id *device_id = of_id->data;
+		hdmi->dev_type = device_id->driver_data;
+	}
+
+	ddc_node = of_parse_phandle(np, "ddc", 0);
+	if (ddc_node) {
+		hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+		if (!hdmi->ddc)
+			dev_dbg(hdmi->dev, "failed to read ddc node\n");
+
+		of_node_put(ddc_node);
+	} else {
+		dev_dbg(hdmi->dev, "no ddc property found\n");
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -EINVAL;
+
+	ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0,
+			       dev_name(&pdev->dev), hdmi);
+	if (ret)
+		return ret;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hdmi->regs = devm_ioremap_resource(&pdev->dev, iores);
+	if (IS_ERR(hdmi->regs))
+		return PTR_ERR(hdmi->regs);
+
+	hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+	if (IS_ERR(hdmi->regmap))
+		return PTR_ERR(hdmi->regmap);
+
+	hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+	if (IS_ERR(hdmi->isfr_clk)) {
+		ret = PTR_ERR(hdmi->isfr_clk);
+		dev_err(hdmi->dev,
+			"Unable to get HDMI isfr clk: %d\n", ret);
+		return ret;
+	}
+
+	ret = clk_prepare_enable(hdmi->isfr_clk);
+	if (ret) {
+		dev_err(hdmi->dev,
+			"Cannot enable HDMI isfr clock: %d\n", ret);
+		return ret;
+	}
+
+	hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+	if (IS_ERR(hdmi->iahb_clk)) {
+		ret = PTR_ERR(hdmi->iahb_clk);
+		dev_err(hdmi->dev,
+			"Unable to get HDMI iahb clk: %d\n", ret);
+		goto err_isfr;
+	}
+
+	ret = clk_prepare_enable(hdmi->iahb_clk);
+	if (ret) {
+		dev_err(hdmi->dev,
+			"Cannot enable HDMI iahb clock: %d\n", ret);
+		goto err_isfr;
+	}
+
+	/* Product and revision IDs */
+	dev_info(&pdev->dev,
+		"Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+		hdmi_readb(hdmi, HDMI_DESIGN_ID),
+		hdmi_readb(hdmi, HDMI_REVISION_ID),
+		hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+		hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+
+	initialize_hdmi_ih_mutes(hdmi);
+
+	/*
+	 * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+	 * N and cts values before enabling phy
+	 */
+	hdmi_init_clk_regenerator(hdmi);
+
+	/*
+	 * Configure registers related to HDMI interrupt
+	 * generation before registering IRQ.
+	 */
+	hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+	/* Clear Hotplug interrupts */
+	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+	ret = imx_hdmi_fb_registered(hdmi);
+	if (ret)
+		goto err_iahb;
+
+	ret = imx_hdmi_register(hdmi);
+	if (ret)
+		goto err_iahb;
+
+	imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np);
+
+	platform_set_drvdata(pdev, hdmi);
+
+	return 0;
+
+err_iahb:
+	clk_disable_unprepare(hdmi->iahb_clk);
+err_isfr:
+	clk_disable_unprepare(hdmi->isfr_clk);
+
+	return ret;
+}
+
+static int imx_hdmi_platform_remove(struct platform_device *pdev)
+{
+	struct imx_hdmi *hdmi = platform_get_drvdata(pdev);
+	struct drm_connector *connector = &hdmi->connector;
+	struct drm_encoder *encoder = &hdmi->encoder;
+
+	drm_mode_connector_detach_encoder(connector, encoder);
+	imx_drm_remove_connector(hdmi->imx_drm_connector);
+	imx_drm_remove_encoder(hdmi->imx_drm_encoder);
+
+	clk_disable_unprepare(hdmi->iahb_clk);
+	clk_disable_unprepare(hdmi->isfr_clk);
+	i2c_put_adapter(hdmi->ddc);
+
+	return 0;
+}
+
+static struct platform_driver imx_hdmi_driver = {
+	.probe  = imx_hdmi_platform_probe,
+	.remove = imx_hdmi_platform_remove,
+	.driver = {
+		.name = "imx-hdmi",
+		.owner = THIS_MODULE,
+		.of_match_table = imx_hdmi_dt_ids,
+	},
+};
+
+module_platform_driver(imx_hdmi_driver);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
new file mode 100644
index 000000000000..39b677689db6
--- /dev/null
+++ b/drivers/staging/imx-drm/imx-hdmi.h
@@ -0,0 +1,1032 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * 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 __IMX_HDMI_H__
+#define __IMX_HDMI_H__
+
+/* Identification Registers */
+#define HDMI_DESIGN_ID                          0x0000
+#define HDMI_REVISION_ID                        0x0001
+#define HDMI_PRODUCT_ID0                        0x0002
+#define HDMI_PRODUCT_ID1                        0x0003
+#define HDMI_CONFIG0_ID                         0x0004
+#define HDMI_CONFIG1_ID                         0x0005
+#define HDMI_CONFIG2_ID                         0x0006
+#define HDMI_CONFIG3_ID                         0x0007
+
+/* Interrupt Registers */
+#define HDMI_IH_FC_STAT0                        0x0100
+#define HDMI_IH_FC_STAT1                        0x0101
+#define HDMI_IH_FC_STAT2                        0x0102
+#define HDMI_IH_AS_STAT0                        0x0103
+#define HDMI_IH_PHY_STAT0                       0x0104
+#define HDMI_IH_I2CM_STAT0                      0x0105
+#define HDMI_IH_CEC_STAT0                       0x0106
+#define HDMI_IH_VP_STAT0                        0x0107
+#define HDMI_IH_I2CMPHY_STAT0                   0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0                 0x0109
+
+#define HDMI_IH_MUTE_FC_STAT0                   0x0180
+#define HDMI_IH_MUTE_FC_STAT1                   0x0181
+#define HDMI_IH_MUTE_FC_STAT2                   0x0182
+#define HDMI_IH_MUTE_AS_STAT0                   0x0183
+#define HDMI_IH_MUTE_PHY_STAT0                  0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0                 0x0185
+#define HDMI_IH_MUTE_CEC_STAT0                  0x0186
+#define HDMI_IH_MUTE_VP_STAT0                   0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0              0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0            0x0189
+#define HDMI_IH_MUTE                            0x01FF
+
+/* Video Sample Registers */
+#define HDMI_TX_INVID0                          0x0200
+#define HDMI_TX_INSTUFFING                      0x0201
+#define HDMI_TX_GYDATA0                         0x0202
+#define HDMI_TX_GYDATA1                         0x0203
+#define HDMI_TX_RCRDATA0                        0x0204
+#define HDMI_TX_RCRDATA1                        0x0205
+#define HDMI_TX_BCBDATA0                        0x0206
+#define HDMI_TX_BCBDATA1                        0x0207
+
+/* Video Packetizer Registers */
+#define HDMI_VP_STATUS                          0x0800
+#define HDMI_VP_PR_CD                           0x0801
+#define HDMI_VP_STUFF                           0x0802
+#define HDMI_VP_REMAP                           0x0803
+#define HDMI_VP_CONF                            0x0804
+#define HDMI_VP_STAT                            0x0805
+#define HDMI_VP_INT                             0x0806
+#define HDMI_VP_MASK                            0x0807
+#define HDMI_VP_POL                             0x0808
+
+/* Frame Composer Registers */
+#define HDMI_FC_INVIDCONF                       0x1000
+#define HDMI_FC_INHACTV0                        0x1001
+#define HDMI_FC_INHACTV1                        0x1002
+#define HDMI_FC_INHBLANK0                       0x1003
+#define HDMI_FC_INHBLANK1                       0x1004
+#define HDMI_FC_INVACTV0                        0x1005
+#define HDMI_FC_INVACTV1                        0x1006
+#define HDMI_FC_INVBLANK                        0x1007
+#define HDMI_FC_HSYNCINDELAY0                   0x1008
+#define HDMI_FC_HSYNCINDELAY1                   0x1009
+#define HDMI_FC_HSYNCINWIDTH0                   0x100A
+#define HDMI_FC_HSYNCINWIDTH1                   0x100B
+#define HDMI_FC_VSYNCINDELAY                    0x100C
+#define HDMI_FC_VSYNCINWIDTH                    0x100D
+#define HDMI_FC_INFREQ0                         0x100E
+#define HDMI_FC_INFREQ1                         0x100F
+#define HDMI_FC_INFREQ2                         0x1010
+#define HDMI_FC_CTRLDUR                         0x1011
+#define HDMI_FC_EXCTRLDUR                       0x1012
+#define HDMI_FC_EXCTRLSPAC                      0x1013
+#define HDMI_FC_CH0PREAM                        0x1014
+#define HDMI_FC_CH1PREAM                        0x1015
+#define HDMI_FC_CH2PREAM                        0x1016
+#define HDMI_FC_AVICONF3                        0x1017
+#define HDMI_FC_GCP                             0x1018
+#define HDMI_FC_AVICONF0                        0x1019
+#define HDMI_FC_AVICONF1                        0x101A
+#define HDMI_FC_AVICONF2                        0x101B
+#define HDMI_FC_AVIVID                          0x101C
+#define HDMI_FC_AVIETB0                         0x101D
+#define HDMI_FC_AVIETB1                         0x101E
+#define HDMI_FC_AVISBB0                         0x101F
+#define HDMI_FC_AVISBB1                         0x1020
+#define HDMI_FC_AVIELB0                         0x1021
+#define HDMI_FC_AVIELB1                         0x1022
+#define HDMI_FC_AVISRB0                         0x1023
+#define HDMI_FC_AVISRB1                         0x1024
+#define HDMI_FC_AUDICONF0                       0x1025
+#define HDMI_FC_AUDICONF1                       0x1026
+#define HDMI_FC_AUDICONF2                       0x1027
+#define HDMI_FC_AUDICONF3                       0x1028
+#define HDMI_FC_VSDIEEEID0                      0x1029
+#define HDMI_FC_VSDSIZE                         0x102A
+#define HDMI_FC_VSDIEEEID1                      0x1030
+#define HDMI_FC_VSDIEEEID2                      0x1031
+#define HDMI_FC_VSDPAYLOAD0                     0x1032
+#define HDMI_FC_VSDPAYLOAD1                     0x1033
+#define HDMI_FC_VSDPAYLOAD2                     0x1034
+#define HDMI_FC_VSDPAYLOAD3                     0x1035
+#define HDMI_FC_VSDPAYLOAD4                     0x1036
+#define HDMI_FC_VSDPAYLOAD5                     0x1037
+#define HDMI_FC_VSDPAYLOAD6                     0x1038
+#define HDMI_FC_VSDPAYLOAD7                     0x1039
+#define HDMI_FC_VSDPAYLOAD8                     0x103A
+#define HDMI_FC_VSDPAYLOAD9                     0x103B
+#define HDMI_FC_VSDPAYLOAD10                    0x103C
+#define HDMI_FC_VSDPAYLOAD11                    0x103D
+#define HDMI_FC_VSDPAYLOAD12                    0x103E
+#define HDMI_FC_VSDPAYLOAD13                    0x103F
+#define HDMI_FC_VSDPAYLOAD14                    0x1040
+#define HDMI_FC_VSDPAYLOAD15                    0x1041
+#define HDMI_FC_VSDPAYLOAD16                    0x1042
+#define HDMI_FC_VSDPAYLOAD17                    0x1043
+#define HDMI_FC_VSDPAYLOAD18                    0x1044
+#define HDMI_FC_VSDPAYLOAD19                    0x1045
+#define HDMI_FC_VSDPAYLOAD20                    0x1046
+#define HDMI_FC_VSDPAYLOAD21                    0x1047
+#define HDMI_FC_VSDPAYLOAD22                    0x1048
+#define HDMI_FC_VSDPAYLOAD23                    0x1049
+#define HDMI_FC_SPDVENDORNAME0                  0x104A
+#define HDMI_FC_SPDVENDORNAME1                  0x104B
+#define HDMI_FC_SPDVENDORNAME2                  0x104C
+#define HDMI_FC_SPDVENDORNAME3                  0x104D
+#define HDMI_FC_SPDVENDORNAME4                  0x104E
+#define HDMI_FC_SPDVENDORNAME5                  0x104F
+#define HDMI_FC_SPDVENDORNAME6                  0x1050
+#define HDMI_FC_SPDVENDORNAME7                  0x1051
+#define HDMI_FC_SDPPRODUCTNAME0                 0x1052
+#define HDMI_FC_SDPPRODUCTNAME1                 0x1053
+#define HDMI_FC_SDPPRODUCTNAME2                 0x1054
+#define HDMI_FC_SDPPRODUCTNAME3                 0x1055
+#define HDMI_FC_SDPPRODUCTNAME4                 0x1056
+#define HDMI_FC_SDPPRODUCTNAME5                 0x1057
+#define HDMI_FC_SDPPRODUCTNAME6                 0x1058
+#define HDMI_FC_SDPPRODUCTNAME7                 0x1059
+#define HDMI_FC_SDPPRODUCTNAME8                 0x105A
+#define HDMI_FC_SDPPRODUCTNAME9                 0x105B
+#define HDMI_FC_SDPPRODUCTNAME10                0x105C
+#define HDMI_FC_SDPPRODUCTNAME11                0x105D
+#define HDMI_FC_SDPPRODUCTNAME12                0x105E
+#define HDMI_FC_SDPPRODUCTNAME13                0x105F
+#define HDMI_FC_SDPPRODUCTNAME14                0x1060
+#define HDMI_FC_SPDPRODUCTNAME15                0x1061
+#define HDMI_FC_SPDDEVICEINF                    0x1062
+#define HDMI_FC_AUDSCONF                        0x1063
+#define HDMI_FC_AUDSSTAT                        0x1064
+#define HDMI_FC_DATACH0FILL                     0x1070
+#define HDMI_FC_DATACH1FILL                     0x1071
+#define HDMI_FC_DATACH2FILL                     0x1072
+#define HDMI_FC_CTRLQHIGH                       0x1073
+#define HDMI_FC_CTRLQLOW                        0x1074
+#define HDMI_FC_ACP0                            0x1075
+#define HDMI_FC_ACP28                           0x1076
+#define HDMI_FC_ACP27                           0x1077
+#define HDMI_FC_ACP26                           0x1078
+#define HDMI_FC_ACP25                           0x1079
+#define HDMI_FC_ACP24                           0x107A
+#define HDMI_FC_ACP23                           0x107B
+#define HDMI_FC_ACP22                           0x107C
+#define HDMI_FC_ACP21                           0x107D
+#define HDMI_FC_ACP20                           0x107E
+#define HDMI_FC_ACP19                           0x107F
+#define HDMI_FC_ACP18                           0x1080
+#define HDMI_FC_ACP17                           0x1081
+#define HDMI_FC_ACP16                           0x1082
+#define HDMI_FC_ACP15                           0x1083
+#define HDMI_FC_ACP14                           0x1084
+#define HDMI_FC_ACP13                           0x1085
+#define HDMI_FC_ACP12                           0x1086
+#define HDMI_FC_ACP11                           0x1087
+#define HDMI_FC_ACP10                           0x1088
+#define HDMI_FC_ACP9                            0x1089
+#define HDMI_FC_ACP8                            0x108A
+#define HDMI_FC_ACP7                            0x108B
+#define HDMI_FC_ACP6                            0x108C
+#define HDMI_FC_ACP5                            0x108D
+#define HDMI_FC_ACP4                            0x108E
+#define HDMI_FC_ACP3                            0x108F
+#define HDMI_FC_ACP2                            0x1090
+#define HDMI_FC_ACP1                            0x1091
+#define HDMI_FC_ISCR1_0                         0x1092
+#define HDMI_FC_ISCR1_16                        0x1093
+#define HDMI_FC_ISCR1_15                        0x1094
+#define HDMI_FC_ISCR1_14                        0x1095
+#define HDMI_FC_ISCR1_13                        0x1096
+#define HDMI_FC_ISCR1_12                        0x1097
+#define HDMI_FC_ISCR1_11                        0x1098
+#define HDMI_FC_ISCR1_10                        0x1099
+#define HDMI_FC_ISCR1_9                         0x109A
+#define HDMI_FC_ISCR1_8                         0x109B
+#define HDMI_FC_ISCR1_7                         0x109C
+#define HDMI_FC_ISCR1_6                         0x109D
+#define HDMI_FC_ISCR1_5                         0x109E
+#define HDMI_FC_ISCR1_4                         0x109F
+#define HDMI_FC_ISCR1_3                         0x10A0
+#define HDMI_FC_ISCR1_2                         0x10A1
+#define HDMI_FC_ISCR1_1                         0x10A2
+#define HDMI_FC_ISCR2_15                        0x10A3
+#define HDMI_FC_ISCR2_14                        0x10A4
+#define HDMI_FC_ISCR2_13                        0x10A5
+#define HDMI_FC_ISCR2_12                        0x10A6
+#define HDMI_FC_ISCR2_11                        0x10A7
+#define HDMI_FC_ISCR2_10                        0x10A8
+#define HDMI_FC_ISCR2_9                         0x10A9
+#define HDMI_FC_ISCR2_8                         0x10AA
+#define HDMI_FC_ISCR2_7                         0x10AB
+#define HDMI_FC_ISCR2_6                         0x10AC
+#define HDMI_FC_ISCR2_5                         0x10AD
+#define HDMI_FC_ISCR2_4                         0x10AE
+#define HDMI_FC_ISCR2_3                         0x10AF
+#define HDMI_FC_ISCR2_2                         0x10B0
+#define HDMI_FC_ISCR2_1                         0x10B1
+#define HDMI_FC_ISCR2_0                         0x10B2
+#define HDMI_FC_DATAUTO0                        0x10B3
+#define HDMI_FC_DATAUTO1                        0x10B4
+#define HDMI_FC_DATAUTO2                        0x10B5
+#define HDMI_FC_DATMAN                          0x10B6
+#define HDMI_FC_DATAUTO3                        0x10B7
+#define HDMI_FC_RDRB0                           0x10B8
+#define HDMI_FC_RDRB1                           0x10B9
+#define HDMI_FC_RDRB2                           0x10BA
+#define HDMI_FC_RDRB3                           0x10BB
+#define HDMI_FC_RDRB4                           0x10BC
+#define HDMI_FC_RDRB5                           0x10BD
+#define HDMI_FC_RDRB6                           0x10BE
+#define HDMI_FC_RDRB7                           0x10BF
+#define HDMI_FC_STAT0                           0x10D0
+#define HDMI_FC_INT0                            0x10D1
+#define HDMI_FC_MASK0                           0x10D2
+#define HDMI_FC_POL0                            0x10D3
+#define HDMI_FC_STAT1                           0x10D4
+#define HDMI_FC_INT1                            0x10D5
+#define HDMI_FC_MASK1                           0x10D6
+#define HDMI_FC_POL1                            0x10D7
+#define HDMI_FC_STAT2                           0x10D8
+#define HDMI_FC_INT2                            0x10D9
+#define HDMI_FC_MASK2                           0x10DA
+#define HDMI_FC_POL2                            0x10DB
+#define HDMI_FC_PRCONF                          0x10E0
+
+#define HDMI_FC_GMD_STAT                        0x1100
+#define HDMI_FC_GMD_EN                          0x1101
+#define HDMI_FC_GMD_UP                          0x1102
+#define HDMI_FC_GMD_CONF                        0x1103
+#define HDMI_FC_GMD_HB                          0x1104
+#define HDMI_FC_GMD_PB0                         0x1105
+#define HDMI_FC_GMD_PB1                         0x1106
+#define HDMI_FC_GMD_PB2                         0x1107
+#define HDMI_FC_GMD_PB3                         0x1108
+#define HDMI_FC_GMD_PB4                         0x1109
+#define HDMI_FC_GMD_PB5                         0x110A
+#define HDMI_FC_GMD_PB6                         0x110B
+#define HDMI_FC_GMD_PB7                         0x110C
+#define HDMI_FC_GMD_PB8                         0x110D
+#define HDMI_FC_GMD_PB9                         0x110E
+#define HDMI_FC_GMD_PB10                        0x110F
+#define HDMI_FC_GMD_PB11                        0x1110
+#define HDMI_FC_GMD_PB12                        0x1111
+#define HDMI_FC_GMD_PB13                        0x1112
+#define HDMI_FC_GMD_PB14                        0x1113
+#define HDMI_FC_GMD_PB15                        0x1114
+#define HDMI_FC_GMD_PB16                        0x1115
+#define HDMI_FC_GMD_PB17                        0x1116
+#define HDMI_FC_GMD_PB18                        0x1117
+#define HDMI_FC_GMD_PB19                        0x1118
+#define HDMI_FC_GMD_PB20                        0x1119
+#define HDMI_FC_GMD_PB21                        0x111A
+#define HDMI_FC_GMD_PB22                        0x111B
+#define HDMI_FC_GMD_PB23                        0x111C
+#define HDMI_FC_GMD_PB24                        0x111D
+#define HDMI_FC_GMD_PB25                        0x111E
+#define HDMI_FC_GMD_PB26                        0x111F
+#define HDMI_FC_GMD_PB27                        0x1120
+
+#define HDMI_FC_DBGFORCE                        0x1200
+#define HDMI_FC_DBGAUD0CH0                      0x1201
+#define HDMI_FC_DBGAUD1CH0                      0x1202
+#define HDMI_FC_DBGAUD2CH0                      0x1203
+#define HDMI_FC_DBGAUD0CH1                      0x1204
+#define HDMI_FC_DBGAUD1CH1                      0x1205
+#define HDMI_FC_DBGAUD2CH1                      0x1206
+#define HDMI_FC_DBGAUD0CH2                      0x1207
+#define HDMI_FC_DBGAUD1CH2                      0x1208
+#define HDMI_FC_DBGAUD2CH2                      0x1209
+#define HDMI_FC_DBGAUD0CH3                      0x120A
+#define HDMI_FC_DBGAUD1CH3                      0x120B
+#define HDMI_FC_DBGAUD2CH3                      0x120C
+#define HDMI_FC_DBGAUD0CH4                      0x120D
+#define HDMI_FC_DBGAUD1CH4                      0x120E
+#define HDMI_FC_DBGAUD2CH4                      0x120F
+#define HDMI_FC_DBGAUD0CH5                      0x1210
+#define HDMI_FC_DBGAUD1CH5                      0x1211
+#define HDMI_FC_DBGAUD2CH5                      0x1212
+#define HDMI_FC_DBGAUD0CH6                      0x1213
+#define HDMI_FC_DBGAUD1CH6                      0x1214
+#define HDMI_FC_DBGAUD2CH6                      0x1215
+#define HDMI_FC_DBGAUD0CH7                      0x1216
+#define HDMI_FC_DBGAUD1CH7                      0x1217
+#define HDMI_FC_DBGAUD2CH7                      0x1218
+#define HDMI_FC_DBGTMDS0                        0x1219
+#define HDMI_FC_DBGTMDS1                        0x121A
+#define HDMI_FC_DBGTMDS2                        0x121B
+
+/* HDMI Source PHY Registers */
+#define HDMI_PHY_CONF0                          0x3000
+#define HDMI_PHY_TST0                           0x3001
+#define HDMI_PHY_TST1                           0x3002
+#define HDMI_PHY_TST2                           0x3003
+#define HDMI_PHY_STAT0                          0x3004
+#define HDMI_PHY_INT0                           0x3005
+#define HDMI_PHY_MASK0                          0x3006
+#define HDMI_PHY_POL0                           0x3007
+
+/* HDMI Master PHY Registers */
+#define HDMI_PHY_I2CM_SLAVE_ADDR                0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR              0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR              0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR              0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR              0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR              0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR            0x3026
+#define HDMI_PHY_I2CM_INT_ADDR                  0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR               0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR                  0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR             0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR        0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR        0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR        0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR        0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR        0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR        0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR        0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR        0x3032
+
+/* Audio Sampler Registers */
+#define HDMI_AUD_CONF0                          0x3100
+#define HDMI_AUD_CONF1                          0x3101
+#define HDMI_AUD_INT                            0x3102
+#define HDMI_AUD_CONF2                          0x3103
+#define HDMI_AUD_N1                             0x3200
+#define HDMI_AUD_N2                             0x3201
+#define HDMI_AUD_N3                             0x3202
+#define HDMI_AUD_CTS1                           0x3203
+#define HDMI_AUD_CTS2                           0x3204
+#define HDMI_AUD_CTS3                           0x3205
+#define HDMI_AUD_INPUTCLKFS                     0x3206
+#define HDMI_AUD_SPDIFINT			0x3302
+#define HDMI_AUD_CONF0_HBR                      0x3400
+#define HDMI_AUD_HBR_STATUS                     0x3401
+#define HDMI_AUD_HBR_INT                        0x3402
+#define HDMI_AUD_HBR_POL                        0x3403
+#define HDMI_AUD_HBR_MASK                       0x3404
+
+/*
+ * Generic Parallel Audio Interface Registers
+ * Not used as GPAUD interface is not enabled in hw
+ */
+#define HDMI_GP_CONF0                           0x3500
+#define HDMI_GP_CONF1                           0x3501
+#define HDMI_GP_CONF2                           0x3502
+#define HDMI_GP_STAT                            0x3503
+#define HDMI_GP_INT                             0x3504
+#define HDMI_GP_MASK                            0x3505
+#define HDMI_GP_POL                             0x3506
+
+/* Audio DMA Registers */
+#define HDMI_AHB_DMA_CONF0                      0x3600
+#define HDMI_AHB_DMA_START                      0x3601
+#define HDMI_AHB_DMA_STOP                       0x3602
+#define HDMI_AHB_DMA_THRSLD                     0x3603
+#define HDMI_AHB_DMA_STRADDR0                   0x3604
+#define HDMI_AHB_DMA_STRADDR1                   0x3605
+#define HDMI_AHB_DMA_STRADDR2                   0x3606
+#define HDMI_AHB_DMA_STRADDR3                   0x3607
+#define HDMI_AHB_DMA_STPADDR0                   0x3608
+#define HDMI_AHB_DMA_STPADDR1                   0x3609
+#define HDMI_AHB_DMA_STPADDR2                   0x360a
+#define HDMI_AHB_DMA_STPADDR3                   0x360b
+#define HDMI_AHB_DMA_BSTADDR0                   0x360c
+#define HDMI_AHB_DMA_BSTADDR1                   0x360d
+#define HDMI_AHB_DMA_BSTADDR2                   0x360e
+#define HDMI_AHB_DMA_BSTADDR3                   0x360f
+#define HDMI_AHB_DMA_MBLENGTH0                  0x3610
+#define HDMI_AHB_DMA_MBLENGTH1                  0x3611
+#define HDMI_AHB_DMA_STAT                       0x3612
+#define HDMI_AHB_DMA_INT                        0x3613
+#define HDMI_AHB_DMA_MASK                       0x3614
+#define HDMI_AHB_DMA_POL                        0x3615
+#define HDMI_AHB_DMA_CONF1                      0x3616
+#define HDMI_AHB_DMA_BUFFSTAT                   0x3617
+#define HDMI_AHB_DMA_BUFFINT                    0x3618
+#define HDMI_AHB_DMA_BUFFMASK                   0x3619
+#define HDMI_AHB_DMA_BUFFPOL                    0x361a
+
+/* Main Controller Registers */
+#define HDMI_MC_SFRDIV                          0x4000
+#define HDMI_MC_CLKDIS                          0x4001
+#define HDMI_MC_SWRSTZ                          0x4002
+#define HDMI_MC_OPCTRL                          0x4003
+#define HDMI_MC_FLOWCTRL                        0x4004
+#define HDMI_MC_PHYRSTZ                         0x4005
+#define HDMI_MC_LOCKONCLOCK                     0x4006
+#define HDMI_MC_HEACPHY_RST                     0x4007
+
+/* Color Space  Converter Registers */
+#define HDMI_CSC_CFG                            0x4100
+#define HDMI_CSC_SCALE                          0x4101
+#define HDMI_CSC_COEF_A1_MSB                    0x4102
+#define HDMI_CSC_COEF_A1_LSB                    0x4103
+#define HDMI_CSC_COEF_A2_MSB                    0x4104
+#define HDMI_CSC_COEF_A2_LSB                    0x4105
+#define HDMI_CSC_COEF_A3_MSB                    0x4106
+#define HDMI_CSC_COEF_A3_LSB                    0x4107
+#define HDMI_CSC_COEF_A4_MSB                    0x4108
+#define HDMI_CSC_COEF_A4_LSB                    0x4109
+#define HDMI_CSC_COEF_B1_MSB                    0x410A
+#define HDMI_CSC_COEF_B1_LSB                    0x410B
+#define HDMI_CSC_COEF_B2_MSB                    0x410C
+#define HDMI_CSC_COEF_B2_LSB                    0x410D
+#define HDMI_CSC_COEF_B3_MSB                    0x410E
+#define HDMI_CSC_COEF_B3_LSB                    0x410F
+#define HDMI_CSC_COEF_B4_MSB                    0x4110
+#define HDMI_CSC_COEF_B4_LSB                    0x4111
+#define HDMI_CSC_COEF_C1_MSB                    0x4112
+#define HDMI_CSC_COEF_C1_LSB                    0x4113
+#define HDMI_CSC_COEF_C2_MSB                    0x4114
+#define HDMI_CSC_COEF_C2_LSB                    0x4115
+#define HDMI_CSC_COEF_C3_MSB                    0x4116
+#define HDMI_CSC_COEF_C3_LSB                    0x4117
+#define HDMI_CSC_COEF_C4_MSB                    0x4118
+#define HDMI_CSC_COEF_C4_LSB                    0x4119
+
+/* HDCP Encryption Engine Registers */
+#define HDMI_A_HDCPCFG0                         0x5000
+#define HDMI_A_HDCPCFG1                         0x5001
+#define HDMI_A_HDCPOBS0                         0x5002
+#define HDMI_A_HDCPOBS1                         0x5003
+#define HDMI_A_HDCPOBS2                         0x5004
+#define HDMI_A_HDCPOBS3                         0x5005
+#define HDMI_A_APIINTCLR                        0x5006
+#define HDMI_A_APIINTSTAT                       0x5007
+#define HDMI_A_APIINTMSK                        0x5008
+#define HDMI_A_VIDPOLCFG                        0x5009
+#define HDMI_A_OESSWCFG                         0x500A
+#define HDMI_A_TIMER1SETUP0                     0x500B
+#define HDMI_A_TIMER1SETUP1                     0x500C
+#define HDMI_A_TIMER2SETUP0                     0x500D
+#define HDMI_A_TIMER2SETUP1                     0x500E
+#define HDMI_A_100MSCFG                         0x500F
+#define HDMI_A_2SCFG0                           0x5010
+#define HDMI_A_2SCFG1                           0x5011
+#define HDMI_A_5SCFG0                           0x5012
+#define HDMI_A_5SCFG1                           0x5013
+#define HDMI_A_SRMVERLSB                        0x5014
+#define HDMI_A_SRMVERMSB                        0x5015
+#define HDMI_A_SRMCTRL                          0x5016
+#define HDMI_A_SFRSETUP                         0x5017
+#define HDMI_A_I2CHSETUP                        0x5018
+#define HDMI_A_INTSETUP                         0x5019
+#define HDMI_A_PRESETUP                         0x501A
+#define HDMI_A_SRM_BASE                         0x5020
+
+/* CEC Engine Registers */
+#define HDMI_CEC_CTRL                           0x7D00
+#define HDMI_CEC_STAT                           0x7D01
+#define HDMI_CEC_MASK                           0x7D02
+#define HDMI_CEC_POLARITY                       0x7D03
+#define HDMI_CEC_INT                            0x7D04
+#define HDMI_CEC_ADDR_L                         0x7D05
+#define HDMI_CEC_ADDR_H                         0x7D06
+#define HDMI_CEC_TX_CNT                         0x7D07
+#define HDMI_CEC_RX_CNT                         0x7D08
+#define HDMI_CEC_TX_DATA0                       0x7D10
+#define HDMI_CEC_TX_DATA1                       0x7D11
+#define HDMI_CEC_TX_DATA2                       0x7D12
+#define HDMI_CEC_TX_DATA3                       0x7D13
+#define HDMI_CEC_TX_DATA4                       0x7D14
+#define HDMI_CEC_TX_DATA5                       0x7D15
+#define HDMI_CEC_TX_DATA6                       0x7D16
+#define HDMI_CEC_TX_DATA7                       0x7D17
+#define HDMI_CEC_TX_DATA8                       0x7D18
+#define HDMI_CEC_TX_DATA9                       0x7D19
+#define HDMI_CEC_TX_DATA10                      0x7D1a
+#define HDMI_CEC_TX_DATA11                      0x7D1b
+#define HDMI_CEC_TX_DATA12                      0x7D1c
+#define HDMI_CEC_TX_DATA13                      0x7D1d
+#define HDMI_CEC_TX_DATA14                      0x7D1e
+#define HDMI_CEC_TX_DATA15                      0x7D1f
+#define HDMI_CEC_RX_DATA0                       0x7D20
+#define HDMI_CEC_RX_DATA1                       0x7D21
+#define HDMI_CEC_RX_DATA2                       0x7D22
+#define HDMI_CEC_RX_DATA3                       0x7D23
+#define HDMI_CEC_RX_DATA4                       0x7D24
+#define HDMI_CEC_RX_DATA5                       0x7D25
+#define HDMI_CEC_RX_DATA6                       0x7D26
+#define HDMI_CEC_RX_DATA7                       0x7D27
+#define HDMI_CEC_RX_DATA8                       0x7D28
+#define HDMI_CEC_RX_DATA9                       0x7D29
+#define HDMI_CEC_RX_DATA10                      0x7D2a
+#define HDMI_CEC_RX_DATA11                      0x7D2b
+#define HDMI_CEC_RX_DATA12                      0x7D2c
+#define HDMI_CEC_RX_DATA13                      0x7D2d
+#define HDMI_CEC_RX_DATA14                      0x7D2e
+#define HDMI_CEC_RX_DATA15                      0x7D2f
+#define HDMI_CEC_LOCK                           0x7D30
+#define HDMI_CEC_WKUPCTRL                       0x7D31
+
+/* I2C Master Registers (E-DDC) */
+#define HDMI_I2CM_SLAVE                         0x7E00
+#define HDMI_I2CMESS                            0x7E01
+#define HDMI_I2CM_DATAO                         0x7E02
+#define HDMI_I2CM_DATAI                         0x7E03
+#define HDMI_I2CM_OPERATION                     0x7E04
+#define HDMI_I2CM_INT                           0x7E05
+#define HDMI_I2CM_CTLINT                        0x7E06
+#define HDMI_I2CM_DIV                           0x7E07
+#define HDMI_I2CM_SEGADDR                       0x7E08
+#define HDMI_I2CM_SOFTRSTZ                      0x7E09
+#define HDMI_I2CM_SEGPTR                        0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR            0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR            0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR            0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR            0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR            0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR            0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR            0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR            0x7E12
+
+enum {
+/* IH_FC_INT2 field values */
+	HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_FC_STAT2 field values */
+	HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_PHY_STAT0 field values */
+	HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
+	HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
+	HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
+	HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
+	HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
+	HDMI_IH_PHY_STAT0_HPD = 0x1,
+
+/* IH_MUTE_I2CMPHY_STAT0 field values */
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+	HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
+/* IH_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE_FC_STAT2 field values */
+	HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_MUTE_AHBDMAAUD_STAT0 field values */
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+	HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE field values */
+	HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
+	HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
+
+/* TX_INVID0 field values */
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
+	HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
+	HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
+	HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
+
+/* TX_INSTUFFING field values */
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
+	HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
+	HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
+	HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
+
+/* VP_PR_CD field values */
+	HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
+	HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
+	HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
+
+/* VP_STUFF field values */
+	HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
+	HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
+	HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
+	HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
+	HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
+	HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
+	HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
+	HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
+	HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
+
+/* VP_CONF field values */
+	HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
+	HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
+	HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
+	HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_PR_EN_MASK = 0x10,
+	HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
+	HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
+	HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
+	HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
+	HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
+	HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
+	HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
+	HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
+
+/* VP_REMAP field values */
+	HDMI_VP_REMAP_MASK = 0x3,
+	HDMI_VP_REMAP_YCC422_24bit = 0x2,
+	HDMI_VP_REMAP_YCC422_20bit = 0x1,
+	HDMI_VP_REMAP_YCC422_16bit = 0x0,
+
+/* FC_INVIDCONF field values */
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
+	HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
+	HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
+	HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
+	HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
+	HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
+	HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
+	HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
+	HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
+
+/* FC_AUDICONF0 field values */
+	HDMI_FC_AUDICONF0_CC_OFFSET = 4,
+	HDMI_FC_AUDICONF0_CC_MASK = 0x70,
+	HDMI_FC_AUDICONF0_CT_OFFSET = 0,
+	HDMI_FC_AUDICONF0_CT_MASK = 0xF,
+
+/* FC_AUDICONF1 field values */
+	HDMI_FC_AUDICONF1_SS_OFFSET = 3,
+	HDMI_FC_AUDICONF1_SS_MASK = 0x18,
+	HDMI_FC_AUDICONF1_SF_OFFSET = 0,
+	HDMI_FC_AUDICONF1_SF_MASK = 0x7,
+
+/* FC_AUDICONF3 field values */
+	HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
+	HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
+	HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
+	HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
+	HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
+	HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
+
+/* FC_AUDSCHNLS0 field values */
+	HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
+
+/* FC_AUDSCHNLS3-6 field values */
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
+
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
+
+/* HDMI_FC_AUDSCHNLS7 field values */
+	HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+
+/* HDMI_FC_AUDSCHNLS8 field values */
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
+	HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
+	HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+
+/* FC_AUDSCONF field values */
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
+	HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
+
+/* FC_STAT2 field values */
+	HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_INT2 field values */
+	HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_MASK2 field values */
+	HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
+	HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
+	HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_PRCONF field values */
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
+	HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
+	HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
+
+/* FC_AVICONF0-FC_AVICONF3 field values */
+	HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
+	HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+	HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
+	HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
+	HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+	HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+	HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+	HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+	HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+	HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
+	HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
+
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
+	HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
+	HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
+	HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
+	HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
+	HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
+	HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
+	HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
+
+	HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
+	HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
+	HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
+	HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
+	HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
+	HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
+	HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
+	HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
+	HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
+	HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
+	HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
+	HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
+	HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
+
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+	HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
+	HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
+	HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
+	HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+
+/* FC_DBGFORCE field values */
+	HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
+	HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+
+/* PHY_CONF0 field values */
+	HDMI_PHY_CONF0_PDZ_MASK = 0x80,
+	HDMI_PHY_CONF0_PDZ_OFFSET = 7,
+	HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
+	HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
+	HDMI_PHY_CONF0_SPARECTRL = 0x20,
+	HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
+	HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
+	HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
+	HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
+	HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
+	HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
+	HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
+	HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
+
+/* PHY_TST0 field values */
+	HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
+	HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
+	HDMI_PHY_TST0_TSTEN_MASK = 0x10,
+	HDMI_PHY_TST0_TSTEN_OFFSET = 4,
+	HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
+	HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
+
+/* PHY_STAT0 field values */
+	HDMI_PHY_RX_SENSE3 = 0x80,
+	HDMI_PHY_RX_SENSE2 = 0x40,
+	HDMI_PHY_RX_SENSE1 = 0x20,
+	HDMI_PHY_RX_SENSE0 = 0x10,
+	HDMI_PHY_HPD = 0x02,
+	HDMI_PHY_TX_PHY_LOCK = 0x01,
+
+/* PHY_I2CM_SLAVE_ADDR field values */
+	HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
+	HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
+
+/* PHY_I2CM_OPERATION_ADDR field values */
+	HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
+	HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
+
+/* HDMI_PHY_I2CM_INT_ADDR */
+	HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
+	HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
+
+/* HDMI_PHY_I2CM_CTLINT_ADDR */
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
+	HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
+	HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
+
+/* AUD_CTS3 field values */
+	HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
+	HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
+	HDMI_AUD_CTS3_N_SHIFT_1 = 0,
+	HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
+	HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
+	HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
+	HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
+	HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
+	/* note that the CTS3 MANUAL bit has been removed
+	   from our part. Can't set it, will read as 0. */
+	HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
+	HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
+
+/* AHB_DMA_CONF0 field values */
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
+	HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
+	HDMI_AHB_DMA_CONF0_HBR = 0x10,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
+	HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
+	HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
+	HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
+	HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
+	HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
+	HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
+
+/* HDMI_AHB_DMA_START field values */
+	HDMI_AHB_DMA_START_START_OFFSET = 0,
+	HDMI_AHB_DMA_START_START_MASK = 0x01,
+
+/* HDMI_AHB_DMA_STOP field values */
+	HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
+	HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
+
+/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
+	HDMI_AHB_DMA_DONE = 0x80,
+	HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
+	HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
+	HDMI_AHB_DMA_ERROR = 0x10,
+	HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
+	HDMI_AHB_DMA_FIFO_FULL = 0x02,
+	HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
+
+/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
+	HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
+	HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
+
+/* MC_CLKDIS field values */
+	HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
+	HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
+	HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
+	HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
+	HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
+	HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
+	HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
+
+/* MC_SWRSTZ field values */
+	HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+
+/* MC_FLOWCTRL field values */
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
+	HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
+
+/* MC_PHYRSTZ field values */
+	HDMI_MC_PHYRSTZ_ASSERT = 0x0,
+	HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+
+/* MC_HEACPHY_RST field values */
+	HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
+	HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
+
+/* CSC_CFG field values */
+	HDMI_CSC_CFG_INTMODE_MASK = 0x30,
+	HDMI_CSC_CFG_INTMODE_OFFSET = 4,
+	HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
+	HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
+	HDMI_CSC_CFG_DECMODE_MASK = 0x3,
+	HDMI_CSC_CFG_DECMODE_OFFSET = 0,
+	HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
+	HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
+
+/* CSC_SCALE field values */
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
+	HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
+	HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
+
+/* A_HDCPCFG0 field values */
+	HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
+	HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
+	HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
+	HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
+	HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
+	HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
+	HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
+	HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
+	HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
+	HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
+	HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
+
+/* A_HDCPCFG1 field values */
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
+	HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
+	HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
+	HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
+	HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
+	HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+
+/* A_VIDPOLCFG field values */
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
+	HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
+	HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
+	HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
+	HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
+	HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
+};
+#endif /* __IMX_HDMI_H__ */
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index b6d36b38b99c..866e355fa409 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -212,6 +212,7 @@
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1	(0x1 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0	(0x2 << 4)
 #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1	(0x3 << 4)
+#define IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT		2
 #define IMX6Q_GPR3_HDMI_MUX_CTL_MASK		(0x3 << 2)
 #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0	(0x0 << 2)
 #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1	(0x1 << 2)
-- 
1.7.4.4

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-02 21:27   ` Russell King
@ 2014-01-03  3:10     ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-03  3:10 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
> 
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
> 
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};
> 
> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
> 
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.

This sounds a lot like the "containers" code that Rafael just submitted
and I acked for 3.14.  Look at the lkml post:
	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>

And see if that could possibly be used instead?

thanks,

greg k-h

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03  3:10     ` Greg Kroah-Hartman
  0 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-03  3:10 UTC (permalink / raw)
  To: Russell King, Rafael J. Wysocki
  Cc: devel, David Airlie, dri-devel, Sascha Hauer, Shawn Guo,
	linux-arm-kernel

On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
> 
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
> 
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};
> 
> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
> 
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.

This sounds a lot like the "containers" code that Rafael just submitted
and I acked for 3.14.  Look at the lkml post:
	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>

And see if that could possibly be used instead?

thanks,

greg k-h

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03  3:10     ` Greg Kroah-Hartman
@ 2014-01-03 11:00       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 11:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> > 
> > The superdevice is declared into the component support, along with the
> > subcomponents.  The superdevice receives callbacks to locate the
> > subcomponents, and identify when all components are present.  At this
> > point, we bind the superdevice, which causes the appropriate subsystem
> > to be initialised in the conventional way.
> > 
> > When any of the components or superdevice are removed from the system,
> > we unbind the superdevice, thereby taking the subsystem down.
> 
> This sounds a lot like the "containers" code that Rafael just submitted
> and I acked for 3.14.  Look at the lkml post:
> 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> 
> And see if that could possibly be used instead?

That's really disappointing bcause I've put a hell of a lot of work into
this over the last few months, and if that's true it's all just been a
total waste of my time.  Okay, lesson learned - don't spend any time
trying to fix other people's problems after discussing them at
kernel-summit.

In any case, the above message ID doesn't give me access to this containers
code to look at to even evaluate whether it can be used for this - it just
gives two patches for ACPI specific patches but not the core stuff.

http://www.spinics.net/lists/linux-acpi/msg48101.html
http://www.spinics.net/lists/linux-acpi/msg48102.html

Please provide a better reference to the code you're referring to.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03 11:00       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 11:00 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> > 
> > The superdevice is declared into the component support, along with the
> > subcomponents.  The superdevice receives callbacks to locate the
> > subcomponents, and identify when all components are present.  At this
> > point, we bind the superdevice, which causes the appropriate subsystem
> > to be initialised in the conventional way.
> > 
> > When any of the components or superdevice are removed from the system,
> > we unbind the superdevice, thereby taking the subsystem down.
> 
> This sounds a lot like the "containers" code that Rafael just submitted
> and I acked for 3.14.  Look at the lkml post:
> 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> 
> And see if that could possibly be used instead?

That's really disappointing bcause I've put a hell of a lot of work into
this over the last few months, and if that's true it's all just been a
total waste of my time.  Okay, lesson learned - don't spend any time
trying to fix other people's problems after discussing them at
kernel-summit.

In any case, the above message ID doesn't give me access to this containers
code to look at to even evaluate whether it can be used for this - it just
gives two patches for ACPI specific patches but not the core stuff.

http://www.spinics.net/lists/linux-acpi/msg48101.html
http://www.spinics.net/lists/linux-acpi/msg48102.html

Please provide a better reference to the code you're referring to.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03 11:00       ` Russell King - ARM Linux
@ 2014-01-03 11:58         ` Rafael J. Wysocki
  -1 siblings, 0 replies; 219+ messages in thread
From: Rafael J. Wysocki @ 2014-01-03 11:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > > 
> > > The superdevice is declared into the component support, along with the
> > > subcomponents.  The superdevice receives callbacks to locate the
> > > subcomponents, and identify when all components are present.  At this
> > > point, we bind the superdevice, which causes the appropriate subsystem
> > > to be initialised in the conventional way.
> > > 
> > > When any of the components or superdevice are removed from the system,
> > > we unbind the superdevice, thereby taking the subsystem down.
> > 
> > This sounds a lot like the "containers" code that Rafael just submitted
> > and I acked for 3.14.  Look at the lkml post:
> > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > 
> > And see if that could possibly be used instead?
> 
> That's really disappointing bcause I've put a hell of a lot of work into
> this over the last few months, and if that's true it's all just been a
> total waste of my time.  Okay, lesson learned - don't spend any time
> trying to fix other people's problems after discussing them at
> kernel-summit.

Well, I didn't know that you were doing this work and my patch is to address
a specific problem that people are seeing in testing.  Also, the generic
containers part in it is very simple and it might be possible to integrate it
with your code, this way or another.  In fact, the only only thing I need from
containers at the moment is the online/offline functionality.

> In any case, the above message ID doesn't give me access to this containers
> code to look at to even evaluate whether it can be used for this - it just
> gives two patches for ACPI specific patches but not the core stuff.
> 
> http://www.spinics.net/lists/linux-acpi/msg48101.html
> http://www.spinics.net/lists/linux-acpi/msg48102.html
> 
> Please provide a better reference to the code you're referring to.

You can use the linux-next branch of the linux-pm.git tree at the moment or I
can set up a separate branch for that if that helps.  The two patches above
depend on some earlier material I've gueued up for 3.14, but it's mostly
ACPI hotplug code.

Thanks,
Rafael

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03 11:58         ` Rafael J. Wysocki
  0 siblings, 0 replies; 219+ messages in thread
From: Rafael J. Wysocki @ 2014-01-03 11:58 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > > 
> > > The superdevice is declared into the component support, along with the
> > > subcomponents.  The superdevice receives callbacks to locate the
> > > subcomponents, and identify when all components are present.  At this
> > > point, we bind the superdevice, which causes the appropriate subsystem
> > > to be initialised in the conventional way.
> > > 
> > > When any of the components or superdevice are removed from the system,
> > > we unbind the superdevice, thereby taking the subsystem down.
> > 
> > This sounds a lot like the "containers" code that Rafael just submitted
> > and I acked for 3.14.  Look at the lkml post:
> > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > 
> > And see if that could possibly be used instead?
> 
> That's really disappointing bcause I've put a hell of a lot of work into
> this over the last few months, and if that's true it's all just been a
> total waste of my time.  Okay, lesson learned - don't spend any time
> trying to fix other people's problems after discussing them at
> kernel-summit.

Well, I didn't know that you were doing this work and my patch is to address
a specific problem that people are seeing in testing.  Also, the generic
containers part in it is very simple and it might be possible to integrate it
with your code, this way or another.  In fact, the only only thing I need from
containers at the moment is the online/offline functionality.

> In any case, the above message ID doesn't give me access to this containers
> code to look at to even evaluate whether it can be used for this - it just
> gives two patches for ACPI specific patches but not the core stuff.
> 
> http://www.spinics.net/lists/linux-acpi/msg48101.html
> http://www.spinics.net/lists/linux-acpi/msg48102.html
> 
> Please provide a better reference to the code you're referring to.

You can use the linux-next branch of the linux-pm.git tree at the moment or I
can set up a separate branch for that if that helps.  The two patches above
depend on some earlier material I've gueued up for 3.14, but it's mostly
ACPI hotplug code.

Thanks,
Rafael

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03 11:58         ` Rafael J. Wysocki
@ 2014-01-03 12:18           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 12:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 12:58:16PM +0100, Rafael J. Wysocki wrote:
> On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> > On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > device structure to represent a subsystem.  However, firmware tends to
> > > > describe the individual devices and the connections between them.
> > > > 
> > > > Therefore, we need a way to gather up the individual component devices
> > > > together, and indicate when we have all the component devices.
> > > > 
> > > > We do this in DT by providing a "superdevice" node which specifies
> > > > the components, eg:
> > > > 
> > > > 	imx-drm {
> > > > 		compatible = "fsl,drm";
> > > > 		crtcs = <&ipu1>;
> > > > 		connectors = <&hdmi>;
> > > > 	};
> > > > 
> > > > The superdevice is declared into the component support, along with the
> > > > subcomponents.  The superdevice receives callbacks to locate the
> > > > subcomponents, and identify when all components are present.  At this
> > > > point, we bind the superdevice, which causes the appropriate subsystem
> > > > to be initialised in the conventional way.
> > > > 
> > > > When any of the components or superdevice are removed from the system,
> > > > we unbind the superdevice, thereby taking the subsystem down.
> > > 
> > > This sounds a lot like the "containers" code that Rafael just submitted
> > > and I acked for 3.14.  Look at the lkml post:
> > > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > > 
> > > And see if that could possibly be used instead?
> > 
> > That's really disappointing bcause I've put a hell of a lot of work into
> > this over the last few months, and if that's true it's all just been a
> > total waste of my time.  Okay, lesson learned - don't spend any time
> > trying to fix other people's problems after discussing them at
> > kernel-summit.
> 
> Well, I didn't know that you were doing this work and my patch is to address
> a specific problem that people are seeing in testing.  Also, the generic
> containers part in it is very simple and it might be possible to integrate it
> with your code, this way or another.  In fact, the only only thing I need from
> containers at the moment is the online/offline functionality.

We had a session at kernel summit chaired by David Airlie to discuss
various issues associated with DRM which included the problems of
componentised devices registering into card-based subsystems.  There
were quite a number of attendees to that session.

It is in that session that I said I would work on this, specifically
with the aim of getting imx-drm out of drivers/staging.

> > In any case, the above message ID doesn't give me access to this containers
> > code to look at to even evaluate whether it can be used for this - it just
> > gives two patches for ACPI specific patches but not the core stuff.
> > 
> > http://www.spinics.net/lists/linux-acpi/msg48101.html
> > http://www.spinics.net/lists/linux-acpi/msg48102.html
> > 
> > Please provide a better reference to the code you're referring to.
> 
> You can use the linux-next branch of the linux-pm.git tree at the moment or I
> can set up a separate branch for that if that helps.  The two patches above
> depend on some earlier material I've gueued up for 3.14, but it's mostly
> ACPI hotplug code.

I'm not sure what I'm looking for.  I've tried looking at the results of
searching your linux-next branch for "container" but I don't see
anything implementing similar functionality to the patch I've sent.

https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03 12:18           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 12:18 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 03, 2014 at 12:58:16PM +0100, Rafael J. Wysocki wrote:
> On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> > On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > device structure to represent a subsystem.  However, firmware tends to
> > > > describe the individual devices and the connections between them.
> > > > 
> > > > Therefore, we need a way to gather up the individual component devices
> > > > together, and indicate when we have all the component devices.
> > > > 
> > > > We do this in DT by providing a "superdevice" node which specifies
> > > > the components, eg:
> > > > 
> > > > 	imx-drm {
> > > > 		compatible = "fsl,drm";
> > > > 		crtcs = <&ipu1>;
> > > > 		connectors = <&hdmi>;
> > > > 	};
> > > > 
> > > > The superdevice is declared into the component support, along with the
> > > > subcomponents.  The superdevice receives callbacks to locate the
> > > > subcomponents, and identify when all components are present.  At this
> > > > point, we bind the superdevice, which causes the appropriate subsystem
> > > > to be initialised in the conventional way.
> > > > 
> > > > When any of the components or superdevice are removed from the system,
> > > > we unbind the superdevice, thereby taking the subsystem down.
> > > 
> > > This sounds a lot like the "containers" code that Rafael just submitted
> > > and I acked for 3.14.  Look at the lkml post:
> > > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > > 
> > > And see if that could possibly be used instead?
> > 
> > That's really disappointing bcause I've put a hell of a lot of work into
> > this over the last few months, and if that's true it's all just been a
> > total waste of my time.  Okay, lesson learned - don't spend any time
> > trying to fix other people's problems after discussing them at
> > kernel-summit.
> 
> Well, I didn't know that you were doing this work and my patch is to address
> a specific problem that people are seeing in testing.  Also, the generic
> containers part in it is very simple and it might be possible to integrate it
> with your code, this way or another.  In fact, the only only thing I need from
> containers at the moment is the online/offline functionality.

We had a session at kernel summit chaired by David Airlie to discuss
various issues associated with DRM which included the problems of
componentised devices registering into card-based subsystems.  There
were quite a number of attendees to that session.

It is in that session that I said I would work on this, specifically
with the aim of getting imx-drm out of drivers/staging.

> > In any case, the above message ID doesn't give me access to this containers
> > code to look at to even evaluate whether it can be used for this - it just
> > gives two patches for ACPI specific patches but not the core stuff.
> > 
> > http://www.spinics.net/lists/linux-acpi/msg48101.html
> > http://www.spinics.net/lists/linux-acpi/msg48102.html
> > 
> > Please provide a better reference to the code you're referring to.
> 
> You can use the linux-next branch of the linux-pm.git tree at the moment or I
> can set up a separate branch for that if that helps.  The two patches above
> depend on some earlier material I've gueued up for 3.14, but it's mostly
> ACPI hotplug code.

I'm not sure what I'm looking for.  I've tried looking at the results of
searching your linux-next branch for "container" but I don't see
anything implementing similar functionality to the patch I've sent.

https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03 12:18           ` Russell King - ARM Linux
@ 2014-01-03 13:24             ` Rafael J. Wysocki
  -1 siblings, 0 replies; 219+ messages in thread
From: Rafael J. Wysocki @ 2014-01-03 13:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, January 03, 2014 12:18:13 PM Russell King - ARM Linux wrote:
> On Fri, Jan 03, 2014 at 12:58:16PM +0100, Rafael J. Wysocki wrote:
> > On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> > > On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > > > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > > device structure to represent a subsystem.  However, firmware tends to
> > > > > describe the individual devices and the connections between them.
> > > > > 
> > > > > Therefore, we need a way to gather up the individual component devices
> > > > > together, and indicate when we have all the component devices.
> > > > > 
> > > > > We do this in DT by providing a "superdevice" node which specifies
> > > > > the components, eg:
> > > > > 
> > > > > 	imx-drm {
> > > > > 		compatible = "fsl,drm";
> > > > > 		crtcs = <&ipu1>;
> > > > > 		connectors = <&hdmi>;
> > > > > 	};
> > > > > 
> > > > > The superdevice is declared into the component support, along with the
> > > > > subcomponents.  The superdevice receives callbacks to locate the
> > > > > subcomponents, and identify when all components are present.  At this
> > > > > point, we bind the superdevice, which causes the appropriate subsystem
> > > > > to be initialised in the conventional way.
> > > > > 
> > > > > When any of the components or superdevice are removed from the system,
> > > > > we unbind the superdevice, thereby taking the subsystem down.
> > > > 
> > > > This sounds a lot like the "containers" code that Rafael just submitted
> > > > and I acked for 3.14.  Look at the lkml post:
> > > > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > > > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > > > 
> > > > And see if that could possibly be used instead?
> > > 
> > > That's really disappointing bcause I've put a hell of a lot of work into
> > > this over the last few months, and if that's true it's all just been a
> > > total waste of my time.  Okay, lesson learned - don't spend any time
> > > trying to fix other people's problems after discussing them at
> > > kernel-summit.
> > 
> > Well, I didn't know that you were doing this work and my patch is to address
> > a specific problem that people are seeing in testing.  Also, the generic
> > containers part in it is very simple and it might be possible to integrate it
> > with your code, this way or another.  In fact, the only only thing I need from
> > containers at the moment is the online/offline functionality.
> 
> We had a session at kernel summit chaired by David Airlie to discuss
> various issues associated with DRM which included the problems of
> componentised devices registering into card-based subsystems.  There
> were quite a number of attendees to that session.

Yeah, I was there too.

> It is in that session that I said I would work on this, specifically
> with the aim of getting imx-drm out of drivers/staging.

OK, but that's not directly related to what I did with containers.

> > > In any case, the above message ID doesn't give me access to this containers
> > > code to look at to even evaluate whether it can be used for this - it just
> > > gives two patches for ACPI specific patches but not the core stuff.
> > > 
> > > http://www.spinics.net/lists/linux-acpi/msg48101.html
> > > http://www.spinics.net/lists/linux-acpi/msg48102.html
> > > 
> > > Please provide a better reference to the code you're referring to.
> > 
> > You can use the linux-next branch of the linux-pm.git tree at the moment or I
> > can set up a separate branch for that if that helps.  The two patches above
> > depend on some earlier material I've gueued up for 3.14, but it's mostly
> > ACPI hotplug code.
> 
> I'm not sure what I'm looking for.  I've tried looking at the results of
> searching your linux-next branch for "container" but I don't see
> anything implementing similar functionality to the patch I've sent.
> 
> https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container

I've just set up the acpi-hotplug branch in linux-pm.git (because I often
rebase the linux-next one).

The only commit in that branch you need to look at is this one:

http://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/commit/?h=acpi-hotplug&id=caa73ea158de9419f08e456f2716c71d1f06012a

but quite frankly I'm not sure how it is related to your work. :-)

Thanks,
Rafael

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03 13:24             ` Rafael J. Wysocki
  0 siblings, 0 replies; 219+ messages in thread
From: Rafael J. Wysocki @ 2014-01-03 13:24 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Friday, January 03, 2014 12:18:13 PM Russell King - ARM Linux wrote:
> On Fri, Jan 03, 2014 at 12:58:16PM +0100, Rafael J. Wysocki wrote:
> > On Friday, January 03, 2014 11:00:30 AM Russell King - ARM Linux wrote:
> > > On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > > > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > > device structure to represent a subsystem.  However, firmware tends to
> > > > > describe the individual devices and the connections between them.
> > > > > 
> > > > > Therefore, we need a way to gather up the individual component devices
> > > > > together, and indicate when we have all the component devices.
> > > > > 
> > > > > We do this in DT by providing a "superdevice" node which specifies
> > > > > the components, eg:
> > > > > 
> > > > > 	imx-drm {
> > > > > 		compatible = "fsl,drm";
> > > > > 		crtcs = <&ipu1>;
> > > > > 		connectors = <&hdmi>;
> > > > > 	};
> > > > > 
> > > > > The superdevice is declared into the component support, along with the
> > > > > subcomponents.  The superdevice receives callbacks to locate the
> > > > > subcomponents, and identify when all components are present.  At this
> > > > > point, we bind the superdevice, which causes the appropriate subsystem
> > > > > to be initialised in the conventional way.
> > > > > 
> > > > > When any of the components or superdevice are removed from the system,
> > > > > we unbind the superdevice, thereby taking the subsystem down.
> > > > 
> > > > This sounds a lot like the "containers" code that Rafael just submitted
> > > > and I acked for 3.14.  Look at the lkml post:
> > > > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > > > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > > > 
> > > > And see if that could possibly be used instead?
> > > 
> > > That's really disappointing bcause I've put a hell of a lot of work into
> > > this over the last few months, and if that's true it's all just been a
> > > total waste of my time.  Okay, lesson learned - don't spend any time
> > > trying to fix other people's problems after discussing them at
> > > kernel-summit.
> > 
> > Well, I didn't know that you were doing this work and my patch is to address
> > a specific problem that people are seeing in testing.  Also, the generic
> > containers part in it is very simple and it might be possible to integrate it
> > with your code, this way or another.  In fact, the only only thing I need from
> > containers at the moment is the online/offline functionality.
> 
> We had a session at kernel summit chaired by David Airlie to discuss
> various issues associated with DRM which included the problems of
> componentised devices registering into card-based subsystems.  There
> were quite a number of attendees to that session.

Yeah, I was there too.

> It is in that session that I said I would work on this, specifically
> with the aim of getting imx-drm out of drivers/staging.

OK, but that's not directly related to what I did with containers.

> > > In any case, the above message ID doesn't give me access to this containers
> > > code to look at to even evaluate whether it can be used for this - it just
> > > gives two patches for ACPI specific patches but not the core stuff.
> > > 
> > > http://www.spinics.net/lists/linux-acpi/msg48101.html
> > > http://www.spinics.net/lists/linux-acpi/msg48102.html
> > > 
> > > Please provide a better reference to the code you're referring to.
> > 
> > You can use the linux-next branch of the linux-pm.git tree at the moment or I
> > can set up a separate branch for that if that helps.  The two patches above
> > depend on some earlier material I've gueued up for 3.14, but it's mostly
> > ACPI hotplug code.
> 
> I'm not sure what I'm looking for.  I've tried looking at the results of
> searching your linux-next branch for "container" but I don't see
> anything implementing similar functionality to the patch I've sent.
> 
> https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container

I've just set up the acpi-hotplug branch in linux-pm.git (because I often
rebase the linux-next one).

The only commit in that branch you need to look at is this one:

http://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/commit/?h=acpi-hotplug&id=caa73ea158de9419f08e456f2716c71d1f06012a

but quite frankly I'm not sure how it is related to your work. :-)

Thanks,
Rafael

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03 13:24             ` Rafael J. Wysocki
@ 2014-01-03 14:14               ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 14:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 02:24:26PM +0100, Rafael J. Wysocki wrote:
> On Friday, January 03, 2014 12:18:13 PM Russell King - ARM Linux wrote:
> > I'm not sure what I'm looking for.  I've tried looking at the results of
> > searching your linux-next branch for "container" but I don't see
> > anything implementing similar functionality to the patch I've sent.
> > 
> > https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container
> 
> I've just set up the acpi-hotplug branch in linux-pm.git (because I often
> rebase the linux-next one).
> 
> The only commit in that branch you need to look at is this one:
> 
> http://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/commit/?h=acpi-hotplug&id=caa73ea158de9419f08e456f2716c71d1f06012a
> 
> but quite frankly I'm not sure how it is related to your work. :-)

Yes, I'm coming to that conclusion as well.  It looks like your "containers"
aren't about collecting up several individual component devices into one
super-device and probing the appropriate subsystem when all components are
known.

Confused why Greg is pointing me at your patches.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-03 14:14               ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 14:14 UTC (permalink / raw)
  To: Rafael J. Wysocki, Greg Kroah-Hartman
  Cc: devel, David Airlie, dri-devel, Sascha Hauer, Shawn Guo,
	linux-arm-kernel

On Fri, Jan 03, 2014 at 02:24:26PM +0100, Rafael J. Wysocki wrote:
> On Friday, January 03, 2014 12:18:13 PM Russell King - ARM Linux wrote:
> > I'm not sure what I'm looking for.  I've tried looking at the results of
> > searching your linux-next branch for "container" but I don't see
> > anything implementing similar functionality to the patch I've sent.
> > 
> > https://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/log/?h=linux-next&qt=grep&q=container
> 
> I've just set up the acpi-hotplug branch in linux-pm.git (because I often
> rebase the linux-next one).
> 
> The only commit in that branch you need to look at is this one:
> 
> http://git.kernel.org/cgit/linux/kernel/git/rafael/linux-pm.git/commit/?h=acpi-hotplug&id=caa73ea158de9419f08e456f2716c71d1f06012a
> 
> but quite frankly I'm not sure how it is related to your work. :-)

Yes, I'm coming to that conclusion as well.  It looks like your "containers"
aren't about collecting up several individual component devices into one
super-device and probing the appropriate subsystem when all components are
known.

Confused why Greg is pointing me at your patches.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
  2014-01-02 21:27   ` Russell King
@ 2014-01-03 16:05     ` David Herrmann
  -1 siblings, 0 replies; 219+ messages in thread
From: David Herrmann @ 2014-01-03 16:05 UTC (permalink / raw)
  To: linux-arm-kernel

Hi

On Thu, Jan 2, 2014 at 10:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> The encoder possible_crtcs mask identifies which CRTCs can be bound to
> a particular encoder.  Each bit from bit 0 defines an index in the list
> of CRTCs held in the DRM mode_config crtc_list.  Rather than having
> drivers trying to track the position of their CRTCs in the list, expose
> the code which already exists for calculating the appropriate mask bit
> for a CRTC.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
>  include/drm/drm_crtc_helper.h     |    1 +
>  2 files changed, 27 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 01361aba033b..10708c248196 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
>  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>
>  /**
> + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
> + * @crtc: crtc to find mask for
> + *
> + * Given a registered CRTC, return the mask bit of that CRTC for an
> + * encoder's possible_crtcs field.

I think this is a nice cleanup which we could pick up right away. Most
drivers can be simplified by using this. Only the name is misleading,
imo, I'd use something like drm_helper_crtc_to_mask(). Anyhow, not my
call so:

Reviewed-by: David Herrmann <dh.herrmann@gmail.com>

Thanks
David

> + */
> +uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       struct drm_crtc *tmp;
> +       uint32_t crtc_mask = 1;
> +
> +       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
> +               if (tmp == crtc)
> +                       return crtc_mask;
> +               crtc_mask <<= 1;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_helper_crtc_possible_mask);
> +
> +/**
>   * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
>   * @encoder: encoder to test
>   * @crtc: crtc to test
> @@ -334,23 +357,13 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>  static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
>                                 struct drm_crtc *crtc)
>  {
> -       struct drm_device *dev;
> -       struct drm_crtc *tmp;
> -       int crtc_mask = 1;
> +       uint32_t crtc_mask;
>
>         WARN(!crtc, "checking null crtc?\n");
>
> -       dev = crtc->dev;
> -
> -       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
> -               if (tmp == crtc)
> -                       break;
> -               crtc_mask <<= 1;
> -       }
> +       crtc_mask = drm_helper_crtc_possible_mask(crtc);
>
> -       if (encoder->possible_crtcs & crtc_mask)
> -               return true;
> -       return false;
> +       return !!(encoder->possible_crtcs & crtc_mask);
>  }
>
>  /*
> diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
> index ef6ad3a8e58e..21b9f47dd88c 100644
> --- a/include/drm/drm_crtc_helper.h
> +++ b/include/drm/drm_crtc_helper.h
> @@ -127,6 +127,7 @@ struct drm_connector_helper_funcs {
>
>  extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
>  extern void drm_helper_disable_unused_functions(struct drm_device *dev);
> +extern uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc);
>  extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
>  extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>                                      struct drm_display_mode *mode,
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
@ 2014-01-03 16:05     ` David Herrmann
  0 siblings, 0 replies; 219+ messages in thread
From: David Herrmann @ 2014-01-03 16:05 UTC (permalink / raw)
  To: Russell King
  Cc: devel, Greg Kroah-Hartman, dri-devel, Sascha Hauer, linux-arm-kernel

Hi

On Thu, Jan 2, 2014 at 10:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> The encoder possible_crtcs mask identifies which CRTCs can be bound to
> a particular encoder.  Each bit from bit 0 defines an index in the list
> of CRTCs held in the DRM mode_config crtc_list.  Rather than having
> drivers trying to track the position of their CRTCs in the list, expose
> the code which already exists for calculating the appropriate mask bit
> for a CRTC.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
>  include/drm/drm_crtc_helper.h     |    1 +
>  2 files changed, 27 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> index 01361aba033b..10708c248196 100644
> --- a/drivers/gpu/drm/drm_crtc_helper.c
> +++ b/drivers/gpu/drm/drm_crtc_helper.c
> @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
>  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>
>  /**
> + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
> + * @crtc: crtc to find mask for
> + *
> + * Given a registered CRTC, return the mask bit of that CRTC for an
> + * encoder's possible_crtcs field.

I think this is a nice cleanup which we could pick up right away. Most
drivers can be simplified by using this. Only the name is misleading,
imo, I'd use something like drm_helper_crtc_to_mask(). Anyhow, not my
call so:

Reviewed-by: David Herrmann <dh.herrmann@gmail.com>

Thanks
David

> + */
> +uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc)
> +{
> +       struct drm_device *dev = crtc->dev;
> +       struct drm_crtc *tmp;
> +       uint32_t crtc_mask = 1;
> +
> +       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
> +               if (tmp == crtc)
> +                       return crtc_mask;
> +               crtc_mask <<= 1;
> +       }
> +
> +       return 0;
> +}
> +EXPORT_SYMBOL(drm_helper_crtc_possible_mask);
> +
> +/**
>   * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
>   * @encoder: encoder to test
>   * @crtc: crtc to test
> @@ -334,23 +357,13 @@ EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>  static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
>                                 struct drm_crtc *crtc)
>  {
> -       struct drm_device *dev;
> -       struct drm_crtc *tmp;
> -       int crtc_mask = 1;
> +       uint32_t crtc_mask;
>
>         WARN(!crtc, "checking null crtc?\n");
>
> -       dev = crtc->dev;
> -
> -       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
> -               if (tmp == crtc)
> -                       break;
> -               crtc_mask <<= 1;
> -       }
> +       crtc_mask = drm_helper_crtc_possible_mask(crtc);
>
> -       if (encoder->possible_crtcs & crtc_mask)
> -               return true;
> -       return false;
> +       return !!(encoder->possible_crtcs & crtc_mask);
>  }
>
>  /*
> diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
> index ef6ad3a8e58e..21b9f47dd88c 100644
> --- a/include/drm/drm_crtc_helper.h
> +++ b/include/drm/drm_crtc_helper.h
> @@ -127,6 +127,7 @@ struct drm_connector_helper_funcs {
>
>  extern int drm_helper_probe_single_connector_modes(struct drm_connector *connector, uint32_t maxX, uint32_t maxY);
>  extern void drm_helper_disable_unused_functions(struct drm_device *dev);
> +extern uint32_t drm_helper_crtc_possible_mask(struct drm_crtc *crtc);
>  extern int drm_crtc_helper_set_config(struct drm_mode_set *set);
>  extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
>                                      struct drm_display_mode *mode,
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
  2014-01-03 16:05     ` David Herrmann
@ 2014-01-03 16:13       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 16:13 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 05:05:46PM +0100, David Herrmann wrote:
> Hi
> 
> On Thu, Jan 2, 2014 at 10:27 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> > The encoder possible_crtcs mask identifies which CRTCs can be bound to
> > a particular encoder.  Each bit from bit 0 defines an index in the list
> > of CRTCs held in the DRM mode_config crtc_list.  Rather than having
> > drivers trying to track the position of their CRTCs in the list, expose
> > the code which already exists for calculating the appropriate mask bit
> > for a CRTC.
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > ---
> >  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
> >  include/drm/drm_crtc_helper.h     |    1 +
> >  2 files changed, 27 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > index 01361aba033b..10708c248196 100644
> > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
> >  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
> >
> >  /**
> > + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
> > + * @crtc: crtc to find mask for
> > + *
> > + * Given a registered CRTC, return the mask bit of that CRTC for an
> > + * encoder's possible_crtcs field.
> 
> I think this is a nice cleanup which we could pick up right away. Most
> drivers can be simplified by using this. Only the name is misleading,
> imo, I'd use something like drm_helper_crtc_to_mask().

I'm not so sure - since the only place this mask gets used is with
the "possible_crtcs" field.  It's got nothing to do with the
"possible_clones" field as that isn't a mask of CRTCs.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
@ 2014-01-03 16:13       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 16:13 UTC (permalink / raw)
  To: David Herrmann
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 03, 2014 at 05:05:46PM +0100, David Herrmann wrote:
> Hi
> 
> On Thu, Jan 2, 2014 at 10:27 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> > The encoder possible_crtcs mask identifies which CRTCs can be bound to
> > a particular encoder.  Each bit from bit 0 defines an index in the list
> > of CRTCs held in the DRM mode_config crtc_list.  Rather than having
> > drivers trying to track the position of their CRTCs in the list, expose
> > the code which already exists for calculating the appropriate mask bit
> > for a CRTC.
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > ---
> >  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
> >  include/drm/drm_crtc_helper.h     |    1 +
> >  2 files changed, 27 insertions(+), 13 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
> > index 01361aba033b..10708c248196 100644
> > --- a/drivers/gpu/drm/drm_crtc_helper.c
> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
> > @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
> >  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
> >
> >  /**
> > + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
> > + * @crtc: crtc to find mask for
> > + *
> > + * Given a registered CRTC, return the mask bit of that CRTC for an
> > + * encoder's possible_crtcs field.
> 
> I think this is a nice cleanup which we could pick up right away. Most
> drivers can be simplified by using this. Only the name is misleading,
> imo, I'd use something like drm_helper_crtc_to_mask().

I'm not so sure - since the only place this mask gets used is with
the "possible_crtcs" field.  It's got nothing to do with the
"possible_clones" field as that isn't a mask of CRTCs.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
  2014-01-03 16:13       ` Russell King - ARM Linux
@ 2014-01-03 16:26         ` David Herrmann
  -1 siblings, 0 replies; 219+ messages in thread
From: David Herrmann @ 2014-01-03 16:26 UTC (permalink / raw)
  To: linux-arm-kernel

Hi

On Fri, Jan 3, 2014 at 5:13 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Jan 03, 2014 at 05:05:46PM +0100, David Herrmann wrote:
>> Hi
>>
>> On Thu, Jan 2, 2014 at 10:27 PM, Russell King
>> <rmk+kernel@arm.linux.org.uk> wrote:
>> > The encoder possible_crtcs mask identifies which CRTCs can be bound to
>> > a particular encoder.  Each bit from bit 0 defines an index in the list
>> > of CRTCs held in the DRM mode_config crtc_list.  Rather than having
>> > drivers trying to track the position of their CRTCs in the list, expose
>> > the code which already exists for calculating the appropriate mask bit
>> > for a CRTC.
>> >
>> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>> > ---
>> >  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
>> >  include/drm/drm_crtc_helper.h     |    1 +
>> >  2 files changed, 27 insertions(+), 13 deletions(-)
>> >
>> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
>> > index 01361aba033b..10708c248196 100644
>> > --- a/drivers/gpu/drm/drm_crtc_helper.c
>> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
>> > @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
>> >  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>> >
>> >  /**
>> > + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
>> > + * @crtc: crtc to find mask for
>> > + *
>> > + * Given a registered CRTC, return the mask bit of that CRTC for an
>> > + * encoder's possible_crtcs field.
>>
>> I think this is a nice cleanup which we could pick up right away. Most
>> drivers can be simplified by using this. Only the name is misleading,
>> imo, I'd use something like drm_helper_crtc_to_mask().
>
> I'm not so sure - since the only place this mask gets used is with
> the "possible_crtcs" field.  It's got nothing to do with the
> "possible_clones" field as that isn't a mask of CRTCs.

At least intel's copy of intel_crtc_encoder_ok() can be updated, too.
But they don't depend on the crtc_helpers so we'd have to move your
small helper into drm_crtc.c (which is fine to me as it is not limited
to the DRM-crtc-helpers).

possible_clones is about encoders, you're right, I missed that. So you
can carry it in your series just fine.

Thanks
David

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

* Re: [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
@ 2014-01-03 16:26         ` David Herrmann
  0 siblings, 0 replies; 219+ messages in thread
From: David Herrmann @ 2014-01-03 16:26 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Hi

On Fri, Jan 3, 2014 at 5:13 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Fri, Jan 03, 2014 at 05:05:46PM +0100, David Herrmann wrote:
>> Hi
>>
>> On Thu, Jan 2, 2014 at 10:27 PM, Russell King
>> <rmk+kernel@arm.linux.org.uk> wrote:
>> > The encoder possible_crtcs mask identifies which CRTCs can be bound to
>> > a particular encoder.  Each bit from bit 0 defines an index in the list
>> > of CRTCs held in the DRM mode_config crtc_list.  Rather than having
>> > drivers trying to track the position of their CRTCs in the list, expose
>> > the code which already exists for calculating the appropriate mask bit
>> > for a CRTC.
>> >
>> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
>> > ---
>> >  drivers/gpu/drm/drm_crtc_helper.c |   39 ++++++++++++++++++++++++------------
>> >  include/drm/drm_crtc_helper.h     |    1 +
>> >  2 files changed, 27 insertions(+), 13 deletions(-)
>> >
>> > diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
>> > index 01361aba033b..10708c248196 100644
>> > --- a/drivers/gpu/drm/drm_crtc_helper.c
>> > +++ b/drivers/gpu/drm/drm_crtc_helper.c
>> > @@ -325,6 +325,29 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
>> >  EXPORT_SYMBOL(drm_helper_disable_unused_functions);
>> >
>> >  /**
>> > + * drm_helper_crtc_possible_mask - find the mask of a registered CRTC
>> > + * @crtc: crtc to find mask for
>> > + *
>> > + * Given a registered CRTC, return the mask bit of that CRTC for an
>> > + * encoder's possible_crtcs field.
>>
>> I think this is a nice cleanup which we could pick up right away. Most
>> drivers can be simplified by using this. Only the name is misleading,
>> imo, I'd use something like drm_helper_crtc_to_mask().
>
> I'm not so sure - since the only place this mask gets used is with
> the "possible_crtcs" field.  It's got nothing to do with the
> "possible_clones" field as that isn't a mask of CRTCs.

At least intel's copy of intel_crtc_encoder_ok() can be updated, too.
But they don't depend on the crtc_helpers so we'd have to move your
small helper into drm_crtc.c (which is fine to me as it is not limited
to the DRM-crtc-helpers).

possible_clones is about encoders, you're right, I missed that. So you
can carry it in your series just fine.

Thanks
David

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

* [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
  2014-01-03 16:26         ` David Herrmann
@ 2014-01-03 16:29           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 16:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 05:26:14PM +0100, David Herrmann wrote:
> Hi
> 
> On Fri, Jan 3, 2014 at 5:13 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > I'm not so sure - since the only place this mask gets used is with
> > the "possible_crtcs" field.  It's got nothing to do with the
> > "possible_clones" field as that isn't a mask of CRTCs.
> 
...
> possible_clones is about encoders, you're right, I missed that. So you
> can carry it in your series just fine.

Thanks for confirming that - it's something which imx-drm seemed to get
wrong as put the same value into possible_clones as it did for
possible_crtcs.  I was fairly certain that was buggy. :)

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask
@ 2014-01-03 16:29           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 16:29 UTC (permalink / raw)
  To: David Herrmann
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 03, 2014 at 05:26:14PM +0100, David Herrmann wrote:
> Hi
> 
> On Fri, Jan 3, 2014 at 5:13 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > I'm not so sure - since the only place this mask gets used is with
> > the "possible_crtcs" field.  It's got nothing to do with the
> > "possible_clones" field as that isn't a mask of CRTCs.
> 
...
> possible_clones is about encoders, you're right, I missed that. So you
> can carry it in your series just fine.

Thanks for confirming that - it's something which imx-drm seemed to get
wrong as put the same value into possible_clones as it did for
possible_crtcs.  I was fairly certain that was buggy. :)

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-02 21:28   ` Russell King
@ 2014-01-03 16:48     ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-03 16:48 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
the HPD signal doesn't seem to work, but after overwriting the
connection check, I got a stable and correct picture on the monitor:

 arch/arm/boot/dts/imx6q-sabrelite.dts | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index f004913..cf9b3f5 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -50,6 +50,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+		connectors = <&hdmi>;
+	};
+
 	sound {
 		compatible = "fsl,imx6q-sabrelite-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
@@ -93,6 +99,12 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	ddc = <&i2c2>;
+	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
+
 &i2c1 {
 	status = "okay";
 	clock-frequency = <100000>;
@@ -108,6 +120,13 @@
 	};
 };
 
+&i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2_2>;
+};
+
 &iomuxc {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_hog>;
-- 
1.8.5.1

Am Donnerstag, den 02.01.2014, 21:28 +0000 schrieb Russell King:
> Use the componentised device support for imx-drm.  This requires all
> the sub-components and the master device to register with the component
> device support.
> 
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  arch/arm/boot/dts/imx51-babbage.dts        |   10 ++-
>  arch/arm/boot/dts/imx53-m53evk.dts         |    8 ++-
>  arch/arm/boot/dts/imx53-mba53.dts          |    6 ++
>  arch/arm/boot/dts/imx53-qsb.dts            |    8 ++-
>  arch/arm/boot/dts/imx6qdl-sabresd.dtsi     |    6 ++
>  drivers/staging/imx-drm/imx-drm-core.c     |  105 ++++++++++++++++++++++-----
>  drivers/staging/imx-drm/imx-ldb.c          |   40 ++++++++---
>  drivers/staging/imx-drm/imx-tve.c          |   63 +++++++++++------
>  drivers/staging/imx-drm/ipuv3-crtc.c       |   46 +++++++++----
>  drivers/staging/imx-drm/parallel-display.c |   30 ++++++--
>  10 files changed, 242 insertions(+), 80 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
> index be1407cf5abd..6ff15a0eacb3 100644
> --- a/arch/arm/boot/dts/imx51-babbage.dts
> +++ b/arch/arm/boot/dts/imx51-babbage.dts
> @@ -21,7 +21,7 @@
>  		reg = <0x90000000 0x20000000>;
>  	};
>  
> -	display at di0 {
> +	display0: display at di0 {
>  		compatible = "fsl,imx-parallel-display";
>  		crtcs = <&ipu 0>;
[...]

Before moving imx-drm out of staging, I'd like to get rid of the
unfortunate 'crtcs' property. I'd rather prefer the components to be
connected with a device tree graph. I'm not quite sure if the DI0/1
should have their own device tree node inside the IPU node or if they
should just appear directly as two of four ports of the IPU (the other
two being CSI0/1). In the latter case, for example:

 arch/arm/boot/dts/imx6q.dtsi           | 32 ++++++++++++++++++++++++++++++--
 arch/arm/boot/dts/imx6qdl.dtsi         | 33 ++++++++++++++++++++++++++++++++-
 drivers/staging/imx-drm/imx-drm-core.c | 44 ++++++++++++++++++++++++++++++++------------
 3 files changed, 94 insertions(+), 15 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 187fe33..93f4721 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,30 @@
 		};
 
 		ipu2: ipu at 02800000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02800000 0x400000>;
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 4>;
+
+			port at 2 {
+				reg = <2>;
+
+				ipu2_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_2>;
+				};
+			};
+
+			port at 3 {
+				reg = <3>;
+
+				ipu2_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_3>;
+				};
+			};
 		};
 	};
 };
@@ -162,5 +179,16 @@
 
 &hdmi {
 	compatible = "fsl,imx6q-hdmi";
-	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+
+	port at 2 {
+		hdmi_mux_2: endpoint {
+			remote-endpoint = <&ipu2_di0_hdmi>;
+		};
+	};
+
+	port at 3 {
+		hdmi_mux_3: endpoint {
+			remote-endpoint = <&ipu2_di1_hdmi>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 930ebe0..d9cb9a3 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,12 +1369,26 @@
 			};
 
 			hdmi: hdmi at 0120000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
 				clocks = <&clks 123>, <&clks 124>;
 				clock-names = "iahb", "isfr";
 				status = "disabled";
+
+				port at 0 {
+					hdmi_mux_0: endpoint {
+						remote-endpoint = <&ipu1_di0_hdmi>;
+					};
+				};
+
+				port at 1 {
+					hdmi_mux_1: endpoint {
+						remote-endpoint = <&ipu1_di1_hdmi>;
+					};
+				};
 			};
 
 			dcic1: dcic at 020e4000 {
@@ -1643,13 +1657,30 @@
 		};
 
 		ipu1: ipu at 02400000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02400000 0x400000>;
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 2>;
+
+			port at 2 {
+				reg = <2>;
+
+				ipu1_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_0>;
+				};
+			};
+
+			port at 3 {
+				reg = <3>;
+
+				ipu1_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_1>;
+				};
+			};
 		};
 	};
 };
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 2490dc3..2c20434 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -23,6 +23,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <media/v4l2-of.h>
 
 #include "imx-drm.h"
 
@@ -420,9 +421,23 @@ EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
  * or removed once the DRM device has been fully initialised.
  */
 static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
-	void *cookie, int id)
+	struct device_node *endpoint)
 {
+	struct device_node *remote_port;
+	void *cookie;
 	unsigned i;
+	int id = 0;
+
+	remote_port = v4l2_of_get_remote_port(endpoint);
+	if (remote_port)
+		of_property_read_u32(remote_port, "reg", &id);
+	else
+		return 0;
+	cookie = remote_port->parent;
+	of_node_put(remote_port);
+
+	/* IPU specific: CSI0/1 at 0/1, DI0/1 at 2/3 */
+	id -= 2;
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
@@ -438,24 +453,21 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
+	struct device_node *ep, *last_ep = NULL;
 	uint32_t crtc_mask = 0;
 	int i, ret = 0;
 
 	for (i = 0; !ret; i++) {
-		struct of_phandle_args args;
 		uint32_t mask;
-		int id;
 
-		ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
-						 &args);
-		if (ret == -ENOENT)
+		ep = v4l2_of_get_next_endpoint(np, last_ep);
+		if (last_ep)
+			of_node_put(last_ep);
+		if (!ep)
 			break;
-		if (ret < 0)
-			return ret;
 
-		id = args.args_count > 0 ? args.args[0] : 0;
-		mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
-		of_node_put(args.np);
+		/* CSI */
+		mask = imx_drm_find_crtc_mask(imxdrm, ep);
 
 		/*
 		 * If we failed to find the CRTC(s) which this encoder is
@@ -463,12 +475,20 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 		 * not been registered yet.  Defer probing, and hope that
 		 * the required CRTC is added later.
 		 */
-		if (mask == 0)
+		if (mask == 0) {
+			of_node_put(ep);
 			return -EPROBE_DEFER;
+		}
 
 		crtc_mask |= mask;
+		last_ep = ep;
 	}
 
+	if (ep)
+		of_node_put(ep);
+	if (i == 0)
+		return -ENOENT;
+
 	encoder->possible_crtcs = crtc_mask;
 
 	/* FIXME: this is the mask of outputs which can clone this output. */
-- 
1.8.5.1

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 187fe33..93f4721 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,30 @@
 		};
 
 		ipu2: ipu at 02800000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02800000 0x400000>;
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 4>;
+
+			port at 2 {
+				reg = <2>;
+
+				ipu2_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_2>;
+				};
+			};
+
+			port at 3 {
+				reg = <3>;
+
+				ipu2_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_3>;
+				};
+			};
 		};
 	};
 };
@@ -162,5 +179,16 @@
 
 &hdmi {
 	compatible = "fsl,imx6q-hdmi";
-	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+
+	port at 2 {
+		hdmi_mux_2: endpoint {
+			remote-endpoint = <&ipu2_di0_hdmi>;
+		};
+	};
+
+	port at 3 {
+		hdmi_mux_3: endpoint {
+			remote-endpoint = <&ipu2_di1_hdmi>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 930ebe0..d9cb9a3 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,12 +1369,26 @@
 			};
 
 			hdmi: hdmi at 0120000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
 				clocks = <&clks 123>, <&clks 124>;
 				clock-names = "iahb", "isfr";
 				status = "disabled";
+
+				port at 0 {
+					hdmi_mux_0: endpoint {
+						remote-endpoint = <&ipu1_di0_hdmi>;
+					};
+				};
+
+				port at 1 {
+					hdmi_mux_1: endpoint {
+						remote-endpoint = <&ipu1_di1_hdmi>;
+					};
+				};
 			};
 
 			dcic1: dcic at 020e4000 {
@@ -1643,13 +1657,30 @@
 		};
 
 		ipu1: ipu at 02400000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02400000 0x400000>;
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 2>;
+
+			port at 2 {
+				reg = <2>;
+
+				ipu1_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_0>;
+				};
+			};
+
+			port at 3 {
+				reg = <3>;
+
+				ipu1_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_1>;
+				};
+			};
 		};
 	};
 };

The IPU ports 0 and 1 would be reserved for a future patch that adds CSI
support. This would allow to connect all input and output components in
the device tree to the IPU using a single abstraction and stop leaking
linux specific terms into the device tree.

regards
Philipp

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-03 16:48     ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-03 16:48 UTC (permalink / raw)
  To: Russell King
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Hi Russell,

I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
the HPD signal doesn't seem to work, but after overwriting the
connection check, I got a stable and correct picture on the monitor:

 arch/arm/boot/dts/imx6q-sabrelite.dts | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index f004913..cf9b3f5 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -50,6 +50,12 @@
 		};
 	};
 
+	imx-drm {
+		compatible = "fsl,imx-drm";
+		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+		connectors = <&hdmi>;
+	};
+
 	sound {
 		compatible = "fsl,imx6q-sabrelite-sgtl5000",
 			     "fsl,imx-audio-sgtl5000";
@@ -93,6 +99,12 @@
 	status = "okay";
 };
 
+&hdmi {
+	status = "okay";
+	ddc = <&i2c2>;
+	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
+
 &i2c1 {
 	status = "okay";
 	clock-frequency = <100000>;
@@ -108,6 +120,13 @@
 	};
 };
 
+&i2c2 {
+	status = "okay";
+	clock-frequency = <100000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_i2c2_2>;
+};
+
 &iomuxc {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_hog>;
-- 
1.8.5.1

Am Donnerstag, den 02.01.2014, 21:28 +0000 schrieb Russell King:
> Use the componentised device support for imx-drm.  This requires all
> the sub-components and the master device to register with the component
> device support.
> 
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  arch/arm/boot/dts/imx51-babbage.dts        |   10 ++-
>  arch/arm/boot/dts/imx53-m53evk.dts         |    8 ++-
>  arch/arm/boot/dts/imx53-mba53.dts          |    6 ++
>  arch/arm/boot/dts/imx53-qsb.dts            |    8 ++-
>  arch/arm/boot/dts/imx6qdl-sabresd.dtsi     |    6 ++
>  drivers/staging/imx-drm/imx-drm-core.c     |  105 ++++++++++++++++++++++-----
>  drivers/staging/imx-drm/imx-ldb.c          |   40 ++++++++---
>  drivers/staging/imx-drm/imx-tve.c          |   63 +++++++++++------
>  drivers/staging/imx-drm/ipuv3-crtc.c       |   46 +++++++++----
>  drivers/staging/imx-drm/parallel-display.c |   30 ++++++--
>  10 files changed, 242 insertions(+), 80 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
> index be1407cf5abd..6ff15a0eacb3 100644
> --- a/arch/arm/boot/dts/imx51-babbage.dts
> +++ b/arch/arm/boot/dts/imx51-babbage.dts
> @@ -21,7 +21,7 @@
>  		reg = <0x90000000 0x20000000>;
>  	};
>  
> -	display@di0 {
> +	display0: display@di0 {
>  		compatible = "fsl,imx-parallel-display";
>  		crtcs = <&ipu 0>;
[...]

Before moving imx-drm out of staging, I'd like to get rid of the
unfortunate 'crtcs' property. I'd rather prefer the components to be
connected with a device tree graph. I'm not quite sure if the DI0/1
should have their own device tree node inside the IPU node or if they
should just appear directly as two of four ports of the IPU (the other
two being CSI0/1). In the latter case, for example:

 arch/arm/boot/dts/imx6q.dtsi           | 32 ++++++++++++++++++++++++++++++--
 arch/arm/boot/dts/imx6qdl.dtsi         | 33 ++++++++++++++++++++++++++++++++-
 drivers/staging/imx-drm/imx-drm-core.c | 44 ++++++++++++++++++++++++++++++++------------
 3 files changed, 94 insertions(+), 15 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 187fe33..93f4721 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,30 @@
 		};
 
 		ipu2: ipu@02800000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02800000 0x400000>;
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 4>;
+
+			port@2 {
+				reg = <2>;
+
+				ipu2_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_2>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+
+				ipu2_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_3>;
+				};
+			};
 		};
 	};
 };
@@ -162,5 +179,16 @@
 
 &hdmi {
 	compatible = "fsl,imx6q-hdmi";
-	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+
+	port@2 {
+		hdmi_mux_2: endpoint {
+			remote-endpoint = <&ipu2_di0_hdmi>;
+		};
+	};
+
+	port@3 {
+		hdmi_mux_3: endpoint {
+			remote-endpoint = <&ipu2_di1_hdmi>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 930ebe0..d9cb9a3 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,12 +1369,26 @@
 			};
 
 			hdmi: hdmi@0120000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
 				clocks = <&clks 123>, <&clks 124>;
 				clock-names = "iahb", "isfr";
 				status = "disabled";
+
+				port@0 {
+					hdmi_mux_0: endpoint {
+						remote-endpoint = <&ipu1_di0_hdmi>;
+					};
+				};
+
+				port@1 {
+					hdmi_mux_1: endpoint {
+						remote-endpoint = <&ipu1_di1_hdmi>;
+					};
+				};
 			};
 
 			dcic1: dcic@020e4000 {
@@ -1643,13 +1657,30 @@
 		};
 
 		ipu1: ipu@02400000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02400000 0x400000>;
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 2>;
+
+			port@2 {
+				reg = <2>;
+
+				ipu1_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_0>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+
+				ipu1_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_1>;
+				};
+			};
 		};
 	};
 };
diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
index 2490dc3..2c20434 100644
--- a/drivers/staging/imx-drm/imx-drm-core.c
+++ b/drivers/staging/imx-drm/imx-drm-core.c
@@ -23,6 +23,7 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <media/v4l2-of.h>
 
 #include "imx-drm.h"
 
@@ -420,9 +421,23 @@ EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
  * or removed once the DRM device has been fully initialised.
  */
 static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
-	void *cookie, int id)
+	struct device_node *endpoint)
 {
+	struct device_node *remote_port;
+	void *cookie;
 	unsigned i;
+	int id = 0;
+
+	remote_port = v4l2_of_get_remote_port(endpoint);
+	if (remote_port)
+		of_property_read_u32(remote_port, "reg", &id);
+	else
+		return 0;
+	cookie = remote_port->parent;
+	of_node_put(remote_port);
+
+	/* IPU specific: CSI0/1 at 0/1, DI0/1 at 2/3 */
+	id -= 2;
 
 	for (i = 0; i < MAX_CRTC; i++) {
 		struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
@@ -438,24 +453,21 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 	struct drm_encoder *encoder, struct device_node *np)
 {
 	struct imx_drm_device *imxdrm = drm->dev_private;
+	struct device_node *ep, *last_ep = NULL;
 	uint32_t crtc_mask = 0;
 	int i, ret = 0;
 
 	for (i = 0; !ret; i++) {
-		struct of_phandle_args args;
 		uint32_t mask;
-		int id;
 
-		ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
-						 &args);
-		if (ret == -ENOENT)
+		ep = v4l2_of_get_next_endpoint(np, last_ep);
+		if (last_ep)
+			of_node_put(last_ep);
+		if (!ep)
 			break;
-		if (ret < 0)
-			return ret;
 
-		id = args.args_count > 0 ? args.args[0] : 0;
-		mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
-		of_node_put(args.np);
+		/* CSI */
+		mask = imx_drm_find_crtc_mask(imxdrm, ep);
 
 		/*
 		 * If we failed to find the CRTC(s) which this encoder is
@@ -463,12 +475,20 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
 		 * not been registered yet.  Defer probing, and hope that
 		 * the required CRTC is added later.
 		 */
-		if (mask == 0)
+		if (mask == 0) {
+			of_node_put(ep);
 			return -EPROBE_DEFER;
+		}
 
 		crtc_mask |= mask;
+		last_ep = ep;
 	}
 
+	if (ep)
+		of_node_put(ep);
+	if (i == 0)
+		return -ENOENT;
+
 	encoder->possible_crtcs = crtc_mask;
 
 	/* FIXME: this is the mask of outputs which can clone this output. */
-- 
1.8.5.1

diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 187fe33..93f4721 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -132,13 +132,30 @@
 		};
 
 		ipu2: ipu@02800000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02800000 0x400000>;
 			interrupts = <0 8 0x4 0 7 0x4>;
 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 4>;
+
+			port@2 {
+				reg = <2>;
+
+				ipu2_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_2>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+
+				ipu2_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_3>;
+				};
+			};
 		};
 	};
 };
@@ -162,5 +179,16 @@
 
 &hdmi {
 	compatible = "fsl,imx6q-hdmi";
-	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+
+	port@2 {
+		hdmi_mux_2: endpoint {
+			remote-endpoint = <&ipu2_di0_hdmi>;
+		};
+	};
+
+	port@3 {
+		hdmi_mux_3: endpoint {
+			remote-endpoint = <&ipu2_di1_hdmi>;
+		};
+	};
 };
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 930ebe0..d9cb9a3 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -1369,12 +1369,26 @@
 			};
 
 			hdmi: hdmi@0120000 {
+				#address-cells = <1>;
+				#size-cells = <0>;
 				reg = <0x00120000 0x9000>;
 				interrupts = <0 115 0x04>;
 				gpr = <&gpr>;
 				clocks = <&clks 123>, <&clks 124>;
 				clock-names = "iahb", "isfr";
 				status = "disabled";
+
+				port@0 {
+					hdmi_mux_0: endpoint {
+						remote-endpoint = <&ipu1_di0_hdmi>;
+					};
+				};
+
+				port@1 {
+					hdmi_mux_1: endpoint {
+						remote-endpoint = <&ipu1_di1_hdmi>;
+					};
+				};
 			};
 
 			dcic1: dcic@020e4000 {
@@ -1643,13 +1657,30 @@
 		};
 
 		ipu1: ipu@02400000 {
-			#crtc-cells = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
 			compatible = "fsl,imx6q-ipu";
 			reg = <0x02400000 0x400000>;
 			interrupts = <0 6 0x4 0 5 0x4>;
 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
 			clock-names = "bus", "di0", "di1";
 			resets = <&src 2>;
+
+			port@2 {
+				reg = <2>;
+
+				ipu1_di0_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_0>;
+				};
+			};
+
+			port@3 {
+				reg = <3>;
+
+				ipu1_di1_hdmi: endpoint {
+					remote-endpoint = <&hdmi_mux_1>;
+				};
+			};
 		};
 	};
 };

The IPU ports 0 and 1 would be reserved for a future patch that adds CSI
support. This would allow to connect all input and output components in
the device tree to the IPU using a single abstraction and stop leaking
linux specific terms into the device tree.

regards
Philipp

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-03 16:48     ` Philipp Zabel
@ 2014-01-03 17:07       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> Hi Russell,
> 
> I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> the HPD signal doesn't seem to work, but after overwriting the
> connection check, I got a stable and correct picture on the monitor:

Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
when you plug and unplug the monitor?

147:        281       GIC 147  120000.hdmi

on turning the TV on:

147:        282       GIC 147  120000.hdmi

on unplugging the HDMI cable:

147:        283       GIC 147  120000.hdmi

on replugging the HDMI cable:

147:        284       GIC 147  120000.hdmi


-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-03 17:07       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 17:07 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> Hi Russell,
> 
> I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> the HPD signal doesn't seem to work, but after overwriting the
> connection check, I got a stable and correct picture on the monitor:

Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
when you plug and unplug the monitor?

147:        281       GIC 147  120000.hdmi

on turning the TV on:

147:        282       GIC 147  120000.hdmi

on unplugging the HDMI cable:

147:        283       GIC 147  120000.hdmi

on replugging the HDMI cable:

147:        284       GIC 147  120000.hdmi


-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-03 17:07       ` Russell King - ARM Linux
@ 2014-01-03 17:26         ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-03 17:26 UTC (permalink / raw)
  To: linux-arm-kernel

Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
Linux:
> On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> > Hi Russell,
> > 
> > I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> > the HPD signal doesn't seem to work, but after overwriting the
> > connection check, I got a stable and correct picture on the monitor:
> 
> Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
> when you plug and unplug the monitor?
> 
> 147:        281       GIC 147  120000.hdmi
> 
> on turning the TV on:
> 
> 147:        282       GIC 147  120000.hdmi
> 
> on unplugging the HDMI cable:
> 
> 147:        283       GIC 147  120000.hdmi
> 
> on replugging the HDMI cable:
> 
> 147:        284       GIC 147  120000.hdmi

Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
(un)plug, the HPD bit stays zero. I'll check with other hardware.

regards
Philipp

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-03 17:26         ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-03 17:26 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
Linux:
> On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> > Hi Russell,
> > 
> > I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> > the HPD signal doesn't seem to work, but after overwriting the
> > connection check, I got a stable and correct picture on the monitor:
> 
> Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
> when you plug and unplug the monitor?
> 
> 147:        281       GIC 147  120000.hdmi
> 
> on turning the TV on:
> 
> 147:        282       GIC 147  120000.hdmi
> 
> on unplugging the HDMI cable:
> 
> 147:        283       GIC 147  120000.hdmi
> 
> on replugging the HDMI cable:
> 
> 147:        284       GIC 147  120000.hdmi

Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
(un)plug, the HPD bit stays zero. I'll check with other hardware.

regards
Philipp

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-03 17:26         ` Philipp Zabel
@ 2014-01-03 17:38           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 17:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 03, 2014 at 06:26:44PM +0100, Philipp Zabel wrote:
> Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
> Linux:
> > On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> > > Hi Russell,
> > > 
> > > I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> > > the HPD signal doesn't seem to work, but after overwriting the
> > > connection check, I got a stable and correct picture on the monitor:
> > 
> > Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
> > when you plug and unplug the monitor?
> > 
> > 147:        281       GIC 147  120000.hdmi
> > 
> > on turning the TV on:
> > 
> > 147:        282       GIC 147  120000.hdmi
> > 
> > on unplugging the HDMI cable:
> > 
> > 147:        283       GIC 147  120000.hdmi
> > 
> > on replugging the HDMI cable:
> > 
> > 147:        284       GIC 147  120000.hdmi
> 
> Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
> (un)plug, the HPD bit stays zero. I'll check with other hardware.

My guess would be that someone forgot to wire up the HPD line
correctly.  As ever, the documentation doesn't describe how this
stuff works...

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-03 17:38           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-03 17:38 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 03, 2014 at 06:26:44PM +0100, Philipp Zabel wrote:
> Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
> Linux:
> > On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
> > > Hi Russell,
> > > 
> > > I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
> > > the HPD signal doesn't seem to work, but after overwriting the
> > > connection check, I got a stable and correct picture on the monitor:
> > 
> > Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
> > when you plug and unplug the monitor?
> > 
> > 147:        281       GIC 147  120000.hdmi
> > 
> > on turning the TV on:
> > 
> > 147:        282       GIC 147  120000.hdmi
> > 
> > on unplugging the HDMI cable:
> > 
> > 147:        283       GIC 147  120000.hdmi
> > 
> > on replugging the HDMI cable:
> > 
> > 147:        284       GIC 147  120000.hdmi
> 
> Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
> (un)plug, the HPD bit stays zero. I'll check with other hardware.

My guess would be that someone forgot to wire up the HPD line
correctly.  As ever, the documentation doesn't describe how this
stuff works...

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-03 17:26         ` Philipp Zabel
@ 2014-01-03 19:14           ` Eric Nelson
  -1 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-03 19:14 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Philipp,

On 01/03/2014 10:26 AM, Philipp Zabel wrote:
> Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
> Linux:
>> On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
>>> Hi Russell,
>>>
>>> I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
>>> the HPD signal doesn't seem to work, but after overwriting the
>>> connection check, I got a stable and correct picture on the monitor:
>>
>> Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
>> when you plug and unplug the monitor?
>>
>> 147:        281       GIC 147  120000.hdmi
>>
>> on turning the TV on:
>>
>> 147:        282       GIC 147  120000.hdmi
>>
>> on unplugging the HDMI cable:
>>
>> 147:        283       GIC 147  120000.hdmi
>>
>> on replugging the HDMI cable:
>>
>> 147:        284       GIC 147  120000.hdmi
>
> Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
> (un)plug, the HPD bit stays zero. I'll check with other hardware.
>

This is an issue we've seen before. The SABRE Lite board has
a voltage divider on the HPD pins and some monitors (esp. DVI
monitors) either don't drive things high enough to assert HPD or
bounce with connect/disconnect.

We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
instead.

Regards,


Eric

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-03 19:14           ` Eric Nelson
  0 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-03 19:14 UTC (permalink / raw)
  To: Philipp Zabel, Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Hi Philipp,

On 01/03/2014 10:26 AM, Philipp Zabel wrote:
> Am Freitag, den 03.01.2014, 17:07 +0000 schrieb Russell King - ARM
> Linux:
>> On Fri, Jan 03, 2014 at 05:48:57PM +0100, Philipp Zabel wrote:
>>> Hi Russell,
>>>
>>> I've tested this series on a BD-SL (SabreLite) with HDMI. Right now
>>> the HPD signal doesn't seem to work, but after overwriting the
>>> connection check, I got a stable and correct picture on the monitor:
>>
>> Hmm.  Does this mean you're not getting any IRQs from the HDMI interface
>> when you plug and unplug the monitor?
>>
>> 147:        281       GIC 147  120000.hdmi
>>
>> on turning the TV on:
>>
>> 147:        282       GIC 147  120000.hdmi
>>
>> on unplugging the HDMI cable:
>>
>> 147:        283       GIC 147  120000.hdmi
>>
>> on replugging the HDMI cable:
>>
>> 147:        284       GIC 147  120000.hdmi
>
> Exactly. And while the RX_SENSE bits of HDMI_IH_PHY_STAT0 change when I
> (un)plug, the HPD bit stays zero. I'll check with other hardware.
>

This is an issue we've seen before. The SABRE Lite board has
a voltage divider on the HPD pins and some monitors (esp. DVI
monitors) either don't drive things high enough to assert HPD or
bounce with connect/disconnect.

We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
instead.

Regards,


Eric

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-03 19:14           ` Eric Nelson
@ 2014-01-06 17:41             ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-06 17:41 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Eric,

Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> This is an issue we've seen before. The SABRE Lite board has
> a voltage divider on the HPD pins and some monitors (esp. DVI
> monitors) either don't drive things high enough to assert HPD or
> bounce with connect/disconnect.

Yes, I used a DVI monitor.

> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> instead.

Reacting to RX_SENSE0 instead of HPD seems to work.

thanks
Philipp

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-06 17:41             ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-06 17:41 UTC (permalink / raw)
  To: Eric Nelson
  Cc: devel, Russell King - ARM Linux, David Airlie,
	Greg Kroah-Hartman, dri-devel, Sascha Hauer, Shawn Guo,
	linux-arm-kernel

Hi Eric,

Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> This is an issue we've seen before. The SABRE Lite board has
> a voltage divider on the HPD pins and some monitors (esp. DVI
> monitors) either don't drive things high enough to assert HPD or
> bounce with connect/disconnect.

Yes, I used a DVI monitor.

> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> instead.

Reacting to RX_SENSE0 instead of HPD seems to work.

thanks
Philipp

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-06 17:41             ` Philipp Zabel
@ 2014-01-06 17:46               ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-06 17:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> Hi Eric,
> 
> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> > This is an issue we've seen before. The SABRE Lite board has
> > a voltage divider on the HPD pins and some monitors (esp. DVI
> > monitors) either don't drive things high enough to assert HPD or
> > bounce with connect/disconnect.
> 
> Yes, I used a DVI monitor.
> 
> > We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> > instead.
> 
> Reacting to RX_SENSE0 instead of HPD seems to work.

However, it's non-compliant, because HPD can be lowered and raised by
the sink when it changes its EDID data (eg, because you're connected
through a switch and the routing has been changed.)

So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
only for those boards which are broken in this regard.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-06 17:46               ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-06 17:46 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, David Airlie, Greg Kroah-Hartman, Eric Nelson, dri-devel,
	Sascha Hauer, Shawn Guo, linux-arm-kernel

On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> Hi Eric,
> 
> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> > This is an issue we've seen before. The SABRE Lite board has
> > a voltage divider on the HPD pins and some monitors (esp. DVI
> > monitors) either don't drive things high enough to assert HPD or
> > bounce with connect/disconnect.
> 
> Yes, I used a DVI monitor.
> 
> > We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> > instead.
> 
> Reacting to RX_SENSE0 instead of HPD seems to work.

However, it's non-compliant, because HPD can be lowered and raised by
the sink when it changes its EDID data (eg, because you're connected
through a switch and the routing has been changed.)

So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
only for those boards which are broken in this regard.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-06 17:46               ` Russell King - ARM Linux
@ 2014-01-07  2:31                 ` Eric Nelson
  -1 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-07  2:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
>> Hi Eric,
>>
>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
>>> This is an issue we've seen before. The SABRE Lite board has
>>> a voltage divider on the HPD pins and some monitors (esp. DVI
>>> monitors) either don't drive things high enough to assert HPD or
>>> bounce with connect/disconnect.
>>
>> Yes, I used a DVI monitor.
>>
>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
>>> instead.
>>
>> Reacting to RX_SENSE0 instead of HPD seems to work.
>
> However, it's non-compliant, because HPD can be lowered and raised by
> the sink when it changes its EDID data (eg, because you're connected
> through a switch and the routing has been changed.)
>
> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> only for those boards which are broken in this regard.
>

I understand. We'll need to carry some patches for a while though,
since there are lots of these boards in the wild.

Regards,


Eric

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-07  2:31                 ` Eric Nelson
  0 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-07  2:31 UTC (permalink / raw)
  To: Russell King - ARM Linux, Philipp Zabel
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Hi Russell,

On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
>> Hi Eric,
>>
>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
>>> This is an issue we've seen before. The SABRE Lite board has
>>> a voltage divider on the HPD pins and some monitors (esp. DVI
>>> monitors) either don't drive things high enough to assert HPD or
>>> bounce with connect/disconnect.
>>
>> Yes, I used a DVI monitor.
>>
>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
>>> instead.
>>
>> Reacting to RX_SENSE0 instead of HPD seems to work.
>
> However, it's non-compliant, because HPD can be lowered and raised by
> the sink when it changes its EDID data (eg, because you're connected
> through a switch and the routing has been changed.)
>
> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> only for those boards which are broken in this regard.
>

I understand. We'll need to carry some patches for a while though,
since there are lots of these boards in the wild.

Regards,


Eric

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

* [PATCH RFC 00/46] Preview of imx-drm cleanup series
  2014-01-02 21:25 ` Russell King - ARM Linux
@ 2014-01-07  6:33   ` Shawn Guo
  -1 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 09:25:28PM +0000, Russell King - ARM Linux wrote:
> Here is my large patch series which cleans up imx-drm, and gets it ready
> to move out of drivers/staging.  This is a preview only.

When moving to non-RFC patches, you may want to run checkpatch.pl on the
patches.  There are some errors and warnings than just "line over 80
characters" one.

Shawn

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

* Re: [PATCH RFC 00/46] Preview of imx-drm cleanup series
@ 2014-01-07  6:33   ` Shawn Guo
  0 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:33 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Thu, Jan 02, 2014 at 09:25:28PM +0000, Russell King - ARM Linux wrote:
> Here is my large patch series which cleans up imx-drm, and gets it ready
> to move out of drivers/staging.  This is a preview only.

When moving to non-RFC patches, you may want to run checkpatch.pl on the
patches.  There are some errors and warnings than just "line over 80
characters" one.

Shawn

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

* [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
  2014-01-02 21:27   ` Russell King
@ 2014-01-07  6:38     ` Shawn Guo
  -1 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:38 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 09:27:48PM +0000, Russell King wrote:
> diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
> index 5649f180dc44..4eb594ce9cff 100644
> --- a/drivers/staging/imx-drm/imx-drm.h
> +++ b/drivers/staging/imx-drm/imx-drm.h
> @@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
>  int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
>  		struct device_node *np);
>  
> +int imx_drm_connector_mode_valid(struct drm_connector *connector,
> +	struct drm_display_mode *mode);
> +
>  #endif /* _IMX_DRM_H_ */

  CC      drivers/staging/imx-drm/ipu-v3/ipu-dc.o
  LD      net/ethernet/built-in.o
In file included from drivers/staging/imx-drm/ipu-v3/ipu-dc.c:23:0:
drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: ?struct drm_display_mode? declared inside parameter list [enabled by default]
drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

Shawn

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

* Re: [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
@ 2014-01-07  6:38     ` Shawn Guo
  0 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:38 UTC (permalink / raw)
  To: Russell King
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Thu, Jan 02, 2014 at 09:27:48PM +0000, Russell King wrote:
> diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
> index 5649f180dc44..4eb594ce9cff 100644
> --- a/drivers/staging/imx-drm/imx-drm.h
> +++ b/drivers/staging/imx-drm/imx-drm.h
> @@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
>  int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
>  		struct device_node *np);
>  
> +int imx_drm_connector_mode_valid(struct drm_connector *connector,
> +	struct drm_display_mode *mode);
> +
>  #endif /* _IMX_DRM_H_ */

  CC      drivers/staging/imx-drm/ipu-v3/ipu-dc.o
  LD      net/ethernet/built-in.o
In file included from drivers/staging/imx-drm/ipu-v3/ipu-dc.c:23:0:
drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: ‘struct drm_display_mode’ declared inside parameter list [enabled by default]
drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

Shawn

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

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

* [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
  2014-01-02 21:28   ` Russell King
@ 2014-01-07  6:49     ` Shawn Guo
  -1 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 09:28:19PM +0000, Russell King wrote:
> @@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
>  		}
>  	}
>  
> +	/*
> +	 * All components are now initialised, so setup the fb helper.
> +	 * The fb helper takes copies of key hardware information, so the
> +	 * crtcs/connectors/encoders must not change after this point.
> +	 */
> +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
> +	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> +		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> +		legacyfb_depth = 16;
> +	}
> +	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> +				drm->mode_config.num_crtc, 4);

s/4/MAX_CRTC

imx-drm-core.c has the macro.

Shawn

> +	if (IS_ERR(imxdrm->fbhelper)) {
> +		ret = PTR_ERR(imxdrm->fbhelper);
> +		imxdrm->fbhelper = NULL;
> +		goto err_unbind;
> +	}
> +#endif
>  	return 0;
>  
>  err_unbind:

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

* Re: [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
@ 2014-01-07  6:49     ` Shawn Guo
  0 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  6:49 UTC (permalink / raw)
  To: Russell King
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Thu, Jan 02, 2014 at 09:28:19PM +0000, Russell King wrote:
> @@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
>  		}
>  	}
>  
> +	/*
> +	 * All components are now initialised, so setup the fb helper.
> +	 * The fb helper takes copies of key hardware information, so the
> +	 * crtcs/connectors/encoders must not change after this point.
> +	 */
> +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
> +	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> +		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> +		legacyfb_depth = 16;
> +	}
> +	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> +				drm->mode_config.num_crtc, 4);

s/4/MAX_CRTC

imx-drm-core.c has the macro.

Shawn

> +	if (IS_ERR(imxdrm->fbhelper)) {
> +		ret = PTR_ERR(imxdrm->fbhelper);
> +		imxdrm->fbhelper = NULL;
> +		goto err_unbind;
> +	}
> +#endif
>  	return 0;
>  
>  err_unbind:

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-02 21:28   ` Russell King
@ 2014-01-07  8:59     ` Shawn Guo
  -1 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  8:59 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> index e75e11b36dff..0e005f21d241 100644
> --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> @@ -62,6 +62,12 @@
>  		};
>  	};
>  
> +	imx-drm {
> +		compatible = "fsl,imx-drm";
> +		crtcs = <&ipu1 0>, <&ipu1 1>;
> +		connectors = <&ldb>;
> +	};
> +

While the change works fine on imx6dl, it breaks LVDS support on imx6q
right away.

imx-ipuv3 2400000.ipu: IPUv3H probed
imx-ipuv3 2800000.ipu: IPUv3H probed
[drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[drm] No driver support for vblank timestamp query.
imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517

Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
defines only 2 in there, the imx_drm_encoder_parse_of() call from
imx_ldb_register() will always return -EPROBE_DEFER.

        lvds-channel at 0 {
                crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
        };

        lvds-channel at 1 {
                crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
        };

Shawn

>  	sound {
>  		compatible = "fsl,imx6q-sabresd-wm8962",
>  			   "fsl,imx-audio-wm8962";

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-07  8:59     ` Shawn Guo
  0 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-07  8:59 UTC (permalink / raw)
  To: Russell King
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> index e75e11b36dff..0e005f21d241 100644
> --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> @@ -62,6 +62,12 @@
>  		};
>  	};
>  
> +	imx-drm {
> +		compatible = "fsl,imx-drm";
> +		crtcs = <&ipu1 0>, <&ipu1 1>;
> +		connectors = <&ldb>;
> +	};
> +

While the change works fine on imx6dl, it breaks LVDS support on imx6q
right away.

imx-ipuv3 2400000.ipu: IPUv3H probed
imx-ipuv3 2800000.ipu: IPUv3H probed
[drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
[drm] No driver support for vblank timestamp query.
imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517

Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
defines only 2 in there, the imx_drm_encoder_parse_of() call from
imx_ldb_register() will always return -EPROBE_DEFER.

        lvds-channel@0 {
                crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
        };

        lvds-channel@1 {
                crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
        };

Shawn

>  	sound {
>  		compatible = "fsl,imx6q-sabresd-wm8962",
>  			   "fsl,imx-audio-wm8962";

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-07  2:31                 ` Eric Nelson
@ 2014-01-07 11:29                   ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-07 11:29 UTC (permalink / raw)
  To: linux-arm-kernel

Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
> Hi Russell,
> 
> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> > On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> >> Hi Eric,
> >>
> >> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> >>> This is an issue we've seen before. The SABRE Lite board has
> >>> a voltage divider on the HPD pins and some monitors (esp. DVI
> >>> monitors) either don't drive things high enough to assert HPD or
> >>> bounce with connect/disconnect.
> >>
> >> Yes, I used a DVI monitor.
> >>
> >>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> >>> instead.
> >>
> >> Reacting to RX_SENSE0 instead of HPD seems to work.
> >
> > However, it's non-compliant, because HPD can be lowered and raised by
> > the sink when it changes its EDID data (eg, because you're connected
> > through a switch and the routing has been changed.)
> >
> > So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> > only for those boards which are broken in this regard.
> >
> 
> I understand. We'll need to carry some patches for a while though,
> since there are lots of these boards in the wild.

Could you point me to your changes? Maybe this could be added to
mainline as a quirk enabled by a device tree property on sabrelite only.

regards
Philipp

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-07 11:29                   ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-07 11:29 UTC (permalink / raw)
  To: Eric Nelson
  Cc: devel, Russell King - ARM Linux, Greg Kroah-Hartman, dri-devel,
	Sascha Hauer, linux-arm-kernel

Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
> Hi Russell,
> 
> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> > On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> >> Hi Eric,
> >>
> >> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> >>> This is an issue we've seen before. The SABRE Lite board has
> >>> a voltage divider on the HPD pins and some monitors (esp. DVI
> >>> monitors) either don't drive things high enough to assert HPD or
> >>> bounce with connect/disconnect.
> >>
> >> Yes, I used a DVI monitor.
> >>
> >>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> >>> instead.
> >>
> >> Reacting to RX_SENSE0 instead of HPD seems to work.
> >
> > However, it's non-compliant, because HPD can be lowered and raised by
> > the sink when it changes its EDID data (eg, because you're connected
> > through a switch and the routing has been changed.)
> >
> > So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> > only for those boards which are broken in this regard.
> >
> 
> I understand. We'll need to carry some patches for a while though,
> since there are lots of these boards in the wild.

Could you point me to your changes? Maybe this could be added to
mainline as a quirk enabled by a device tree property on sabrelite only.

regards
Philipp

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-07 11:29                   ` Philipp Zabel
@ 2014-01-07 15:30                     ` Eric Nelson
  -1 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-07 15:30 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Philipp,

On 01/07/2014 04:29 AM, Philipp Zabel wrote:
> Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
>> Hi Russell,
>>
>> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
>>> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
>>>> Hi Eric,
>>>>
>>>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
>>>>> This is an issue we've seen before. The SABRE Lite board has
>>>>> a voltage divider on the HPD pins and some monitors (esp. DVI
>>>>> monitors) either don't drive things high enough to assert HPD or
>>>>> bounce with connect/disconnect.
>>>>
>>>> Yes, I used a DVI monitor.
>>>>
>>>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
>>>>> instead.
>>>>
>>>> Reacting to RX_SENSE0 instead of HPD seems to work.
>>>
>>> However, it's non-compliant, because HPD can be lowered and raised by
>>> the sink when it changes its EDID data (eg, because you're connected
>>> through a switch and the routing has been changed.)
>>>
>>> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
>>> only for those boards which are broken in this regard.
>>>
>>
>> I understand. We'll need to carry some patches for a while though,
>> since there are lots of these boards in the wild.
>
> Could you point me to your changes? Maybe this could be added to
> mainline as a quirk enabled by a device tree property on sabrelite only.
>

We only have them for 3.0.35 at the moment.

Here's the patch to use RXSENSE instead of HPD
	https://github.com/boundarydevices/linux-imx6/commit/c0439e262bb6c23887d96466b2ab7916aa0488d9

A follow-up patch disables the disconnect detection entirely
unless requested:
	https://github.com/boundarydevices/linux-imx6/commit/d9cd79d11ff9f7a7f89cbc94b68757b67cdfe5fc

Regards,


Eric

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-07 15:30                     ` Eric Nelson
  0 siblings, 0 replies; 219+ messages in thread
From: Eric Nelson @ 2014-01-07 15:30 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, Russell King - ARM Linux, David Airlie,
	Greg Kroah-Hartman, dri-devel, Laci Tele, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Hi Philipp,

On 01/07/2014 04:29 AM, Philipp Zabel wrote:
> Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
>> Hi Russell,
>>
>> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
>>> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
>>>> Hi Eric,
>>>>
>>>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
>>>>> This is an issue we've seen before. The SABRE Lite board has
>>>>> a voltage divider on the HPD pins and some monitors (esp. DVI
>>>>> monitors) either don't drive things high enough to assert HPD or
>>>>> bounce with connect/disconnect.
>>>>
>>>> Yes, I used a DVI monitor.
>>>>
>>>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
>>>>> instead.
>>>>
>>>> Reacting to RX_SENSE0 instead of HPD seems to work.
>>>
>>> However, it's non-compliant, because HPD can be lowered and raised by
>>> the sink when it changes its EDID data (eg, because you're connected
>>> through a switch and the routing has been changed.)
>>>
>>> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
>>> only for those boards which are broken in this regard.
>>>
>>
>> I understand. We'll need to carry some patches for a while though,
>> since there are lots of these boards in the wild.
>
> Could you point me to your changes? Maybe this could be added to
> mainline as a quirk enabled by a device tree property on sabrelite only.
>

We only have them for 3.0.35 at the moment.

Here's the patch to use RXSENSE instead of HPD
	https://github.com/boundarydevices/linux-imx6/commit/c0439e262bb6c23887d96466b2ab7916aa0488d9

A follow-up patch disables the disconnect detection entirely
unless requested:
	https://github.com/boundarydevices/linux-imx6/commit/d9cd79d11ff9f7a7f89cbc94b68757b67cdfe5fc

Regards,


Eric

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-07 15:30                     ` Eric Nelson
@ 2014-01-07 16:29                       ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-07 16:29 UTC (permalink / raw)
  To: linux-arm-kernel

Am Dienstag, den 07.01.2014, 08:30 -0700 schrieb Eric Nelson:
> Hi Philipp,
> 
> On 01/07/2014 04:29 AM, Philipp Zabel wrote:
> > Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
> >> Hi Russell,
> >>
> >> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> >>> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> >>>> Hi Eric,
> >>>>
> >>>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> >>>>> This is an issue we've seen before. The SABRE Lite board has
> >>>>> a voltage divider on the HPD pins and some monitors (esp. DVI
> >>>>> monitors) either don't drive things high enough to assert HPD or
> >>>>> bounce with connect/disconnect.
> >>>>
> >>>> Yes, I used a DVI monitor.
> >>>>
> >>>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> >>>>> instead.
> >>>>
> >>>> Reacting to RX_SENSE0 instead of HPD seems to work.
> >>>
> >>> However, it's non-compliant, because HPD can be lowered and raised by
> >>> the sink when it changes its EDID data (eg, because you're connected
> >>> through a switch and the routing has been changed.)
> >>>
> >>> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> >>> only for those boards which are broken in this regard.
> >>>
> >>
> >> I understand. We'll need to carry some patches for a while though,
> >> since there are lots of these boards in the wild.
> >
> > Could you point me to your changes? Maybe this could be added to
> > mainline as a quirk enabled by a device tree property on sabrelite only.
> >
> 
> We only have them for 3.0.35 at the moment.
> 
> Here's the patch to use RXSENSE instead of HPD
> 	https://github.com/boundarydevices/linux-imx6/commit/c0439e262bb6c23887d96466b2ab7916aa0488d9
> 
> A follow-up patch disables the disconnect detection entirely
> unless requested:
> 	https://github.com/boundarydevices/linux-imx6/commit/d9cd79d11ff9f7a7f89cbc94b68757b67cdfe5fc

Thanky you. This is what I came up with so far:

From: Philipp Zabel <p.zabel@pengutronix.de>
Subject: [PATCH 1/2] staging: imx-hdmi: use RX_SENSE0 for plug detection if
 HPD is unreliable

On some boards HPD might not reliably detect DVI monitors. Allow to use
RX_SENSE0 as a workaround.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/staging/imx-drm/imx-hdmi.c | 45 +++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 7779337..cc305f3 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -139,6 +139,7 @@ struct imx_hdmi {
 
 	struct regmap *regmap;
 	struct i2c_adapter *ddc;
+	bool hpd_unreliable;
 	void __iomem *regs;
 
 	unsigned int sample_rate;
@@ -1309,6 +1310,14 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 /* Wait until we are registered to enable interrupts */
 static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
+	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
+	int mask_bits = ~HDMI_PHY_HPD;
+
+	if (hdmi->hpd_unreliable) {
+		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
+		mask_bits = ~HDMI_PHY_RX_SENSE0;
+	}
+
 	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
 		    HDMI_PHY_I2CM_INT_ADDR);
 
@@ -1317,10 +1326,10 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 		    HDMI_PHY_I2CM_CTLINT_ADDR);
 
 	/* enable cable hot plug irq */
-	hdmi_writeb(hdmi, (u8)~HDMI_PHY_RX_SENSE0, HDMI_PHY_MASK0);
+	hdmi_writeb(hdmi, (u8)mask_bits, HDMI_PHY_MASK0);
 
 	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, stat_bit, HDMI_IH_PHY_STAT0);
 
 	return 0;
 }
@@ -1524,25 +1533,32 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
 static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 {
 	struct imx_hdmi *hdmi = dev_id;
+	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
+	int pol_bit = HDMI_PHY_HPD;
 	u8 intr_stat;
 	u8 phy_int_pol;
 
+	if (hdmi->hpd_unreliable) {
+		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
+		pol_bit = HDMI_PHY_RX_SENSE0;
+	}
+
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
 
 	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
 
-	if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE0) {
-		if (phy_int_pol & HDMI_PHY_RX_SENSE0) {
+	if (intr_stat & stat_bit) {
+		if (phy_int_pol & pol_bit) {
 			dev_dbg(hdmi->dev, "EVENT=plugin\n");
 
-			hdmi_modb(hdmi, 0, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, 0, pol_bit, HDMI_PHY_POL0);
 
 			hdmi->connector_status = connector_status_connected;
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
-			hdmi_modb(hdmi, HDMI_PHY_RX_SENSE0, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, pol_bit, pol_bit, HDMI_PHY_POL0);
 
 			hdmi->connector_status = connector_status_disconnected;
 			imx_hdmi_poweroff(hdmi);
@@ -1551,7 +1567,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	}
 
 	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, ~stat_bit, HDMI_IH_MUTE_PHY_STAT0);
 
 	return IRQ_HANDLED;
 }
@@ -1611,6 +1627,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
+	int pol_bit, stat_bit;
 	int ret, irq;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
@@ -1703,14 +1720,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	 */
 	hdmi_init_clk_regenerator(hdmi);
 
+	pol_bit = HDMI_PHY_HPD;
+	stat_bit =  HDMI_IH_PHY_STAT0_HPD;
+	hdmi->hpd_unreliable = of_property_read_bool(np, "hpd-unreliable");
+	if (hdmi->hpd_unreliable) {
+		pol_bit = HDMI_PHY_RX_SENSE0;
+		stat_bit =  HDMI_IH_PHY_STAT0_RX_SENSE0;
+	}
+
 	/*
 	 * Configure registers related to HDMI interrupt
 	 * generation before registering IRQ.
 	 */
-	hdmi_writeb(hdmi, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+	hdmi_writeb(hdmi, pol_bit, HDMI_PHY_POL0);
 
 	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, stat_bit, HDMI_IH_PHY_STAT0);
 
 	ret = imx_hdmi_fb_registered(hdmi);
 	if (ret)
@@ -1721,7 +1746,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		goto err_iahb;
 
 	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, ~stat_bit, HDMI_IH_MUTE_PHY_STAT0);
 
 	ret = snd_dw_hdmi_probe(&hdmi->audio, dev, hdmi->regs, irq, hdmi);
 	if (ret)
-- 
1.8.5.2

regards
Philipp

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-07 16:29                       ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-07 16:29 UTC (permalink / raw)
  To: Eric Nelson
  Cc: devel, Russell King - ARM Linux, David Airlie,
	Greg Kroah-Hartman, dri-devel, Laci Tele, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Am Dienstag, den 07.01.2014, 08:30 -0700 schrieb Eric Nelson:
> Hi Philipp,
> 
> On 01/07/2014 04:29 AM, Philipp Zabel wrote:
> > Am Montag, den 06.01.2014, 19:31 -0700 schrieb Eric Nelson:
> >> Hi Russell,
> >>
> >> On 01/06/2014 10:46 AM, Russell King - ARM Linux wrote:
> >>> On Mon, Jan 06, 2014 at 06:41:28PM +0100, Philipp Zabel wrote:
> >>>> Hi Eric,
> >>>>
> >>>> Am Freitag, den 03.01.2014, 12:14 -0700 schrieb Eric Nelson:
> >>>>> This is an issue we've seen before. The SABRE Lite board has
> >>>>> a voltage divider on the HPD pins and some monitors (esp. DVI
> >>>>> monitors) either don't drive things high enough to assert HPD or
> >>>>> bounce with connect/disconnect.
> >>>>
> >>>> Yes, I used a DVI monitor.
> >>>>
> >>>>> We've instrumented our 3.0.35 kernels to use the RX_SENSE bits
> >>>>> instead.
> >>>>
> >>>> Reacting to RX_SENSE0 instead of HPD seems to work.
> >>>
> >>> However, it's non-compliant, because HPD can be lowered and raised by
> >>> the sink when it changes its EDID data (eg, because you're connected
> >>> through a switch and the routing has been changed.)
> >>>
> >>> So, reacting to RX_SENSE0 instead of HPD has to be a work-around enabled
> >>> only for those boards which are broken in this regard.
> >>>
> >>
> >> I understand. We'll need to carry some patches for a while though,
> >> since there are lots of these boards in the wild.
> >
> > Could you point me to your changes? Maybe this could be added to
> > mainline as a quirk enabled by a device tree property on sabrelite only.
> >
> 
> We only have them for 3.0.35 at the moment.
> 
> Here's the patch to use RXSENSE instead of HPD
> 	https://github.com/boundarydevices/linux-imx6/commit/c0439e262bb6c23887d96466b2ab7916aa0488d9
> 
> A follow-up patch disables the disconnect detection entirely
> unless requested:
> 	https://github.com/boundarydevices/linux-imx6/commit/d9cd79d11ff9f7a7f89cbc94b68757b67cdfe5fc

Thanky you. This is what I came up with so far:

From: Philipp Zabel <p.zabel@pengutronix.de>
Subject: [PATCH 1/2] staging: imx-hdmi: use RX_SENSE0 for plug detection if
 HPD is unreliable

On some boards HPD might not reliably detect DVI monitors. Allow to use
RX_SENSE0 as a workaround.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
---
 drivers/staging/imx-drm/imx-hdmi.c | 45 +++++++++++++++++++++++++++++---------
 1 file changed, 35 insertions(+), 10 deletions(-)

diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
index 7779337..cc305f3 100644
--- a/drivers/staging/imx-drm/imx-hdmi.c
+++ b/drivers/staging/imx-drm/imx-hdmi.c
@@ -139,6 +139,7 @@ struct imx_hdmi {
 
 	struct regmap *regmap;
 	struct i2c_adapter *ddc;
+	bool hpd_unreliable;
 	void __iomem *regs;
 
 	unsigned int sample_rate;
@@ -1309,6 +1310,14 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
 /* Wait until we are registered to enable interrupts */
 static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 {
+	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
+	int mask_bits = ~HDMI_PHY_HPD;
+
+	if (hdmi->hpd_unreliable) {
+		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
+		mask_bits = ~HDMI_PHY_RX_SENSE0;
+	}
+
 	hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
 		    HDMI_PHY_I2CM_INT_ADDR);
 
@@ -1317,10 +1326,10 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
 		    HDMI_PHY_I2CM_CTLINT_ADDR);
 
 	/* enable cable hot plug irq */
-	hdmi_writeb(hdmi, (u8)~HDMI_PHY_RX_SENSE0, HDMI_PHY_MASK0);
+	hdmi_writeb(hdmi, (u8)mask_bits, HDMI_PHY_MASK0);
 
 	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, stat_bit, HDMI_IH_PHY_STAT0);
 
 	return 0;
 }
@@ -1524,25 +1533,32 @@ static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
 static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 {
 	struct imx_hdmi *hdmi = dev_id;
+	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
+	int pol_bit = HDMI_PHY_HPD;
 	u8 intr_stat;
 	u8 phy_int_pol;
 
+	if (hdmi->hpd_unreliable) {
+		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
+		pol_bit = HDMI_PHY_RX_SENSE0;
+	}
+
 	intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
 
 	phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
 
-	if (intr_stat & HDMI_IH_PHY_STAT0_RX_SENSE0) {
-		if (phy_int_pol & HDMI_PHY_RX_SENSE0) {
+	if (intr_stat & stat_bit) {
+		if (phy_int_pol & pol_bit) {
 			dev_dbg(hdmi->dev, "EVENT=plugin\n");
 
-			hdmi_modb(hdmi, 0, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, 0, pol_bit, HDMI_PHY_POL0);
 
 			hdmi->connector_status = connector_status_connected;
 			imx_hdmi_poweron(hdmi);
 		} else {
 			dev_dbg(hdmi->dev, "EVENT=plugout\n");
 
-			hdmi_modb(hdmi, HDMI_PHY_RX_SENSE0, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+			hdmi_modb(hdmi, pol_bit, pol_bit, HDMI_PHY_POL0);
 
 			hdmi->connector_status = connector_status_disconnected;
 			imx_hdmi_poweroff(hdmi);
@@ -1551,7 +1567,7 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
 	}
 
 	hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, ~stat_bit, HDMI_IH_MUTE_PHY_STAT0);
 
 	return IRQ_HANDLED;
 }
@@ -1611,6 +1627,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	struct device_node *ddc_node;
 	struct imx_hdmi *hdmi;
 	struct resource *iores;
+	int pol_bit, stat_bit;
 	int ret, irq;
 
 	hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
@@ -1703,14 +1720,22 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 	 */
 	hdmi_init_clk_regenerator(hdmi);
 
+	pol_bit = HDMI_PHY_HPD;
+	stat_bit =  HDMI_IH_PHY_STAT0_HPD;
+	hdmi->hpd_unreliable = of_property_read_bool(np, "hpd-unreliable");
+	if (hdmi->hpd_unreliable) {
+		pol_bit = HDMI_PHY_RX_SENSE0;
+		stat_bit =  HDMI_IH_PHY_STAT0_RX_SENSE0;
+	}
+
 	/*
 	 * Configure registers related to HDMI interrupt
 	 * generation before registering IRQ.
 	 */
-	hdmi_writeb(hdmi, HDMI_PHY_RX_SENSE0, HDMI_PHY_POL0);
+	hdmi_writeb(hdmi, pol_bit, HDMI_PHY_POL0);
 
 	/* Clear Hotplug interrupts */
-	hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_PHY_STAT0);
+	hdmi_writeb(hdmi, stat_bit, HDMI_IH_PHY_STAT0);
 
 	ret = imx_hdmi_fb_registered(hdmi);
 	if (ret)
@@ -1721,7 +1746,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
 		goto err_iahb;
 
 	/* Unmute interrupts */
-	hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_RX_SENSE0, HDMI_IH_MUTE_PHY_STAT0);
+	hdmi_writeb(hdmi, ~stat_bit, HDMI_IH_MUTE_PHY_STAT0);
 
 	ret = snd_dw_hdmi_probe(&hdmi->audio, dev, hdmi->regs, irq, hdmi);
 	if (ret)
-- 
1.8.5.2

regards
Philipp

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-02 21:27   ` Russell King
@ 2014-01-07 20:18     ` Sean Paul
  -1 siblings, 0 replies; 219+ messages in thread
From: Sean Paul @ 2014-01-07 20:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 2, 2014 at 4:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
>
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
>
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
>
>         imx-drm {
>                 compatible = "fsl,drm";
>                 crtcs = <&ipu1>;
>                 connectors = <&hdmi>;
>         };
>

Hi Russell,
This looks really good. I'd definitely like to use it for the exynos
drm driver both to bind the various IP blocks together, and also to
pull in any attached bridges that are specified in the device tree.
Along those lines, it might be worthwhile to pull some of the master
bind functionality in your next patch into drm helpers so other
drivers can use them, and so we have concrete bindings across drm.
Make sense?

Sean



> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
>
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/base/Makefile     |    2 +-
>  drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/component.h |   31 ++++
>  3 files changed, 411 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/base/component.c
>  create mode 100644 include/linux/component.h
>
> diff --git a/drivers/base/Makefile b/drivers/base/Makefile
> index 94e8a80e87f8..870ecfd503af 100644
> --- a/drivers/base/Makefile
> +++ b/drivers/base/Makefile
> @@ -1,6 +1,6 @@
>  # Makefile for the Linux device tree
>
> -obj-y                  := core.o bus.o dd.o syscore.o \
> +obj-y                  := component.o core.o bus.o dd.o syscore.o \
>                            driver.o class.o platform.o \
>                            cpu.o firmware.o init.o map.o devres.o \
>                            attribute_container.o transport_class.o \
> diff --git a/drivers/base/component.c b/drivers/base/component.c
> new file mode 100644
> index 000000000000..5492cd8d2247
> --- /dev/null
> +++ b/drivers/base/component.c
> @@ -0,0 +1,379 @@
> +/*
> + * Componentized device handling.
> + *
> + * 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.
> + *
> + * This is work in progress.  We gather up the component devices into a list,
> + * and bind them when instructed.  At the moment, we're specific to the DRM
> + * subsystem, and only handles one master device, but this doesn't have to be
> + * the case.
> + */
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +struct master {
> +       struct list_head node;
> +       struct list_head components;
> +       bool bound;
> +
> +       const struct component_master_ops *ops;
> +       struct device *dev;
> +};
> +
> +struct component {
> +       struct list_head node;
> +       struct list_head master_node;
> +       struct master *master;
> +       bool bound;
> +
> +       const struct component_ops *ops;
> +       struct device *dev;
> +};
> +
> +static DEFINE_MUTEX(component_mutex);
> +static LIST_HEAD(component_list);
> +static LIST_HEAD(masters);
> +
> +static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *m;
> +
> +       list_for_each_entry(m, &masters, node)
> +               if (m->dev == dev && (!ops || m->ops == ops))
> +                       return m;
> +
> +       return NULL;
> +}
> +
> +/* Attach an unattached component to a master. */
> +static void component_attach_master(struct master *master, struct component *c)
> +{
> +       c->master = master;
> +
> +       list_add_tail(&c->master_node, &master->components);
> +}
> +
> +/* Detach a component from a master. */
> +static void component_detach_master(struct master *master, struct component *c)
> +{
> +       list_del(&c->master_node);
> +
> +       c->master = NULL;
> +}
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data)
> +{
> +       struct component *c;
> +       int ret = -ENXIO;
> +
> +       list_for_each_entry(c, &component_list, node) {
> +               if (c->master)
> +                       continue;
> +
> +               if (compare(c->dev, compare_data)) {
> +                       component_attach_master(master, c);
> +                       ret = 0;
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add_child);
> +
> +/* Detach all attached components from this master */
> +static void master_remove_components(struct master *master)
> +{
> +       while (!list_empty(&master->components)) {
> +               struct component *c = list_first_entry(&master->components,
> +                                       struct component, master_node);
> +
> +               WARN_ON(c->master != master);
> +
> +               component_detach_master(master, c);
> +       }
> +}
> +
> +/*
> + * Try to bring up a master.  If component is NULL, we're interested in
> + * this master, otherwise it's a component which must be present to try
> + * and bring up the master.
> + *
> + * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
> + */
> +static int try_to_bring_up_master(struct master *master,
> +       struct component *component)
> +{
> +       int ret = 0;
> +
> +       if (!master->bound) {
> +               /*
> +                * Search the list of components, looking for components that
> +                * belong to this master, and attach them to the master.
> +                */
> +               if (master->ops->add_components(master->dev, master)) {
> +                       /* Failed to find all components */
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               if (component && component->master != master) {
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               /* Found all components */
> +               ret = master->ops->bind(master->dev);
> +               if (ret < 0) {
> +                       master_remove_components(master);
> +                       goto out;
> +               }
> +
> +               master->bound = true;
> +               ret = 1;
> +       }
> +out:
> +
> +       return ret;
> +}
> +
> +static int try_to_bring_up_masters(struct component *component)
> +{
> +       struct master *m;
> +       int ret = 0;
> +
> +       list_for_each_entry(m, &masters, node) {
> +               ret = try_to_bring_up_master(m, component);
> +               if (ret != 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static void take_down_master(struct master *master)
> +{
> +       if (master->bound) {
> +               master->ops->unbind(master->dev);
> +               master->bound = false;
> +       }
> +
> +       master_remove_components(master);
> +}
> +
> +int component_master_add(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +       int ret;
> +
> +       master = kzalloc(sizeof(*master), GFP_KERNEL);
> +       if (!master)
> +               return -ENOMEM;
> +
> +       master->dev = dev;
> +       master->ops = ops;
> +       INIT_LIST_HEAD(&master->components);
> +
> +       /* Add to the list of available masters. */
> +       mutex_lock(&component_mutex);
> +       list_add(&master->node, &masters);
> +
> +       ret = try_to_bring_up_master(master, NULL);
> +
> +       if (ret < 0) {
> +               /* Delete off the list if we weren't successful */
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add);
> +
> +void component_master_del(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +
> +       mutex_lock(&component_mutex);
> +       master = __master_find(dev, ops);
> +       if (master) {
> +               take_down_master(master);
> +
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +}
> +EXPORT_SYMBOL_GPL(component_master_del);
> +
> +static void component_unbind(struct component *component,
> +       struct master *master, void *data)
> +{
> +       WARN_ON(!component->bound);
> +
> +       component->ops->unbind(component->dev, master->dev, data);
> +       component->bound = false;
> +
> +       /* Release all resources claimed in the binding of this component */
> +       devres_release_group(component->dev, component);
> +}
> +
> +void component_unbind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return;
> +
> +       list_for_each_entry_reverse(c, &master->components, master_node)
> +               component_unbind(c, master, data);
> +}
> +EXPORT_SYMBOL_GPL(component_unbind_all);
> +
> +static int component_bind(struct component *component, struct master *master,
> +       void *data)
> +{
> +       int ret;
> +
> +       /*
> +        * Each component initialises inside its own devres group.
> +        * This allows us to roll-back a failed component without
> +        * affecting anything else.
> +        */
> +       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
> +               return -ENOMEM;
> +
> +       /*
> +        * Also open a group for the device itself: this allows us
> +        * to release the resources claimed against the sub-device
> +        * at the appropriate moment.
> +        */
> +       if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
> +               devres_release_group(master->dev, NULL);
> +               return -ENOMEM;
> +       }
> +
> +       dev_dbg(master->dev, "binding %s (ops %ps)\n",
> +               dev_name(component->dev), component->ops);
> +
> +       ret = component->ops->bind(component->dev, master->dev, data);
> +       if (!ret) {
> +               component->bound = true;
> +
> +               /*
> +                * Close the component device's group so that resources
> +                * allocated in the binding are encapsulated for removal
> +                * at unbind.  Remove the group on the DRM device as we
> +                * can clean those resources up independently.
> +                */
> +               devres_close_group(component->dev, NULL);
> +               devres_remove_group(master->dev, NULL);
> +
> +               dev_info(master->dev, "bound %s (ops %ps)\n",
> +                        dev_name(component->dev), component->ops);
> +       } else {
> +               devres_release_group(component->dev, NULL);
> +               devres_release_group(master->dev, NULL);
> +
> +               dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
> +                       dev_name(component->dev), component->ops, ret);
> +       }
> +
> +       return ret;
> +}
> +
> +int component_bind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +       int ret = 0;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return -EINVAL;
> +
> +       list_for_each_entry(c, &master->components, master_node) {
> +               ret = component_bind(c, master, data);
> +               if (ret)
> +                       break;
> +       }
> +
> +       if (ret != 0) {
> +               list_for_each_entry_continue_reverse(c, &master->components,
> +                                                    master_node)
> +                       component_unbind(c, master, data);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_bind_all);
> +
> +int component_add(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *component;
> +       int ret;
> +
> +       component = kzalloc(sizeof(*component), GFP_KERNEL);
> +       if (!component)
> +               return -ENOMEM;
> +
> +       component->ops = ops;
> +       component->dev = dev;
> +
> +       dev_dbg(dev, "adding component (ops %ps)\n", ops);
> +
> +       mutex_lock(&component_mutex);
> +       list_add_tail(&component->node, &component_list);
> +
> +       ret = try_to_bring_up_masters(component);
> +       if (ret < 0) {
> +               list_del(&component->node);
> +
> +               kfree(component);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_add);
> +
> +void component_del(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *c, *component = NULL;
> +
> +       mutex_lock(&component_mutex);
> +       list_for_each_entry(c, &component_list, node)
> +               if (c->dev == dev && c->ops == ops) {
> +                       list_del(&c->node);
> +                       component = c;
> +                       break;
> +               }
> +
> +       if (component && component->master)
> +               take_down_master(component->master);
> +
> +       mutex_unlock(&component_mutex);
> +
> +       WARN_ON(!component);
> +       kfree(component);
> +}
> +EXPORT_SYMBOL_GPL(component_del);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/component.h b/include/linux/component.h
> new file mode 100644
> index 000000000000..73657636db0b
> --- /dev/null
> +++ b/include/linux/component.h
> @@ -0,0 +1,31 @@
> +#ifndef COMPONENT_H
> +#define COMPONENT_H
> +
> +struct device;
> +
> +struct component_ops {
> +       int (*bind)(struct device *, struct device *, void *);
> +       void (*unbind)(struct device *, struct device *, void *);
> +};
> +
> +int component_add(struct device *, const struct component_ops *);
> +void component_del(struct device *, const struct component_ops *);
> +
> +int component_bind_all(struct device *, void *);
> +void component_unbind_all(struct device *, void *);
> +
> +struct master;
> +
> +struct component_master_ops {
> +       int (*add_components)(struct device *, struct master *);
> +       int (*bind)(struct device *);
> +       void (*unbind)(struct device *);
> +};
> +
> +int component_master_add(struct device *, const struct component_master_ops *);
> +void component_master_del(struct device *, const struct component_master_ops *);
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data);
> +
> +#endif
> --
> 1.7.4.4
>
> _______________________________________________
> devel mailing list
> devel at linuxdriverproject.org
> http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-07 20:18     ` Sean Paul
  0 siblings, 0 replies; 219+ messages in thread
From: Sean Paul @ 2014-01-07 20:18 UTC (permalink / raw)
  To: Russell King
  Cc: devel, Greg Kroah-Hartman, dri-devel, Sascha Hauer, Linux ARM Kernel

On Thu, Jan 2, 2014 at 4:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
>
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
>
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
>
>         imx-drm {
>                 compatible = "fsl,drm";
>                 crtcs = <&ipu1>;
>                 connectors = <&hdmi>;
>         };
>

Hi Russell,
This looks really good. I'd definitely like to use it for the exynos
drm driver both to bind the various IP blocks together, and also to
pull in any attached bridges that are specified in the device tree.
Along those lines, it might be worthwhile to pull some of the master
bind functionality in your next patch into drm helpers so other
drivers can use them, and so we have concrete bindings across drm.
Make sense?

Sean



> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
>
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/base/Makefile     |    2 +-
>  drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/component.h |   31 ++++
>  3 files changed, 411 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/base/component.c
>  create mode 100644 include/linux/component.h
>
> diff --git a/drivers/base/Makefile b/drivers/base/Makefile
> index 94e8a80e87f8..870ecfd503af 100644
> --- a/drivers/base/Makefile
> +++ b/drivers/base/Makefile
> @@ -1,6 +1,6 @@
>  # Makefile for the Linux device tree
>
> -obj-y                  := core.o bus.o dd.o syscore.o \
> +obj-y                  := component.o core.o bus.o dd.o syscore.o \
>                            driver.o class.o platform.o \
>                            cpu.o firmware.o init.o map.o devres.o \
>                            attribute_container.o transport_class.o \
> diff --git a/drivers/base/component.c b/drivers/base/component.c
> new file mode 100644
> index 000000000000..5492cd8d2247
> --- /dev/null
> +++ b/drivers/base/component.c
> @@ -0,0 +1,379 @@
> +/*
> + * Componentized device handling.
> + *
> + * 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.
> + *
> + * This is work in progress.  We gather up the component devices into a list,
> + * and bind them when instructed.  At the moment, we're specific to the DRM
> + * subsystem, and only handles one master device, but this doesn't have to be
> + * the case.
> + */
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +struct master {
> +       struct list_head node;
> +       struct list_head components;
> +       bool bound;
> +
> +       const struct component_master_ops *ops;
> +       struct device *dev;
> +};
> +
> +struct component {
> +       struct list_head node;
> +       struct list_head master_node;
> +       struct master *master;
> +       bool bound;
> +
> +       const struct component_ops *ops;
> +       struct device *dev;
> +};
> +
> +static DEFINE_MUTEX(component_mutex);
> +static LIST_HEAD(component_list);
> +static LIST_HEAD(masters);
> +
> +static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *m;
> +
> +       list_for_each_entry(m, &masters, node)
> +               if (m->dev == dev && (!ops || m->ops == ops))
> +                       return m;
> +
> +       return NULL;
> +}
> +
> +/* Attach an unattached component to a master. */
> +static void component_attach_master(struct master *master, struct component *c)
> +{
> +       c->master = master;
> +
> +       list_add_tail(&c->master_node, &master->components);
> +}
> +
> +/* Detach a component from a master. */
> +static void component_detach_master(struct master *master, struct component *c)
> +{
> +       list_del(&c->master_node);
> +
> +       c->master = NULL;
> +}
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data)
> +{
> +       struct component *c;
> +       int ret = -ENXIO;
> +
> +       list_for_each_entry(c, &component_list, node) {
> +               if (c->master)
> +                       continue;
> +
> +               if (compare(c->dev, compare_data)) {
> +                       component_attach_master(master, c);
> +                       ret = 0;
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add_child);
> +
> +/* Detach all attached components from this master */
> +static void master_remove_components(struct master *master)
> +{
> +       while (!list_empty(&master->components)) {
> +               struct component *c = list_first_entry(&master->components,
> +                                       struct component, master_node);
> +
> +               WARN_ON(c->master != master);
> +
> +               component_detach_master(master, c);
> +       }
> +}
> +
> +/*
> + * Try to bring up a master.  If component is NULL, we're interested in
> + * this master, otherwise it's a component which must be present to try
> + * and bring up the master.
> + *
> + * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
> + */
> +static int try_to_bring_up_master(struct master *master,
> +       struct component *component)
> +{
> +       int ret = 0;
> +
> +       if (!master->bound) {
> +               /*
> +                * Search the list of components, looking for components that
> +                * belong to this master, and attach them to the master.
> +                */
> +               if (master->ops->add_components(master->dev, master)) {
> +                       /* Failed to find all components */
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               if (component && component->master != master) {
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               /* Found all components */
> +               ret = master->ops->bind(master->dev);
> +               if (ret < 0) {
> +                       master_remove_components(master);
> +                       goto out;
> +               }
> +
> +               master->bound = true;
> +               ret = 1;
> +       }
> +out:
> +
> +       return ret;
> +}
> +
> +static int try_to_bring_up_masters(struct component *component)
> +{
> +       struct master *m;
> +       int ret = 0;
> +
> +       list_for_each_entry(m, &masters, node) {
> +               ret = try_to_bring_up_master(m, component);
> +               if (ret != 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static void take_down_master(struct master *master)
> +{
> +       if (master->bound) {
> +               master->ops->unbind(master->dev);
> +               master->bound = false;
> +       }
> +
> +       master_remove_components(master);
> +}
> +
> +int component_master_add(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +       int ret;
> +
> +       master = kzalloc(sizeof(*master), GFP_KERNEL);
> +       if (!master)
> +               return -ENOMEM;
> +
> +       master->dev = dev;
> +       master->ops = ops;
> +       INIT_LIST_HEAD(&master->components);
> +
> +       /* Add to the list of available masters. */
> +       mutex_lock(&component_mutex);
> +       list_add(&master->node, &masters);
> +
> +       ret = try_to_bring_up_master(master, NULL);
> +
> +       if (ret < 0) {
> +               /* Delete off the list if we weren't successful */
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add);
> +
> +void component_master_del(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +
> +       mutex_lock(&component_mutex);
> +       master = __master_find(dev, ops);
> +       if (master) {
> +               take_down_master(master);
> +
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +}
> +EXPORT_SYMBOL_GPL(component_master_del);
> +
> +static void component_unbind(struct component *component,
> +       struct master *master, void *data)
> +{
> +       WARN_ON(!component->bound);
> +
> +       component->ops->unbind(component->dev, master->dev, data);
> +       component->bound = false;
> +
> +       /* Release all resources claimed in the binding of this component */
> +       devres_release_group(component->dev, component);
> +}
> +
> +void component_unbind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return;
> +
> +       list_for_each_entry_reverse(c, &master->components, master_node)
> +               component_unbind(c, master, data);
> +}
> +EXPORT_SYMBOL_GPL(component_unbind_all);
> +
> +static int component_bind(struct component *component, struct master *master,
> +       void *data)
> +{
> +       int ret;
> +
> +       /*
> +        * Each component initialises inside its own devres group.
> +        * This allows us to roll-back a failed component without
> +        * affecting anything else.
> +        */
> +       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
> +               return -ENOMEM;
> +
> +       /*
> +        * Also open a group for the device itself: this allows us
> +        * to release the resources claimed against the sub-device
> +        * at the appropriate moment.
> +        */
> +       if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
> +               devres_release_group(master->dev, NULL);
> +               return -ENOMEM;
> +       }
> +
> +       dev_dbg(master->dev, "binding %s (ops %ps)\n",
> +               dev_name(component->dev), component->ops);
> +
> +       ret = component->ops->bind(component->dev, master->dev, data);
> +       if (!ret) {
> +               component->bound = true;
> +
> +               /*
> +                * Close the component device's group so that resources
> +                * allocated in the binding are encapsulated for removal
> +                * at unbind.  Remove the group on the DRM device as we
> +                * can clean those resources up independently.
> +                */
> +               devres_close_group(component->dev, NULL);
> +               devres_remove_group(master->dev, NULL);
> +
> +               dev_info(master->dev, "bound %s (ops %ps)\n",
> +                        dev_name(component->dev), component->ops);
> +       } else {
> +               devres_release_group(component->dev, NULL);
> +               devres_release_group(master->dev, NULL);
> +
> +               dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
> +                       dev_name(component->dev), component->ops, ret);
> +       }
> +
> +       return ret;
> +}
> +
> +int component_bind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +       int ret = 0;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return -EINVAL;
> +
> +       list_for_each_entry(c, &master->components, master_node) {
> +               ret = component_bind(c, master, data);
> +               if (ret)
> +                       break;
> +       }
> +
> +       if (ret != 0) {
> +               list_for_each_entry_continue_reverse(c, &master->components,
> +                                                    master_node)
> +                       component_unbind(c, master, data);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_bind_all);
> +
> +int component_add(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *component;
> +       int ret;
> +
> +       component = kzalloc(sizeof(*component), GFP_KERNEL);
> +       if (!component)
> +               return -ENOMEM;
> +
> +       component->ops = ops;
> +       component->dev = dev;
> +
> +       dev_dbg(dev, "adding component (ops %ps)\n", ops);
> +
> +       mutex_lock(&component_mutex);
> +       list_add_tail(&component->node, &component_list);
> +
> +       ret = try_to_bring_up_masters(component);
> +       if (ret < 0) {
> +               list_del(&component->node);
> +
> +               kfree(component);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_add);
> +
> +void component_del(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *c, *component = NULL;
> +
> +       mutex_lock(&component_mutex);
> +       list_for_each_entry(c, &component_list, node)
> +               if (c->dev == dev && c->ops == ops) {
> +                       list_del(&c->node);
> +                       component = c;
> +                       break;
> +               }
> +
> +       if (component && component->master)
> +               take_down_master(component->master);
> +
> +       mutex_unlock(&component_mutex);
> +
> +       WARN_ON(!component);
> +       kfree(component);
> +}
> +EXPORT_SYMBOL_GPL(component_del);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/component.h b/include/linux/component.h
> new file mode 100644
> index 000000000000..73657636db0b
> --- /dev/null
> +++ b/include/linux/component.h
> @@ -0,0 +1,31 @@
> +#ifndef COMPONENT_H
> +#define COMPONENT_H
> +
> +struct device;
> +
> +struct component_ops {
> +       int (*bind)(struct device *, struct device *, void *);
> +       void (*unbind)(struct device *, struct device *, void *);
> +};
> +
> +int component_add(struct device *, const struct component_ops *);
> +void component_del(struct device *, const struct component_ops *);
> +
> +int component_bind_all(struct device *, void *);
> +void component_unbind_all(struct device *, void *);
> +
> +struct master;
> +
> +struct component_master_ops {
> +       int (*add_components)(struct device *, struct master *);
> +       int (*bind)(struct device *);
> +       void (*unbind)(struct device *);
> +};
> +
> +int component_master_add(struct device *, const struct component_master_ops *);
> +void component_master_del(struct device *, const struct component_master_ops *);
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data);
> +
> +#endif
> --
> 1.7.4.4
>
> _______________________________________________
> devel mailing list
> devel@linuxdriverproject.org
> http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

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

* [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
  2014-01-07  6:38     ` Shawn Guo
@ 2014-01-08 21:25       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 02:38:05PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:27:48PM +0000, Russell King wrote:
> > diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
> > index 5649f180dc44..4eb594ce9cff 100644
> > --- a/drivers/staging/imx-drm/imx-drm.h
> > +++ b/drivers/staging/imx-drm/imx-drm.h
> > @@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
> >  int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
> >  		struct device_node *np);
> >  
> > +int imx_drm_connector_mode_valid(struct drm_connector *connector,
> > +	struct drm_display_mode *mode);
> > +
> >  #endif /* _IMX_DRM_H_ */
> 
>   CC      drivers/staging/imx-drm/ipu-v3/ipu-dc.o
>   LD      net/ethernet/built-in.o
> In file included from drivers/staging/imx-drm/ipu-v3/ipu-dc.c:23:0:
> drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: ?struct drm_display_mode? declared inside parameter list [enabled by default]
> drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

Thanks, fixed.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 24/46] imx-drm: provide common connector mode validation function
@ 2014-01-08 21:25       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:25 UTC (permalink / raw)
  To: Shawn Guo
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Tue, Jan 07, 2014 at 02:38:05PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:27:48PM +0000, Russell King wrote:
> > diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
> > index 5649f180dc44..4eb594ce9cff 100644
> > --- a/drivers/staging/imx-drm/imx-drm.h
> > +++ b/drivers/staging/imx-drm/imx-drm.h
> > @@ -68,4 +68,7 @@ int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
> >  int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder,
> >  		struct device_node *np);
> >  
> > +int imx_drm_connector_mode_valid(struct drm_connector *connector,
> > +	struct drm_display_mode *mode);
> > +
> >  #endif /* _IMX_DRM_H_ */
> 
>   CC      drivers/staging/imx-drm/ipu-v3/ipu-dc.o
>   LD      net/ethernet/built-in.o
> In file included from drivers/staging/imx-drm/ipu-v3/ipu-dc.c:23:0:
> drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: ‘struct drm_display_mode’ declared inside parameter list [enabled by default]
> drivers/staging/imx-drm/ipu-v3/../imx-drm.h:56:9: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]

Thanks, fixed.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

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

* [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
  2014-01-07  6:49     ` Shawn Guo
@ 2014-01-08 21:27       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 02:49:50PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:28:19PM +0000, Russell King wrote:
> > @@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
> >  		}
> >  	}
> >  
> > +	/*
> > +	 * All components are now initialised, so setup the fb helper.
> > +	 * The fb helper takes copies of key hardware information, so the
> > +	 * crtcs/connectors/encoders must not change after this point.
> > +	 */
> > +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
> > +	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> > +		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> > +		legacyfb_depth = 16;
> > +	}
> > +	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> > +				drm->mode_config.num_crtc, 4);
> 
> s/4/MAX_CRTC
> 
> imx-drm-core.c has the macro.

Possible, but when moving code from one location to another it's best
to move it with minimal changes.  Even so, I've now changed this.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev
@ 2014-01-08 21:27       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:27 UTC (permalink / raw)
  To: Shawn Guo
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Tue, Jan 07, 2014 at 02:49:50PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:28:19PM +0000, Russell King wrote:
> > @@ -449,6 +458,24 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
> >  		}
> >  	}
> >  
> > +	/*
> > +	 * All components are now initialised, so setup the fb helper.
> > +	 * The fb helper takes copies of key hardware information, so the
> > +	 * crtcs/connectors/encoders must not change after this point.
> > +	 */
> > +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
> > +	if (legacyfb_depth != 16 && legacyfb_depth != 32) {
> > +		dev_warn(drm->dev, "Invalid legacyfb_depth.  Defaulting to 16bpp\n");
> > +		legacyfb_depth = 16;
> > +	}
> > +	imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth,
> > +				drm->mode_config.num_crtc, 4);
> 
> s/4/MAX_CRTC
> 
> imx-drm-core.c has the macro.

Possible, but when moving code from one location to another it's best
to move it with minimal changes.  Even so, I've now changed this.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-07  8:59     ` Shawn Guo
@ 2014-01-08 21:32       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:32 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 04:59:35PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> > diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > index e75e11b36dff..0e005f21d241 100644
> > --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > @@ -62,6 +62,12 @@
> >  		};
> >  	};
> >  
> > +	imx-drm {
> > +		compatible = "fsl,imx-drm";
> > +		crtcs = <&ipu1 0>, <&ipu1 1>;
> > +		connectors = <&ldb>;
> > +	};
> > +
> 
> While the change works fine on imx6dl, it breaks LVDS support on imx6q
> right away.
> 
> imx-ipuv3 2400000.ipu: IPUv3H probed
> imx-ipuv3 2800000.ipu: IPUv3H probed
> [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
> [drm] No driver support for vblank timestamp query.
> imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
> imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
> imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517
> 
> Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
> defines only 2 in there, the imx_drm_encoder_parse_of() call from
> imx_ldb_register() will always return -EPROBE_DEFER.
> 
>         lvds-channel at 0 {
>                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
>         };
> 
>         lvds-channel at 1 {
>                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
>         };

This is why some help would be useful here - I think I got these right
but I've no way to check them.

Can you confirm that adding all four is the right thing not only for
the imx6q but also the imx6dl sabresd please?

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-08 21:32       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:32 UTC (permalink / raw)
  To: Shawn Guo
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Tue, Jan 07, 2014 at 04:59:35PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> > diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > index e75e11b36dff..0e005f21d241 100644
> > --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > @@ -62,6 +62,12 @@
> >  		};
> >  	};
> >  
> > +	imx-drm {
> > +		compatible = "fsl,imx-drm";
> > +		crtcs = <&ipu1 0>, <&ipu1 1>;
> > +		connectors = <&ldb>;
> > +	};
> > +
> 
> While the change works fine on imx6dl, it breaks LVDS support on imx6q
> right away.
> 
> imx-ipuv3 2400000.ipu: IPUv3H probed
> imx-ipuv3 2800000.ipu: IPUv3H probed
> [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
> [drm] No driver support for vblank timestamp query.
> imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
> imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
> imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517
> 
> Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
> defines only 2 in there, the imx_drm_encoder_parse_of() call from
> imx_ldb_register() will always return -EPROBE_DEFER.
> 
>         lvds-channel@0 {
>                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
>         };
> 
>         lvds-channel@1 {
>                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
>         };

This is why some help would be useful here - I think I got these right
but I've no way to check them.

Can you confirm that adding all four is the right thing not only for
the imx6q but also the imx6dl sabresd please?

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-07 20:18     ` Sean Paul
@ 2014-01-08 21:36       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 03:18:21PM -0500, Sean Paul wrote:
> On Thu, Jan 2, 2014 at 4:27 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> >
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> >
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> >
> >         imx-drm {
> >                 compatible = "fsl,drm";
> >                 crtcs = <&ipu1>;
> >                 connectors = <&hdmi>;
> >         };
> >
> 
> Hi Russell,
> This looks really good. I'd definitely like to use it for the exynos
> drm driver both to bind the various IP blocks together, and also to
> pull in any attached bridges that are specified in the device tree.
> Along those lines, it might be worthwhile to pull some of the master
> bind functionality in your next patch into drm helpers so other
> drivers can use them, and so we have concrete bindings across drm.

Which bits do you think would be useful to move into the core?
imx_drm_add_components() is rather imx-drm specific, especially for
the CRTCs - it carries the knowledge that the OF device to be matched
can be found in the _parent_ device, rather than the device registered
into the component helpers.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-08 21:36       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:36 UTC (permalink / raw)
  To: Sean Paul
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Shawn Guo, Linux ARM Kernel

On Tue, Jan 07, 2014 at 03:18:21PM -0500, Sean Paul wrote:
> On Thu, Jan 2, 2014 at 4:27 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> >
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> >
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> >
> >         imx-drm {
> >                 compatible = "fsl,drm";
> >                 crtcs = <&ipu1>;
> >                 connectors = <&hdmi>;
> >         };
> >
> 
> Hi Russell,
> This looks really good. I'd definitely like to use it for the exynos
> drm driver both to bind the various IP blocks together, and also to
> pull in any attached bridges that are specified in the device tree.
> Along those lines, it might be worthwhile to pull some of the master
> bind functionality in your next patch into drm helpers so other
> drivers can use them, and so we have concrete bindings across drm.

Which bits do you think would be useful to move into the core?
imx_drm_add_components() is rather imx-drm specific, especially for
the CRTCs - it carries the knowledge that the OF device to be matched
can be found in the _parent_ device, rather than the device registered
into the component helpers.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-07 16:29                       ` Philipp Zabel
@ 2014-01-08 21:40                         ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 05:29:55PM +0100, Philipp Zabel wrote:
> Thanky you. This is what I came up with so far:
> 
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Subject: [PATCH 1/2] staging: imx-hdmi: use RX_SENSE0 for plug detection if
>  HPD is unreliable
> 
> On some boards HPD might not reliably detect DVI monitors. Allow to use
> RX_SENSE0 as a workaround.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
>  drivers/staging/imx-drm/imx-hdmi.c | 45 +++++++++++++++++++++++++++++---------
>  1 file changed, 35 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
> index 7779337..cc305f3 100644
> --- a/drivers/staging/imx-drm/imx-hdmi.c
> +++ b/drivers/staging/imx-drm/imx-hdmi.c
> @@ -139,6 +139,7 @@ struct imx_hdmi {
>  
>  	struct regmap *regmap;
>  	struct i2c_adapter *ddc;
> +	bool hpd_unreliable;
>  	void __iomem *regs;
>  
>  	unsigned int sample_rate;
> @@ -1309,6 +1310,14 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
>  /* Wait until we are registered to enable interrupts */
>  static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
>  {
> +	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
> +	int mask_bits = ~HDMI_PHY_HPD;
> +
> +	if (hdmi->hpd_unreliable) {
> +		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
> +		mask_bits = ~HDMI_PHY_RX_SENSE0;
> +	}
> +

How about storing these in imx_hdmi instead, so we don't have to compute
them in each interrupt?  Maybe "sink_detect_status" and "sink_detect_mask"?

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-08 21:40                         ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-08 21:40 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, David Airlie, Greg Kroah-Hartman, Eric Nelson, dri-devel,
	Laci Tele, Sascha Hauer, Shawn Guo, linux-arm-kernel

On Tue, Jan 07, 2014 at 05:29:55PM +0100, Philipp Zabel wrote:
> Thanky you. This is what I came up with so far:
> 
> From: Philipp Zabel <p.zabel@pengutronix.de>
> Subject: [PATCH 1/2] staging: imx-hdmi: use RX_SENSE0 for plug detection if
>  HPD is unreliable
> 
> On some boards HPD might not reliably detect DVI monitors. Allow to use
> RX_SENSE0 as a workaround.
> 
> Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
> ---
>  drivers/staging/imx-drm/imx-hdmi.c | 45 +++++++++++++++++++++++++++++---------
>  1 file changed, 35 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
> index 7779337..cc305f3 100644
> --- a/drivers/staging/imx-drm/imx-hdmi.c
> +++ b/drivers/staging/imx-drm/imx-hdmi.c
> @@ -139,6 +139,7 @@ struct imx_hdmi {
>  
>  	struct regmap *regmap;
>  	struct i2c_adapter *ddc;
> +	bool hpd_unreliable;
>  	void __iomem *regs;
>  
>  	unsigned int sample_rate;
> @@ -1309,6 +1310,14 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
>  /* Wait until we are registered to enable interrupts */
>  static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
>  {
> +	int stat_bit = HDMI_IH_PHY_STAT0_HPD;
> +	int mask_bits = ~HDMI_PHY_HPD;
> +
> +	if (hdmi->hpd_unreliable) {
> +		stat_bit = HDMI_IH_PHY_STAT0_RX_SENSE0;
> +		mask_bits = ~HDMI_PHY_RX_SENSE0;
> +	}
> +

How about storing these in imx_hdmi instead, so we don't have to compute
them in each interrupt?  Maybe "sink_detect_status" and "sink_detect_mask"?

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-08 21:36       ` Russell King - ARM Linux
@ 2014-01-08 22:39         ` Sean Paul
  -1 siblings, 0 replies; 219+ messages in thread
From: Sean Paul @ 2014-01-08 22:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 8, 2014 at 4:36 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Tue, Jan 07, 2014 at 03:18:21PM -0500, Sean Paul wrote:
>> On Thu, Jan 2, 2014 at 4:27 PM, Russell King
>> <rmk+kernel@arm.linux.org.uk> wrote:
>> > Subsystems such as ALSA, DRM and others require a single card-level
>> > device structure to represent a subsystem.  However, firmware tends to
>> > describe the individual devices and the connections between them.
>> >
>> > Therefore, we need a way to gather up the individual component devices
>> > together, and indicate when we have all the component devices.
>> >
>> > We do this in DT by providing a "superdevice" node which specifies
>> > the components, eg:
>> >
>> >         imx-drm {
>> >                 compatible = "fsl,drm";
>> >                 crtcs = <&ipu1>;
>> >                 connectors = <&hdmi>;
>> >         };
>> >
>>
>> Hi Russell,
>> This looks really good. I'd definitely like to use it for the exynos
>> drm driver both to bind the various IP blocks together, and also to
>> pull in any attached bridges that are specified in the device tree.
>> Along those lines, it might be worthwhile to pull some of the master
>> bind functionality in your next patch into drm helpers so other
>> drivers can use them, and so we have concrete bindings across drm.
>
> Which bits do you think would be useful to move into the core?
> imx_drm_add_components() is rather imx-drm specific, especially for
> the CRTCs - it carries the knowledge that the OF device to be matched
> can be found in the _parent_ device, rather than the device registered
> into the component helpers.
>

Yeah, I was thinking of imx_drm_add_components() actually. It probably
doesn't make sense to enforce the parent relationship in a generic
manner, but it would be nice to have a helper which added the various
drm components (crtc/encoder/bridge/connector) with a consistent
binding.

We have 3 different exynos boards which would have the following
superdevices (please forgive my hypothetical syntax/naming):

Board 1:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        bridges = <&ptn3460 &dp1>;
        connectors = <&ptn3460>, <&hdmi1>;
};

Board 2:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        bridges = <&ps8622 &dp1>, <&anx7808 &hdmi1>;
        connectors = <&ps8622>, <&anx7808>;
};

Board 3:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        connectors = <&dp1>, <&hdmi1>;
};

In addition to enforcing common bindings across drivers, we could also
assign bridges to encoders from the dt. The bridge->encoder
relationship is 1:1 at the moment, and the bridge driver can be a
completely separate entity from the encoder. Allowing assignment from
the dt means the encoder never needs to know whether a bridge is
connected.

Right now the encoder must enumerate all possible bridges to see if
they are present (check out "[PATCH v3 31/32] drm/exynos: Move lvds
bridge discovery into DP driver" for an example of what I mean).

Sean

> --
> FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
> in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
> Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-08 22:39         ` Sean Paul
  0 siblings, 0 replies; 219+ messages in thread
From: Sean Paul @ 2014-01-08 22:39 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, Greg Kroah-Hartman, dri-devel, Sascha Hauer, Linux ARM Kernel

On Wed, Jan 8, 2014 at 4:36 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Tue, Jan 07, 2014 at 03:18:21PM -0500, Sean Paul wrote:
>> On Thu, Jan 2, 2014 at 4:27 PM, Russell King
>> <rmk+kernel@arm.linux.org.uk> wrote:
>> > Subsystems such as ALSA, DRM and others require a single card-level
>> > device structure to represent a subsystem.  However, firmware tends to
>> > describe the individual devices and the connections between them.
>> >
>> > Therefore, we need a way to gather up the individual component devices
>> > together, and indicate when we have all the component devices.
>> >
>> > We do this in DT by providing a "superdevice" node which specifies
>> > the components, eg:
>> >
>> >         imx-drm {
>> >                 compatible = "fsl,drm";
>> >                 crtcs = <&ipu1>;
>> >                 connectors = <&hdmi>;
>> >         };
>> >
>>
>> Hi Russell,
>> This looks really good. I'd definitely like to use it for the exynos
>> drm driver both to bind the various IP blocks together, and also to
>> pull in any attached bridges that are specified in the device tree.
>> Along those lines, it might be worthwhile to pull some of the master
>> bind functionality in your next patch into drm helpers so other
>> drivers can use them, and so we have concrete bindings across drm.
>
> Which bits do you think would be useful to move into the core?
> imx_drm_add_components() is rather imx-drm specific, especially for
> the CRTCs - it carries the knowledge that the OF device to be matched
> can be found in the _parent_ device, rather than the device registered
> into the component helpers.
>

Yeah, I was thinking of imx_drm_add_components() actually. It probably
doesn't make sense to enforce the parent relationship in a generic
manner, but it would be nice to have a helper which added the various
drm components (crtc/encoder/bridge/connector) with a consistent
binding.

We have 3 different exynos boards which would have the following
superdevices (please forgive my hypothetical syntax/naming):

Board 1:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        bridges = <&ptn3460 &dp1>;
        connectors = <&ptn3460>, <&hdmi1>;
};

Board 2:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        bridges = <&ps8622 &dp1>, <&anx7808 &hdmi1>;
        connectors = <&ps8622>, <&anx7808>;
};

Board 3:
exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>, <&mixer1>;
        encoders = <&dp1>, <&hdmi1>;
        connectors = <&dp1>, <&hdmi1>;
};

In addition to enforcing common bindings across drivers, we could also
assign bridges to encoders from the dt. The bridge->encoder
relationship is 1:1 at the moment, and the bridge driver can be a
completely separate entity from the encoder. Allowing assignment from
the dt means the encoder never needs to know whether a bridge is
connected.

Right now the encoder must enumerate all possible bridges to see if
they are present (check out "[PATCH v3 31/32] drm/exynos: Move lvds
bridge discovery into DP driver" for an example of what I mean).

Sean

> --
> FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
> in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
> Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-08 22:39         ` Sean Paul
@ 2014-01-09  7:40           ` Sascha Hauer
  -1 siblings, 0 replies; 219+ messages in thread
From: Sascha Hauer @ 2014-01-09  7:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 08, 2014 at 05:39:31PM -0500, Sean Paul wrote:
> On Wed, Jan 8, 2014 at 4:36 PM, Russell King - ARM Linux
> > Which bits do you think would be useful to move into the core?
> > imx_drm_add_components() is rather imx-drm specific, especially for
> > the CRTCs - it carries the knowledge that the OF device to be matched
> > can be found in the _parent_ device, rather than the device registered
> > into the component helpers.
> >
> 
> Yeah, I was thinking of imx_drm_add_components() actually. It probably
> doesn't make sense to enforce the parent relationship in a generic
> manner, but it would be nice to have a helper which added the various
> drm components (crtc/encoder/bridge/connector) with a consistent
> binding.
> 
> We have 3 different exynos boards which would have the following
> superdevices (please forgive my hypothetical syntax/naming):
> 
> Board 1:
> exynos-drm {
>         compatible = "exynos,drm";
>         crtcs = <&fimd1>, <&mixer1>;
>         encoders = <&dp1>, <&hdmi1>;
>         bridges = <&ptn3460 &dp1>;
>         connectors = <&ptn3460>, <&hdmi1>;
> };

Can we have an example with a different number of
encoders/connectors/crtcs, like:

exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>;
        encoders = <&dp1>, <&hdmi1>, <&lvds1>;
        connectors = <&ptn3460>, <&hdmi1>;
};

Otherwise I get the impression that there is some topology of the
components or at least relationship between the components encoded
into the binding.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-09  7:40           ` Sascha Hauer
  0 siblings, 0 replies; 219+ messages in thread
From: Sascha Hauer @ 2014-01-09  7:40 UTC (permalink / raw)
  To: Sean Paul
  Cc: devel, Russell King - ARM Linux, Greg Kroah-Hartman, dri-devel,
	Sascha Hauer, Linux ARM Kernel

On Wed, Jan 08, 2014 at 05:39:31PM -0500, Sean Paul wrote:
> On Wed, Jan 8, 2014 at 4:36 PM, Russell King - ARM Linux
> > Which bits do you think would be useful to move into the core?
> > imx_drm_add_components() is rather imx-drm specific, especially for
> > the CRTCs - it carries the knowledge that the OF device to be matched
> > can be found in the _parent_ device, rather than the device registered
> > into the component helpers.
> >
> 
> Yeah, I was thinking of imx_drm_add_components() actually. It probably
> doesn't make sense to enforce the parent relationship in a generic
> manner, but it would be nice to have a helper which added the various
> drm components (crtc/encoder/bridge/connector) with a consistent
> binding.
> 
> We have 3 different exynos boards which would have the following
> superdevices (please forgive my hypothetical syntax/naming):
> 
> Board 1:
> exynos-drm {
>         compatible = "exynos,drm";
>         crtcs = <&fimd1>, <&mixer1>;
>         encoders = <&dp1>, <&hdmi1>;
>         bridges = <&ptn3460 &dp1>;
>         connectors = <&ptn3460>, <&hdmi1>;
> };

Can we have an example with a different number of
encoders/connectors/crtcs, like:

exynos-drm {
        compatible = "exynos,drm";
        crtcs = <&fimd1>;
        encoders = <&dp1>, <&hdmi1>, <&lvds1>;
        connectors = <&ptn3460>, <&hdmi1>;
};

Otherwise I get the impression that there is some topology of the
components or at least relationship between the components encoded
into the binding.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH RFC 00/46] Preview of imx-drm cleanup series
  2014-01-07  6:33   ` Shawn Guo
@ 2014-01-09 13:17     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-09 13:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jan 07, 2014 at 02:33:22PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:25:28PM +0000, Russell King - ARM Linux wrote:
> > Here is my large patch series which cleans up imx-drm, and gets it ready
> > to move out of drivers/staging.  This is a preview only.
> 
> When moving to non-RFC patches, you may want to run checkpatch.pl on the
> patches.  There are some errors and warnings than just "line over 80
> characters" one.

I'm going to fix some of them, but I'm not fixing all of them.  The
reason is that some of these should have been done to the code already,
and I'm not going to mess up my patches integrating coding style fixes
amongst moving code around.

The warnings about "over 80 characters" are fine for new code but not
when code is merely being moved - there it's far more important not to
reformat code.

The errors you refer to are:
(a) in Fabio's patch adding imx-hdmi support, a derivative of which has
    already been accepted into the staging tree.
(b) in ipuv3-crtc.c, where checkpatch detects the presence of the FSF
    address in the context of my patch.

So, these are not my problem to fix, and I will *not* fix these "errors"
in this series.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 00/46] Preview of imx-drm cleanup series
@ 2014-01-09 13:17     ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-09 13:17 UTC (permalink / raw)
  To: Shawn Guo
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Tue, Jan 07, 2014 at 02:33:22PM +0800, Shawn Guo wrote:
> On Thu, Jan 02, 2014 at 09:25:28PM +0000, Russell King - ARM Linux wrote:
> > Here is my large patch series which cleans up imx-drm, and gets it ready
> > to move out of drivers/staging.  This is a preview only.
> 
> When moving to non-RFC patches, you may want to run checkpatch.pl on the
> patches.  There are some errors and warnings than just "line over 80
> characters" one.

I'm going to fix some of them, but I'm not fixing all of them.  The
reason is that some of these should have been done to the code already,
and I'm not going to mess up my patches integrating coding style fixes
amongst moving code around.

The warnings about "over 80 characters" are fine for new code but not
when code is merely being moved - there it's far more important not to
reformat code.

The errors you refer to are:
(a) in Fabio's patch adding imx-hdmi support, a derivative of which has
    already been accepted into the staging tree.
(b) in ipuv3-crtc.c, where checkpatch detects the presence of the FSF
    address in the context of my patch.

So, these are not my problem to fix, and I will *not* fix these "errors"
in this series.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-08 21:32       ` Russell King - ARM Linux
@ 2014-01-09 15:25         ` Shawn Guo
  -1 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-09 15:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 08, 2014 at 09:32:58PM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 07, 2014 at 04:59:35PM +0800, Shawn Guo wrote:
> > On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> > > diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > index e75e11b36dff..0e005f21d241 100644
> > > --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > @@ -62,6 +62,12 @@
> > >  		};
> > >  	};
> > >  
> > > +	imx-drm {
> > > +		compatible = "fsl,imx-drm";
> > > +		crtcs = <&ipu1 0>, <&ipu1 1>;
> > > +		connectors = <&ldb>;
> > > +	};
> > > +
> > 
> > While the change works fine on imx6dl, it breaks LVDS support on imx6q
> > right away.
> > 
> > imx-ipuv3 2400000.ipu: IPUv3H probed
> > imx-ipuv3 2800000.ipu: IPUv3H probed
> > [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
> > [drm] No driver support for vblank timestamp query.
> > imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
> > imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
> > imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517
> > 
> > Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
> > defines only 2 in there, the imx_drm_encoder_parse_of() call from
> > imx_ldb_register() will always return -EPROBE_DEFER.
> > 
> >         lvds-channel at 0 {
> >                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
> >         };
> > 
> >         lvds-channel at 1 {
> >                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
> >         };
> 
> This is why some help would be useful here - I think I got these right
> but I've no way to check them.
> 
> Can you confirm that adding all four is the right thing not only for
> the imx6q but also the imx6dl sabresd please?

Yea, adding all four into imx-drm crtcs works for imx6q, but it doesn't
for imx6dl, because &ipu2 is unavailable for imx6dl at all.

Here is how I get around it.

---8<-----------

diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts
index 9cbdfe7..66f220a 100644
--- a/arch/arm/boot/dts/imx6q-sabresd.dts
+++ b/arch/arm/boot/dts/imx6q-sabresd.dts
@@ -20,6 +20,10 @@
        compatible = "fsl,imx6q-sabresd", "fsl,imx6q";
 };

+&imx_drm {
+       crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
+
 &sata {
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 0e005f2..dfca3e0 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -62,7 +62,7 @@
                };
        };

-       imx-drm {
+       imx_drm: imx-drm {
                compatible = "fsl,imx-drm";
                crtcs = <&ipu1 0>, <&ipu1 1>;
                connectors = <&ldb>;

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-09 15:25         ` Shawn Guo
  0 siblings, 0 replies; 219+ messages in thread
From: Shawn Guo @ 2014-01-09 15:25 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Wed, Jan 08, 2014 at 09:32:58PM +0000, Russell King - ARM Linux wrote:
> On Tue, Jan 07, 2014 at 04:59:35PM +0800, Shawn Guo wrote:
> > On Thu, Jan 02, 2014 at 09:28:03PM +0000, Russell King wrote:
> > > diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > index e75e11b36dff..0e005f21d241 100644
> > > --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
> > > @@ -62,6 +62,12 @@
> > >  		};
> > >  	};
> > >  
> > > +	imx-drm {
> > > +		compatible = "fsl,imx-drm";
> > > +		crtcs = <&ipu1 0>, <&ipu1 1>;
> > > +		connectors = <&ldb>;
> > > +	};
> > > +
> > 
> > While the change works fine on imx6dl, it breaks LVDS support on imx6q
> > right away.
> > 
> > imx-ipuv3 2400000.ipu: IPUv3H probed
> > imx-ipuv3 2800000.ipu: IPUv3H probed
> > [drm] Supports vblank timestamp caching Rev 2 (21.10.2013).
> > [drm] No driver support for vblank timestamp query.
> > imx-drm imx-drm.16: bound imx-ipuv3-crtc.0 (ops ipu_crtc_ops)
> > imx-drm imx-drm.16: bound imx-ipuv3-crtc.1 (ops ipu_crtc_ops)
> > imx-drm imx-drm.16: failed to bind ldb.10 (ops imx_ldb_ops): -517
> > 
> > Because we have 4 crtcs for lvds-channel on imx6q while imx-drm master
> > defines only 2 in there, the imx_drm_encoder_parse_of() call from
> > imx_ldb_register() will always return -EPROBE_DEFER.
> > 
> >         lvds-channel@0 {
> >                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
> >         };
> > 
> >         lvds-channel@1 {
> >                 crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
> >         };
> 
> This is why some help would be useful here - I think I got these right
> but I've no way to check them.
> 
> Can you confirm that adding all four is the right thing not only for
> the imx6q but also the imx6dl sabresd please?

Yea, adding all four into imx-drm crtcs works for imx6q, but it doesn't
for imx6dl, because &ipu2 is unavailable for imx6dl at all.

Here is how I get around it.

---8<-----------

diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts
index 9cbdfe7..66f220a 100644
--- a/arch/arm/boot/dts/imx6q-sabresd.dts
+++ b/arch/arm/boot/dts/imx6q-sabresd.dts
@@ -20,6 +20,10 @@
        compatible = "fsl,imx6q-sabresd", "fsl,imx6q";
 };

+&imx_drm {
+       crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
+};
+
 &sata {
        status = "okay";
 };
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 0e005f2..dfca3e0 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -62,7 +62,7 @@
                };
        };

-       imx-drm {
+       imx_drm: imx-drm {
                compatible = "fsl,imx-drm";
                crtcs = <&ipu1 0>, <&ipu1 1>;
                connectors = <&ldb>;

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

* [PATCH RFC 27/46] imx-drm: convert to componentised device support
  2014-01-09 15:25         ` Shawn Guo
@ 2014-01-09 15:33           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-09 15:33 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 09, 2014 at 11:25:38PM +0800, Shawn Guo wrote:
> Yea, adding all four into imx-drm crtcs works for imx6q, but it doesn't
> for imx6dl, because &ipu2 is unavailable for imx6dl at all.
> 
> Here is how I get around it.

Thanks, I've rolled your change into this commit now.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 27/46] imx-drm: convert to componentised device support
@ 2014-01-09 15:33           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-09 15:33 UTC (permalink / raw)
  To: Shawn Guo
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	linux-arm-kernel

On Thu, Jan 09, 2014 at 11:25:38PM +0800, Shawn Guo wrote:
> Yea, adding all four into imx-drm crtcs works for imx6q, but it doesn't
> for imx6dl, because &ipu2 is unavailable for imx6dl at all.
> 
> Here is how I get around it.

Thanks, I've rolled your change into this commit now.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-03  3:10     ` Greg Kroah-Hartman
@ 2014-01-10 14:54       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 14:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> > 
> > The superdevice is declared into the component support, along with the
> > subcomponents.  The superdevice receives callbacks to locate the
> > subcomponents, and identify when all components are present.  At this
> > point, we bind the superdevice, which causes the appropriate subsystem
> > to be initialised in the conventional way.
> > 
> > When any of the components or superdevice are removed from the system,
> > we unbind the superdevice, thereby taking the subsystem down.
> 
> This sounds a lot like the "containers" code that Rafael just submitted
> and I acked for 3.14.  Look at the lkml post:
> 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> 
> And see if that could possibly be used instead?

Greg,

Not sure if you saw the outcome to your comment above.  My conclusion
was:

"Yes, I'm coming to that conclusion as well.  It looks like your "containers"
aren't about collecting up several individual component devices into one
super-device and probing the appropriate subsystem when all components are
known.

"Confused why Greg is pointing me at your patches."

Does this mean you're happy with the patch?

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 14:54       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 14:54 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> > 
> > The superdevice is declared into the component support, along with the
> > subcomponents.  The superdevice receives callbacks to locate the
> > subcomponents, and identify when all components are present.  At this
> > point, we bind the superdevice, which causes the appropriate subsystem
> > to be initialised in the conventional way.
> > 
> > When any of the components or superdevice are removed from the system,
> > we unbind the superdevice, thereby taking the subsystem down.
> 
> This sounds a lot like the "containers" code that Rafael just submitted
> and I acked for 3.14.  Look at the lkml post:
> 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> 
> And see if that could possibly be used instead?

Greg,

Not sure if you saw the outcome to your comment above.  My conclusion
was:

"Yes, I'm coming to that conclusion as well.  It looks like your "containers"
aren't about collecting up several individual component devices into one
super-device and probing the appropriate subsystem when all components are
known.

"Confused why Greg is pointing me at your patches."

Does this mean you're happy with the patch?

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 14:54       ` Russell King - ARM Linux
@ 2014-01-10 15:07         ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 15:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > > 
> > > The superdevice is declared into the component support, along with the
> > > subcomponents.  The superdevice receives callbacks to locate the
> > > subcomponents, and identify when all components are present.  At this
> > > point, we bind the superdevice, which causes the appropriate subsystem
> > > to be initialised in the conventional way.
> > > 
> > > When any of the components or superdevice are removed from the system,
> > > we unbind the superdevice, thereby taking the subsystem down.
> > 
> > This sounds a lot like the "containers" code that Rafael just submitted
> > and I acked for 3.14.  Look at the lkml post:
> > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > 
> > And see if that could possibly be used instead?
> 
> Greg,
> 
> Not sure if you saw the outcome to your comment above.  My conclusion
> was:
> 
> "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> aren't about collecting up several individual component devices into one
> super-device and probing the appropriate subsystem when all components are
> known.
> 
> "Confused why Greg is pointing me at your patches."

Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.

> Does this mean you're happy with the patch?

Well, I will not object to it on the grounds of it being a duplicate of
Rafael's work now :)

I'll be glad to consider it on its own, when you feel the series is
ready to be submitted.

thanks,

greg k-h

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 15:07         ` Greg Kroah-Hartman
  0 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 15:07 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> On Thu, Jan 02, 2014 at 07:10:55PM -0800, Greg Kroah-Hartman wrote:
> > On Thu, Jan 02, 2014 at 09:27:58PM +0000, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > > 
> > > The superdevice is declared into the component support, along with the
> > > subcomponents.  The superdevice receives callbacks to locate the
> > > subcomponents, and identify when all components are present.  At this
> > > point, we bind the superdevice, which causes the appropriate subsystem
> > > to be initialised in the conventional way.
> > > 
> > > When any of the components or superdevice are removed from the system,
> > > we unbind the superdevice, thereby taking the subsystem down.
> > 
> > This sounds a lot like the "containers" code that Rafael just submitted
> > and I acked for 3.14.  Look at the lkml post:
> > 	Subject: [PATCH 2/2] ACPI / hotplug / driver core: Handle containers in a special way
> > 	Message-ID: <1991202.gilW172FBV@vostro.rjw.lan>
> > 
> > And see if that could possibly be used instead?
> 
> Greg,
> 
> Not sure if you saw the outcome to your comment above.  My conclusion
> was:
> 
> "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> aren't about collecting up several individual component devices into one
> super-device and probing the appropriate subsystem when all components are
> known.
> 
> "Confused why Greg is pointing me at your patches."

Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.

> Does this mean you're happy with the patch?

Well, I will not object to it on the grounds of it being a duplicate of
Rafael's work now :)

I'll be glad to consider it on its own, when you feel the series is
ready to be submitted.

thanks,

greg k-h

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 15:07         ` Greg Kroah-Hartman
@ 2014-01-10 15:11           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 15:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > Greg,
> > 
> > Not sure if you saw the outcome to your comment above.  My conclusion
> > was:
> > 
> > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > aren't about collecting up several individual component devices into one
> > super-device and probing the appropriate subsystem when all components are
> > known.
> > 
> > "Confused why Greg is pointing me at your patches."
> 
> Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> 
> > Does this mean you're happy with the patch?
> 
> Well, I will not object to it on the grounds of it being a duplicate of
> Rafael's work now :)
> 
> I'll be glad to consider it on its own, when you feel the series is
> ready to be submitted.

I'll sort out a new set of patches today, along with a branch to pull if
you wish to take them that way.

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 15:11           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 15:11 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > Greg,
> > 
> > Not sure if you saw the outcome to your comment above.  My conclusion
> > was:
> > 
> > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > aren't about collecting up several individual component devices into one
> > super-device and probing the appropriate subsystem when all components are
> > known.
> > 
> > "Confused why Greg is pointing me at your patches."
> 
> Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> 
> > Does this mean you're happy with the patch?
> 
> Well, I will not object to it on the grounds of it being a duplicate of
> Rafael's work now :)
> 
> I'll be glad to consider it on its own, when you feel the series is
> ready to be submitted.

I'll sort out a new set of patches today, along with a branch to pull if
you wish to take them that way.

Thanks.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 15:11           ` Russell King - ARM Linux
@ 2014-01-10 15:35             ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 15:35 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 03:11:23PM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> > On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > > Greg,
> > > 
> > > Not sure if you saw the outcome to your comment above.  My conclusion
> > > was:
> > > 
> > > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > > aren't about collecting up several individual component devices into one
> > > super-device and probing the appropriate subsystem when all components are
> > > known.
> > > 
> > > "Confused why Greg is pointing me at your patches."
> > 
> > Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> > 
> > > Does this mean you're happy with the patch?
> > 
> > Well, I will not object to it on the grounds of it being a duplicate of
> > Rafael's work now :)
> > 
> > I'll be glad to consider it on its own, when you feel the series is
> > ready to be submitted.
> 
> I'll sort out a new set of patches today, along with a branch to pull if
> you wish to take them that way.

It's too late for 3.14, as my tree is now closed for that because 3.13
should be out this weekend.  But I'll be glad to queue them up after
3.14-rc1 is out.

thanks,

greg k-h

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 15:35             ` Greg Kroah-Hartman
  0 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 15:35 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 03:11:23PM +0000, Russell King - ARM Linux wrote:
> On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> > On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > > Greg,
> > > 
> > > Not sure if you saw the outcome to your comment above.  My conclusion
> > > was:
> > > 
> > > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > > aren't about collecting up several individual component devices into one
> > > super-device and probing the appropriate subsystem when all components are
> > > known.
> > > 
> > > "Confused why Greg is pointing me at your patches."
> > 
> > Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> > 
> > > Does this mean you're happy with the patch?
> > 
> > Well, I will not object to it on the grounds of it being a duplicate of
> > Rafael's work now :)
> > 
> > I'll be glad to consider it on its own, when you feel the series is
> > ready to be submitted.
> 
> I'll sort out a new set of patches today, along with a branch to pull if
> you wish to take them that way.

It's too late for 3.14, as my tree is now closed for that because 3.13
should be out this weekend.  But I'll be glad to queue them up after
3.14-rc1 is out.

thanks,

greg k-h

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 15:35             ` Greg Kroah-Hartman
@ 2014-01-10 16:04               ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 03:11:23PM +0000, Russell King - ARM Linux wrote:
> > On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> > > On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > > > Greg,
> > > > 
> > > > Not sure if you saw the outcome to your comment above.  My conclusion
> > > > was:
> > > > 
> > > > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > > > aren't about collecting up several individual component devices into one
> > > > super-device and probing the appropriate subsystem when all components are
> > > > known.
> > > > 
> > > > "Confused why Greg is pointing me at your patches."
> > > 
> > > Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> > > 
> > > > Does this mean you're happy with the patch?
> > > 
> > > Well, I will not object to it on the grounds of it being a duplicate of
> > > Rafael's work now :)
> > > 
> > > I'll be glad to consider it on its own, when you feel the series is
> > > ready to be submitted.
> > 
> > I'll sort out a new set of patches today, along with a branch to pull if
> > you wish to take them that way.
> 
> It's too late for 3.14, as my tree is now closed for that because 3.13
> should be out this weekend.  But I'll be glad to queue them up after
> 3.14-rc1 is out.

That's rather annoying... I'll not put effort into this for a few months
then.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 16:04               ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 16:04 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, David Airlie, Rafael J. Wysocki, dri-devel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 03:11:23PM +0000, Russell King - ARM Linux wrote:
> > On Fri, Jan 10, 2014 at 07:07:02AM -0800, Greg Kroah-Hartman wrote:
> > > On Fri, Jan 10, 2014 at 02:54:44PM +0000, Russell King - ARM Linux wrote:
> > > > Greg,
> > > > 
> > > > Not sure if you saw the outcome to your comment above.  My conclusion
> > > > was:
> > > > 
> > > > "Yes, I'm coming to that conclusion as well.  It looks like your "containers"
> > > > aren't about collecting up several individual component devices into one
> > > > super-device and probing the appropriate subsystem when all components are
> > > > known.
> > > > 
> > > > "Confused why Greg is pointing me at your patches."
> > > 
> > > Ah, sorry, I missed that in my "catch up on 2 weeks of email" flood.
> > > 
> > > > Does this mean you're happy with the patch?
> > > 
> > > Well, I will not object to it on the grounds of it being a duplicate of
> > > Rafael's work now :)
> > > 
> > > I'll be glad to consider it on its own, when you feel the series is
> > > ready to be submitted.
> > 
> > I'll sort out a new set of patches today, along with a branch to pull if
> > you wish to take them that way.
> 
> It's too late for 3.14, as my tree is now closed for that because 3.13
> should be out this weekend.  But I'll be glad to queue them up after
> 3.14-rc1 is out.

That's rather annoying... I'll not put effort into this for a few months
then.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 15:35             ` Greg Kroah-Hartman
@ 2014-01-10 18:30               ` Robert Schwebel
  -1 siblings, 0 replies; 219+ messages in thread
From: Robert Schwebel @ 2014-01-10 18:30 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > I'll sort out a new set of patches today, along with a branch to pull if
> > you wish to take them that way.
> 
> It's too late for 3.14, as my tree is now closed for that because 3.13
> should be out this weekend.  But I'll be glad to queue them up after
> 3.14-rc1 is out.

Didnt' Linus say there would be an -rc8?

However - there is a devicetree issue to be discussed anyway (see
Sascha's comment). Although we'd personally like to see this series
being merged sooner than later, it should be sorted out first.
Devicetree issues are ugly to change once they are in mainline.

rsc
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 18:30               ` Robert Schwebel
  0 siblings, 0 replies; 219+ messages in thread
From: Robert Schwebel @ 2014-01-10 18:30 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, Russell King - ARM Linux, Rafael J. Wysocki, dri-devel,
	Sascha Hauer, linux-arm-kernel

On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > I'll sort out a new set of patches today, along with a branch to pull if
> > you wish to take them that way.
> 
> It's too late for 3.14, as my tree is now closed for that because 3.13
> should be out this weekend.  But I'll be glad to queue them up after
> 3.14-rc1 is out.

Didnt' Linus say there would be an -rc8?

However - there is a devicetree issue to be discussed anyway (see
Sascha's comment). Although we'd personally like to see this series
being merged sooner than later, it should be sorted out first.
Devicetree issues are ugly to change once they are in mainline.

rsc
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 18:30               ` Robert Schwebel
@ 2014-01-10 20:42                 ` Greg Kroah-Hartman
  -1 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 20:42 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 07:30:21PM +0100, Robert Schwebel wrote:
> On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > > I'll sort out a new set of patches today, along with a branch to pull if
> > > you wish to take them that way.
> > 
> > It's too late for 3.14, as my tree is now closed for that because 3.13
> > should be out this weekend.  But I'll be glad to queue them up after
> > 3.14-rc1 is out.
> 
> Didnt' Linus say there would be an -rc8?

Ah, you are right, nevermind then :)

Russell, if you want to send me just the driver core patch, I can take
that now and get that into 3.14 so that you don't have any cross-tree
dependancies on the rest of this patch series.

thanks,

greg k-h

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 20:42                 ` Greg Kroah-Hartman
  0 siblings, 0 replies; 219+ messages in thread
From: Greg Kroah-Hartman @ 2014-01-10 20:42 UTC (permalink / raw)
  To: Robert Schwebel
  Cc: devel, Russell King - ARM Linux, David Airlie, Rafael J. Wysocki,
	dri-devel, Sascha Hauer, Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 07:30:21PM +0100, Robert Schwebel wrote:
> On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > > I'll sort out a new set of patches today, along with a branch to pull if
> > > you wish to take them that way.
> > 
> > It's too late for 3.14, as my tree is now closed for that because 3.13
> > should be out this weekend.  But I'll be glad to queue them up after
> > 3.14-rc1 is out.
> 
> Didnt' Linus say there would be an -rc8?

Ah, you are right, nevermind then :)

Russell, if you want to send me just the driver core patch, I can take
that now and get that into 3.14 so that you don't have any cross-tree
dependancies on the rest of this patch series.

thanks,

greg k-h

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 20:42                 ` Greg Kroah-Hartman
@ 2014-01-10 23:23                   ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 23:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 12:42:59PM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 07:30:21PM +0100, Robert Schwebel wrote:
> > On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > > > I'll sort out a new set of patches today, along with a branch to pull if
> > > > you wish to take them that way.
> > > 
> > > It's too late for 3.14, as my tree is now closed for that because 3.13
> > > should be out this weekend.  But I'll be glad to queue them up after
> > > 3.14-rc1 is out.
> > 
> > Didnt' Linus say there would be an -rc8?
> 
> Ah, you are right, nevermind then :)
> 
> Russell, if you want to send me just the driver core patch, I can take
> that now and get that into 3.14 so that you don't have any cross-tree
> dependancies on the rest of this patch series.

Thanks, here it is.  Only change from the previously posted one is a
few checkpatch cleanups.

8<===
From: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH] drivers/base: provide an infrastructure for componentised
 subsystems

Subsystems such as ALSA, DRM and others require a single card-level
device structure to represent a subsystem.  However, firmware tends to
describe the individual devices and the connections between them.

Therefore, we need a way to gather up the individual component devices
together, and indicate when we have all the component devices.

We do this in DT by providing a "superdevice" node which specifies
the components, eg:

	imx-drm {
		compatible = "fsl,drm";
		crtcs = <&ipu1>;
		connectors = <&hdmi>;
	};

The superdevice is declared into the component support, along with the
subcomponents.  The superdevice receives callbacks to locate the
subcomponents, and identify when all components are present.  At this
point, we bind the superdevice, which causes the appropriate subsystem
to be initialised in the conventional way.

When any of the components or superdevice are removed from the system,
we unbind the superdevice, thereby taking the subsystem down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/base/Makefile     |   2 +-
 drivers/base/component.c  | 382 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/component.h |  32 ++++
 3 files changed, 415 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 include/linux/component.h

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80e87f8..870ecfd503af 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o bus.o dd.o syscore.o \
+obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
diff --git a/drivers/base/component.c b/drivers/base/component.c
new file mode 100644
index 000000000000..c53efe6c6d8e
--- /dev/null
+++ b/drivers/base/component.c
@@ -0,0 +1,382 @@
+/*
+ * Componentized device handling.
+ *
+ * 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.
+ *
+ * This is work in progress.  We gather up the component devices into a list,
+ * and bind them when instructed.  At the moment, we're specific to the DRM
+ * subsystem, and only handles one master device, but this doesn't have to be
+ * the case.
+ */
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+struct master {
+	struct list_head node;
+	struct list_head components;
+	bool bound;
+
+	const struct component_master_ops *ops;
+	struct device *dev;
+};
+
+struct component {
+	struct list_head node;
+	struct list_head master_node;
+	struct master *master;
+	bool bound;
+
+	const struct component_ops *ops;
+	struct device *dev;
+};
+
+static DEFINE_MUTEX(component_mutex);
+static LIST_HEAD(component_list);
+static LIST_HEAD(masters);
+
+static struct master *__master_find(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *m;
+
+	list_for_each_entry(m, &masters, node)
+		if (m->dev == dev && (!ops || m->ops == ops))
+			return m;
+
+	return NULL;
+}
+
+/* Attach an unattached component to a master. */
+static void component_attach_master(struct master *master, struct component *c)
+{
+	c->master = master;
+
+	list_add_tail(&c->master_node, &master->components);
+}
+
+/* Detach a component from a master. */
+static void component_detach_master(struct master *master, struct component *c)
+{
+	list_del(&c->master_node);
+
+	c->master = NULL;
+}
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data)
+{
+	struct component *c;
+	int ret = -ENXIO;
+
+	list_for_each_entry(c, &component_list, node) {
+		if (c->master)
+			continue;
+
+		if (compare(c->dev, compare_data)) {
+			component_attach_master(master, c);
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_master_add_child);
+
+/* Detach all attached components from this master */
+static void master_remove_components(struct master *master)
+{
+	while (!list_empty(&master->components)) {
+		struct component *c = list_first_entry(&master->components,
+					struct component, master_node);
+
+		WARN_ON(c->master != master);
+
+		component_detach_master(master, c);
+	}
+}
+
+/*
+ * Try to bring up a master.  If component is NULL, we're interested in
+ * this master, otherwise it's a component which must be present to try
+ * and bring up the master.
+ *
+ * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
+ */
+static int try_to_bring_up_master(struct master *master,
+	struct component *component)
+{
+	int ret = 0;
+
+	if (!master->bound) {
+		/*
+		 * Search the list of components, looking for components that
+		 * belong to this master, and attach them to the master.
+		 */
+		if (master->ops->add_components(master->dev, master)) {
+			/* Failed to find all components */
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		if (component && component->master != master) {
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		/* Found all components */
+		ret = master->ops->bind(master->dev);
+		if (ret < 0) {
+			master_remove_components(master);
+			goto out;
+		}
+
+		master->bound = true;
+		ret = 1;
+	}
+out:
+
+	return ret;
+}
+
+static int try_to_bring_up_masters(struct component *component)
+{
+	struct master *m;
+	int ret = 0;
+
+	list_for_each_entry(m, &masters, node) {
+		ret = try_to_bring_up_master(m, component);
+		if (ret != 0)
+			break;
+	}
+
+	return ret;
+}
+
+static void take_down_master(struct master *master)
+{
+	if (master->bound) {
+		master->ops->unbind(master->dev);
+		master->bound = false;
+	}
+
+	master_remove_components(master);
+}
+
+int component_master_add(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *master;
+	int ret;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return -ENOMEM;
+
+	master->dev = dev;
+	master->ops = ops;
+	INIT_LIST_HEAD(&master->components);
+
+	/* Add to the list of available masters. */
+	mutex_lock(&component_mutex);
+	list_add(&master->node, &masters);
+
+	ret = try_to_bring_up_master(master, NULL);
+
+	if (ret < 0) {
+		/* Delete off the list if we weren't successful */
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_master_add);
+
+void component_master_del(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *master;
+
+	mutex_lock(&component_mutex);
+	master = __master_find(dev, ops);
+	if (master) {
+		take_down_master(master);
+
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+}
+EXPORT_SYMBOL_GPL(component_master_del);
+
+static void component_unbind(struct component *component,
+	struct master *master, void *data)
+{
+	WARN_ON(!component->bound);
+
+	component->ops->unbind(component->dev, master->dev, data);
+	component->bound = false;
+
+	/* Release all resources claimed in the binding of this component */
+	devres_release_group(component->dev, component);
+}
+
+void component_unbind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return;
+
+	list_for_each_entry_reverse(c, &master->components, master_node)
+		component_unbind(c, master, data);
+}
+EXPORT_SYMBOL_GPL(component_unbind_all);
+
+static int component_bind(struct component *component, struct master *master,
+	void *data)
+{
+	int ret;
+
+	/*
+	 * Each component initialises inside its own devres group.
+	 * This allows us to roll-back a failed component without
+	 * affecting anything else.
+	 */
+	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	/*
+	 * Also open a group for the device itself: this allows us
+	 * to release the resources claimed against the sub-device
+	 * at the appropriate moment.
+	 */
+	if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
+		devres_release_group(master->dev, NULL);
+		return -ENOMEM;
+	}
+
+	dev_dbg(master->dev, "binding %s (ops %ps)\n",
+		dev_name(component->dev), component->ops);
+
+	ret = component->ops->bind(component->dev, master->dev, data);
+	if (!ret) {
+		component->bound = true;
+
+		/*
+		 * Close the component device's group so that resources
+		 * allocated in the binding are encapsulated for removal
+		 * at unbind.  Remove the group on the DRM device as we
+		 * can clean those resources up independently.
+		 */
+		devres_close_group(component->dev, NULL);
+		devres_remove_group(master->dev, NULL);
+
+		dev_info(master->dev, "bound %s (ops %ps)\n",
+			 dev_name(component->dev), component->ops);
+	} else {
+		devres_release_group(component->dev, NULL);
+		devres_release_group(master->dev, NULL);
+
+		dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+			dev_name(component->dev), component->ops, ret);
+	}
+
+	return ret;
+}
+
+int component_bind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+	int ret = 0;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return -EINVAL;
+
+	list_for_each_entry(c, &master->components, master_node) {
+		ret = component_bind(c, master, data);
+		if (ret)
+			break;
+	}
+
+	if (ret != 0) {
+		list_for_each_entry_continue_reverse(c, &master->components,
+						     master_node)
+			component_unbind(c, master, data);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_bind_all);
+
+int component_add(struct device *dev, const struct component_ops *ops)
+{
+	struct component *component;
+	int ret;
+
+	component = kzalloc(sizeof(*component), GFP_KERNEL);
+	if (!component)
+		return -ENOMEM;
+
+	component->ops = ops;
+	component->dev = dev;
+
+	dev_dbg(dev, "adding component (ops %ps)\n", ops);
+
+	mutex_lock(&component_mutex);
+	list_add_tail(&component->node, &component_list);
+
+	ret = try_to_bring_up_masters(component);
+	if (ret < 0) {
+		list_del(&component->node);
+
+		kfree(component);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_add);
+
+void component_del(struct device *dev, const struct component_ops *ops)
+{
+	struct component *c, *component = NULL;
+
+	mutex_lock(&component_mutex);
+	list_for_each_entry(c, &component_list, node)
+		if (c->dev == dev && c->ops == ops) {
+			list_del(&c->node);
+			component = c;
+			break;
+		}
+
+	if (component && component->master)
+		take_down_master(component->master);
+
+	mutex_unlock(&component_mutex);
+
+	WARN_ON(!component);
+	kfree(component);
+}
+EXPORT_SYMBOL_GPL(component_del);
+
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/component.h b/include/linux/component.h
new file mode 100644
index 000000000000..68870182ca1e
--- /dev/null
+++ b/include/linux/component.h
@@ -0,0 +1,32 @@
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+struct device;
+
+struct component_ops {
+	int (*bind)(struct device *, struct device *, void *);
+	void (*unbind)(struct device *, struct device *, void *);
+};
+
+int component_add(struct device *, const struct component_ops *);
+void component_del(struct device *, const struct component_ops *);
+
+int component_bind_all(struct device *, void *);
+void component_unbind_all(struct device *, void *);
+
+struct master;
+
+struct component_master_ops {
+	int (*add_components)(struct device *, struct master *);
+	int (*bind)(struct device *);
+	void (*unbind)(struct device *);
+};
+
+int component_master_add(struct device *, const struct component_master_ops *);
+void component_master_del(struct device *,
+	const struct component_master_ops *);
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data);
+
+#endif
-- 
1.8.3.1


-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-10 23:23                   ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-10 23:23 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: devel, David Airlie, Robert Schwebel, Rafael J. Wysocki,
	dri-devel, Sascha Hauer, Shawn Guo, linux-arm-kernel

On Fri, Jan 10, 2014 at 12:42:59PM -0800, Greg Kroah-Hartman wrote:
> On Fri, Jan 10, 2014 at 07:30:21PM +0100, Robert Schwebel wrote:
> > On Fri, Jan 10, 2014 at 07:35:30AM -0800, Greg Kroah-Hartman wrote:
> > > > I'll sort out a new set of patches today, along with a branch to pull if
> > > > you wish to take them that way.
> > > 
> > > It's too late for 3.14, as my tree is now closed for that because 3.13
> > > should be out this weekend.  But I'll be glad to queue them up after
> > > 3.14-rc1 is out.
> > 
> > Didnt' Linus say there would be an -rc8?
> 
> Ah, you are right, nevermind then :)
> 
> Russell, if you want to send me just the driver core patch, I can take
> that now and get that into 3.14 so that you don't have any cross-tree
> dependancies on the rest of this patch series.

Thanks, here it is.  Only change from the previously posted one is a
few checkpatch cleanups.

8<===
From: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Subject: [PATCH] drivers/base: provide an infrastructure for componentised
 subsystems

Subsystems such as ALSA, DRM and others require a single card-level
device structure to represent a subsystem.  However, firmware tends to
describe the individual devices and the connections between them.

Therefore, we need a way to gather up the individual component devices
together, and indicate when we have all the component devices.

We do this in DT by providing a "superdevice" node which specifies
the components, eg:

	imx-drm {
		compatible = "fsl,drm";
		crtcs = <&ipu1>;
		connectors = <&hdmi>;
	};

The superdevice is declared into the component support, along with the
subcomponents.  The superdevice receives callbacks to locate the
subcomponents, and identify when all components are present.  At this
point, we bind the superdevice, which causes the appropriate subsystem
to be initialised in the conventional way.

When any of the components or superdevice are removed from the system,
we unbind the superdevice, thereby taking the subsystem down.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/base/Makefile     |   2 +-
 drivers/base/component.c  | 382 ++++++++++++++++++++++++++++++++++++++++++++++
 include/linux/component.h |  32 ++++
 3 files changed, 415 insertions(+), 1 deletion(-)
 create mode 100644 drivers/base/component.c
 create mode 100644 include/linux/component.h

diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 94e8a80e87f8..870ecfd503af 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -1,6 +1,6 @@
 # Makefile for the Linux device tree
 
-obj-y			:= core.o bus.o dd.o syscore.o \
+obj-y			:= component.o core.o bus.o dd.o syscore.o \
 			   driver.o class.o platform.o \
 			   cpu.o firmware.o init.o map.o devres.o \
 			   attribute_container.o transport_class.o \
diff --git a/drivers/base/component.c b/drivers/base/component.c
new file mode 100644
index 000000000000..c53efe6c6d8e
--- /dev/null
+++ b/drivers/base/component.c
@@ -0,0 +1,382 @@
+/*
+ * Componentized device handling.
+ *
+ * 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.
+ *
+ * This is work in progress.  We gather up the component devices into a list,
+ * and bind them when instructed.  At the moment, we're specific to the DRM
+ * subsystem, and only handles one master device, but this doesn't have to be
+ * the case.
+ */
+#include <linux/component.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+struct master {
+	struct list_head node;
+	struct list_head components;
+	bool bound;
+
+	const struct component_master_ops *ops;
+	struct device *dev;
+};
+
+struct component {
+	struct list_head node;
+	struct list_head master_node;
+	struct master *master;
+	bool bound;
+
+	const struct component_ops *ops;
+	struct device *dev;
+};
+
+static DEFINE_MUTEX(component_mutex);
+static LIST_HEAD(component_list);
+static LIST_HEAD(masters);
+
+static struct master *__master_find(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *m;
+
+	list_for_each_entry(m, &masters, node)
+		if (m->dev == dev && (!ops || m->ops == ops))
+			return m;
+
+	return NULL;
+}
+
+/* Attach an unattached component to a master. */
+static void component_attach_master(struct master *master, struct component *c)
+{
+	c->master = master;
+
+	list_add_tail(&c->master_node, &master->components);
+}
+
+/* Detach a component from a master. */
+static void component_detach_master(struct master *master, struct component *c)
+{
+	list_del(&c->master_node);
+
+	c->master = NULL;
+}
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data)
+{
+	struct component *c;
+	int ret = -ENXIO;
+
+	list_for_each_entry(c, &component_list, node) {
+		if (c->master)
+			continue;
+
+		if (compare(c->dev, compare_data)) {
+			component_attach_master(master, c);
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_master_add_child);
+
+/* Detach all attached components from this master */
+static void master_remove_components(struct master *master)
+{
+	while (!list_empty(&master->components)) {
+		struct component *c = list_first_entry(&master->components,
+					struct component, master_node);
+
+		WARN_ON(c->master != master);
+
+		component_detach_master(master, c);
+	}
+}
+
+/*
+ * Try to bring up a master.  If component is NULL, we're interested in
+ * this master, otherwise it's a component which must be present to try
+ * and bring up the master.
+ *
+ * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
+ */
+static int try_to_bring_up_master(struct master *master,
+	struct component *component)
+{
+	int ret = 0;
+
+	if (!master->bound) {
+		/*
+		 * Search the list of components, looking for components that
+		 * belong to this master, and attach them to the master.
+		 */
+		if (master->ops->add_components(master->dev, master)) {
+			/* Failed to find all components */
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		if (component && component->master != master) {
+			master_remove_components(master);
+			ret = 0;
+			goto out;
+		}
+
+		/* Found all components */
+		ret = master->ops->bind(master->dev);
+		if (ret < 0) {
+			master_remove_components(master);
+			goto out;
+		}
+
+		master->bound = true;
+		ret = 1;
+	}
+out:
+
+	return ret;
+}
+
+static int try_to_bring_up_masters(struct component *component)
+{
+	struct master *m;
+	int ret = 0;
+
+	list_for_each_entry(m, &masters, node) {
+		ret = try_to_bring_up_master(m, component);
+		if (ret != 0)
+			break;
+	}
+
+	return ret;
+}
+
+static void take_down_master(struct master *master)
+{
+	if (master->bound) {
+		master->ops->unbind(master->dev);
+		master->bound = false;
+	}
+
+	master_remove_components(master);
+}
+
+int component_master_add(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *master;
+	int ret;
+
+	master = kzalloc(sizeof(*master), GFP_KERNEL);
+	if (!master)
+		return -ENOMEM;
+
+	master->dev = dev;
+	master->ops = ops;
+	INIT_LIST_HEAD(&master->components);
+
+	/* Add to the list of available masters. */
+	mutex_lock(&component_mutex);
+	list_add(&master->node, &masters);
+
+	ret = try_to_bring_up_master(master, NULL);
+
+	if (ret < 0) {
+		/* Delete off the list if we weren't successful */
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_master_add);
+
+void component_master_del(struct device *dev,
+	const struct component_master_ops *ops)
+{
+	struct master *master;
+
+	mutex_lock(&component_mutex);
+	master = __master_find(dev, ops);
+	if (master) {
+		take_down_master(master);
+
+		list_del(&master->node);
+		kfree(master);
+	}
+	mutex_unlock(&component_mutex);
+}
+EXPORT_SYMBOL_GPL(component_master_del);
+
+static void component_unbind(struct component *component,
+	struct master *master, void *data)
+{
+	WARN_ON(!component->bound);
+
+	component->ops->unbind(component->dev, master->dev, data);
+	component->bound = false;
+
+	/* Release all resources claimed in the binding of this component */
+	devres_release_group(component->dev, component);
+}
+
+void component_unbind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return;
+
+	list_for_each_entry_reverse(c, &master->components, master_node)
+		component_unbind(c, master, data);
+}
+EXPORT_SYMBOL_GPL(component_unbind_all);
+
+static int component_bind(struct component *component, struct master *master,
+	void *data)
+{
+	int ret;
+
+	/*
+	 * Each component initialises inside its own devres group.
+	 * This allows us to roll-back a failed component without
+	 * affecting anything else.
+	 */
+	if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+		return -ENOMEM;
+
+	/*
+	 * Also open a group for the device itself: this allows us
+	 * to release the resources claimed against the sub-device
+	 * at the appropriate moment.
+	 */
+	if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
+		devres_release_group(master->dev, NULL);
+		return -ENOMEM;
+	}
+
+	dev_dbg(master->dev, "binding %s (ops %ps)\n",
+		dev_name(component->dev), component->ops);
+
+	ret = component->ops->bind(component->dev, master->dev, data);
+	if (!ret) {
+		component->bound = true;
+
+		/*
+		 * Close the component device's group so that resources
+		 * allocated in the binding are encapsulated for removal
+		 * at unbind.  Remove the group on the DRM device as we
+		 * can clean those resources up independently.
+		 */
+		devres_close_group(component->dev, NULL);
+		devres_remove_group(master->dev, NULL);
+
+		dev_info(master->dev, "bound %s (ops %ps)\n",
+			 dev_name(component->dev), component->ops);
+	} else {
+		devres_release_group(component->dev, NULL);
+		devres_release_group(master->dev, NULL);
+
+		dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
+			dev_name(component->dev), component->ops, ret);
+	}
+
+	return ret;
+}
+
+int component_bind_all(struct device *master_dev, void *data)
+{
+	struct master *master;
+	struct component *c;
+	int ret = 0;
+
+	WARN_ON(!mutex_is_locked(&component_mutex));
+
+	master = __master_find(master_dev, NULL);
+	if (!master)
+		return -EINVAL;
+
+	list_for_each_entry(c, &master->components, master_node) {
+		ret = component_bind(c, master, data);
+		if (ret)
+			break;
+	}
+
+	if (ret != 0) {
+		list_for_each_entry_continue_reverse(c, &master->components,
+						     master_node)
+			component_unbind(c, master, data);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(component_bind_all);
+
+int component_add(struct device *dev, const struct component_ops *ops)
+{
+	struct component *component;
+	int ret;
+
+	component = kzalloc(sizeof(*component), GFP_KERNEL);
+	if (!component)
+		return -ENOMEM;
+
+	component->ops = ops;
+	component->dev = dev;
+
+	dev_dbg(dev, "adding component (ops %ps)\n", ops);
+
+	mutex_lock(&component_mutex);
+	list_add_tail(&component->node, &component_list);
+
+	ret = try_to_bring_up_masters(component);
+	if (ret < 0) {
+		list_del(&component->node);
+
+		kfree(component);
+	}
+	mutex_unlock(&component_mutex);
+
+	return ret < 0 ? ret : 0;
+}
+EXPORT_SYMBOL_GPL(component_add);
+
+void component_del(struct device *dev, const struct component_ops *ops)
+{
+	struct component *c, *component = NULL;
+
+	mutex_lock(&component_mutex);
+	list_for_each_entry(c, &component_list, node)
+		if (c->dev == dev && c->ops == ops) {
+			list_del(&c->node);
+			component = c;
+			break;
+		}
+
+	if (component && component->master)
+		take_down_master(component->master);
+
+	mutex_unlock(&component_mutex);
+
+	WARN_ON(!component);
+	kfree(component);
+}
+EXPORT_SYMBOL_GPL(component_del);
+
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/component.h b/include/linux/component.h
new file mode 100644
index 000000000000..68870182ca1e
--- /dev/null
+++ b/include/linux/component.h
@@ -0,0 +1,32 @@
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+struct device;
+
+struct component_ops {
+	int (*bind)(struct device *, struct device *, void *);
+	void (*unbind)(struct device *, struct device *, void *);
+};
+
+int component_add(struct device *, const struct component_ops *);
+void component_del(struct device *, const struct component_ops *);
+
+int component_bind_all(struct device *, void *);
+void component_unbind_all(struct device *, void *);
+
+struct master;
+
+struct component_master_ops {
+	int (*add_components)(struct device *, struct master *);
+	int (*bind)(struct device *);
+	void (*unbind)(struct device *);
+};
+
+int component_master_add(struct device *, const struct component_master_ops *);
+void component_master_del(struct device *,
+	const struct component_master_ops *);
+
+int component_master_add_child(struct master *master,
+	int (*compare)(struct device *, void *), void *compare_data);
+
+#endif
-- 
1.8.3.1


-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-10 23:23                   ` Russell King - ARM Linux
@ 2014-01-11 11:31                     ` Robert Schwebel
  -1 siblings, 0 replies; 219+ messages in thread
From: Robert Schwebel @ 2014-01-11 11:31 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};

Saschas comment from 20140109074030.GN6750 at pengutronix.de isn't
addressed yet:

Sascha Hauer wrote:
> Can we have an example with a different number of
> encoders/connectors/crtcs, like:
> 
> exynos-drm {
>         compatible = "exynos,drm";
>         crtcs = <&fimd1>;
>         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
>         connectors = <&ptn3460>, <&hdmi1>;
> };
> 
> Otherwise I get the impression that there is some topology of the
> components or at least relationship between the components encoded
> into the binding.

If I remember correctly, Sascha+Philipp+Lucas still had issues with the
bindings, but I'm not sure if they have been already addressed.

It's no good timing to finalize this during the weekend, where most
people are not in the office :)

rsc
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-11 11:31                     ` Robert Schwebel
  0 siblings, 0 replies; 219+ messages in thread
From: Robert Schwebel @ 2014-01-11 11:31 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, Robert Schwebel,
	Rafael J. Wysocki, dri-devel, Sascha Hauer, Shawn Guo,
	linux-arm-kernel

On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};

Saschas comment from 20140109074030.GN6750@pengutronix.de isn't
addressed yet:

Sascha Hauer wrote:
> Can we have an example with a different number of
> encoders/connectors/crtcs, like:
> 
> exynos-drm {
>         compatible = "exynos,drm";
>         crtcs = <&fimd1>;
>         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
>         connectors = <&ptn3460>, <&hdmi1>;
> };
> 
> Otherwise I get the impression that there is some topology of the
> components or at least relationship between the components encoded
> into the binding.

If I remember correctly, Sascha+Philipp+Lucas still had issues with the
bindings, but I'm not sure if they have been already addressed.

It's no good timing to finalize this during the weekend, where most
people are not in the office :)

rsc
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-11 11:31                     ` Robert Schwebel
@ 2014-01-11 11:40                       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-11 11:40 UTC (permalink / raw)
  To: linux-arm-kernel

On Sat, Jan 11, 2014 at 12:31:19PM +0100, Robert Schwebel wrote:
> On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> 
> Saschas comment from 20140109074030.GN6750 at pengutronix.de isn't
> addressed yet:

This is not a comment against _this_ patch.  It was a question for Sean
Paul.  You can tell this by the contents of the To: and Cc: headers on
Sascha's email.  If that's not what was intended, then the email headers
are misleading.

> Sascha Hauer wrote:
> > Can we have an example with a different number of
> > encoders/connectors/crtcs, like:
> > 
> > exynos-drm {
> >         compatible = "exynos,drm";
> >         crtcs = <&fimd1>;
> >         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
> >         connectors = <&ptn3460>, <&hdmi1>;
> > };
> > 
> > Otherwise I get the impression that there is some topology of the
> > components or at least relationship between the components encoded
> > into the binding.
> 
> If I remember correctly, Sascha+Philipp+Lucas still had issues with the
> bindings, but I'm not sure if they have been already addressed.

The bindings are not part of this patch.  This patch doesn't even care
about DT one bit - that's part of the design goal of it.  It doesn't
care about platform devices either.

All it cares about is maintaining lists of struct device pointers,
asking the master device(s) whether they have all their components, and
binding/unbinding the components at the appropriate moment.  It's
completely up to the master device operations to decide how to make
these decisions, and how those decisions are made, whether it be by
looking up in DT, or ACPI, or whatever.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-11 11:40                       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-01-11 11:40 UTC (permalink / raw)
  To: Robert Schwebel
  Cc: devel, David Airlie, Greg Kroah-Hartman, Robert Schwebel,
	Rafael J. Wysocki, dri-devel, Sascha Hauer, Shawn Guo,
	linux-arm-kernel

On Sat, Jan 11, 2014 at 12:31:19PM +0100, Robert Schwebel wrote:
> On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> 
> Saschas comment from 20140109074030.GN6750@pengutronix.de isn't
> addressed yet:

This is not a comment against _this_ patch.  It was a question for Sean
Paul.  You can tell this by the contents of the To: and Cc: headers on
Sascha's email.  If that's not what was intended, then the email headers
are misleading.

> Sascha Hauer wrote:
> > Can we have an example with a different number of
> > encoders/connectors/crtcs, like:
> > 
> > exynos-drm {
> >         compatible = "exynos,drm";
> >         crtcs = <&fimd1>;
> >         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
> >         connectors = <&ptn3460>, <&hdmi1>;
> > };
> > 
> > Otherwise I get the impression that there is some topology of the
> > components or at least relationship between the components encoded
> > into the binding.
> 
> If I remember correctly, Sascha+Philipp+Lucas still had issues with the
> bindings, but I'm not sure if they have been already addressed.

The bindings are not part of this patch.  This patch doesn't even care
about DT one bit - that's part of the design goal of it.  It doesn't
care about platform devices either.

All it cares about is maintaining lists of struct device pointers,
asking the master device(s) whether they have all their components, and
binding/unbinding the components at the appropriate moment.  It's
completely up to the master device operations to decide how to make
these decisions, and how those decisions are made, whether it be by
looking up in DT, or ACPI, or whatever.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-11 11:40                       ` Russell King - ARM Linux
@ 2014-01-13  8:34                         ` Philipp Zabel
  -1 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-13  8:34 UTC (permalink / raw)
  To: linux-arm-kernel

Am Samstag, den 11.01.2014, 11:40 +0000 schrieb Russell King - ARM
Linux:
> On Sat, Jan 11, 2014 at 12:31:19PM +0100, Robert Schwebel wrote:
> > On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > 
> > Saschas comment from 20140109074030.GN6750 at pengutronix.de isn't
> > addressed yet:
> 
> This is not a comment against _this_ patch.  It was a question for Sean
> Paul.  You can tell this by the contents of the To: and Cc: headers on
> Sascha's email.  If that's not what was intended, then the email headers
> are misleading.
> 
> > Sascha Hauer wrote:
> > > Can we have an example with a different number of
> > > encoders/connectors/crtcs, like:
> > > 
> > > exynos-drm {
> > >         compatible = "exynos,drm";
> > >         crtcs = <&fimd1>;
> > >         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
> > >         connectors = <&ptn3460>, <&hdmi1>;
> > > };
> > > 
> > > Otherwise I get the impression that there is some topology of the
> > > components or at least relationship between the components encoded
> > > into the binding.
> > 
> > If I remember correctly, Sascha+Philipp+Lucas still had issues with the
> > bindings, but I'm not sure if they have been already addressed.
> 
> The bindings are not part of this patch.  This patch doesn't even care
> about DT one bit - that's part of the design goal of it.  It doesn't
> care about platform devices either.

Yes, I think the device tree bindings are in need of discussion, but
this is a separate issue. I'd be happy to hear your opinion on the
"imx-drm dt bindings" patches.

> All it cares about is maintaining lists of struct device pointers,
> asking the master device(s) whether they have all their components, and
> binding/unbinding the components at the appropriate moment.  It's
> completely up to the master device operations to decide how to make
> these decisions, and how those decisions are made, whether it be by
> looking up in DT, or ACPI, or whatever.

I'm very much in favor of this particular patch being merged as soon as
sensible.

regards
Philipp

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-01-13  8:34                         ` Philipp Zabel
  0 siblings, 0 replies; 219+ messages in thread
From: Philipp Zabel @ 2014-01-13  8:34 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, Robert Schwebel,
	Rafael J. Wysocki, dri-devel, Robert Schwebel, Sascha Hauer,
	Shawn Guo, linux-arm-kernel

Am Samstag, den 11.01.2014, 11:40 +0000 schrieb Russell King - ARM
Linux:
> On Sat, Jan 11, 2014 at 12:31:19PM +0100, Robert Schwebel wrote:
> > On Fri, Jan 10, 2014 at 11:23:37PM +0000, Russell King - ARM Linux wrote:
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > 
> > Saschas comment from 20140109074030.GN6750@pengutronix.de isn't
> > addressed yet:
> 
> This is not a comment against _this_ patch.  It was a question for Sean
> Paul.  You can tell this by the contents of the To: and Cc: headers on
> Sascha's email.  If that's not what was intended, then the email headers
> are misleading.
> 
> > Sascha Hauer wrote:
> > > Can we have an example with a different number of
> > > encoders/connectors/crtcs, like:
> > > 
> > > exynos-drm {
> > >         compatible = "exynos,drm";
> > >         crtcs = <&fimd1>;
> > >         encoders = <&dp1>, <&hdmi1>, <&lvds1>;
> > >         connectors = <&ptn3460>, <&hdmi1>;
> > > };
> > > 
> > > Otherwise I get the impression that there is some topology of the
> > > components or at least relationship between the components encoded
> > > into the binding.
> > 
> > If I remember correctly, Sascha+Philipp+Lucas still had issues with the
> > bindings, but I'm not sure if they have been already addressed.
> 
> The bindings are not part of this patch.  This patch doesn't even care
> about DT one bit - that's part of the design goal of it.  It doesn't
> care about platform devices either.

Yes, I think the device tree bindings are in need of discussion, but
this is a separate issue. I'd be happy to hear your opinion on the
"imx-drm dt bindings" patches.

> All it cares about is maintaining lists of struct device pointers,
> asking the master device(s) whether they have all their components, and
> binding/unbinding the components at the appropriate moment.  It's
> completely up to the master device operations to decide how to make
> these decisions, and how those decisions are made, whether it be by
> looking up in DT, or ACPI, or whatever.

I'm very much in favor of this particular patch being merged as soon as
sensible.

regards
Philipp

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-02 21:27   ` Russell King
  (?)
@ 2014-02-07  9:04     ` Daniel Vetter
  -1 siblings, 0 replies; 219+ messages in thread
From: Daniel Vetter @ 2014-02-07  9:04 UTC (permalink / raw)
  To: Russell King
  Cc: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo, devel,
	dri-devel, linux-arm-kernel, Hans Verkuil, linux-media,
	Takashi Iwai, alsa-devel

I've chatted a bit with Hans Verkuil about this topic at fosdem and
apparently both v4l and alsa have something like this already in their
helper libraries. Adding more people as fyi in case they want to
switch to the new driver core stuff from Russell.
-Daniel

On Thu, Jan 2, 2014 at 10:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
>
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
>
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
>
>         imx-drm {
>                 compatible = "fsl,drm";
>                 crtcs = <&ipu1>;
>                 connectors = <&hdmi>;
>         };
>
> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
>
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/base/Makefile     |    2 +-
>  drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/component.h |   31 ++++
>  3 files changed, 411 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/base/component.c
>  create mode 100644 include/linux/component.h
>
> diff --git a/drivers/base/Makefile b/drivers/base/Makefile
> index 94e8a80e87f8..870ecfd503af 100644
> --- a/drivers/base/Makefile
> +++ b/drivers/base/Makefile
> @@ -1,6 +1,6 @@
>  # Makefile for the Linux device tree
>
> -obj-y                  := core.o bus.o dd.o syscore.o \
> +obj-y                  := component.o core.o bus.o dd.o syscore.o \
>                            driver.o class.o platform.o \
>                            cpu.o firmware.o init.o map.o devres.o \
>                            attribute_container.o transport_class.o \
> diff --git a/drivers/base/component.c b/drivers/base/component.c
> new file mode 100644
> index 000000000000..5492cd8d2247
> --- /dev/null
> +++ b/drivers/base/component.c
> @@ -0,0 +1,379 @@
> +/*
> + * Componentized device handling.
> + *
> + * 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.
> + *
> + * This is work in progress.  We gather up the component devices into a list,
> + * and bind them when instructed.  At the moment, we're specific to the DRM
> + * subsystem, and only handles one master device, but this doesn't have to be
> + * the case.
> + */
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +struct master {
> +       struct list_head node;
> +       struct list_head components;
> +       bool bound;
> +
> +       const struct component_master_ops *ops;
> +       struct device *dev;
> +};
> +
> +struct component {
> +       struct list_head node;
> +       struct list_head master_node;
> +       struct master *master;
> +       bool bound;
> +
> +       const struct component_ops *ops;
> +       struct device *dev;
> +};
> +
> +static DEFINE_MUTEX(component_mutex);
> +static LIST_HEAD(component_list);
> +static LIST_HEAD(masters);
> +
> +static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *m;
> +
> +       list_for_each_entry(m, &masters, node)
> +               if (m->dev == dev && (!ops || m->ops == ops))
> +                       return m;
> +
> +       return NULL;
> +}
> +
> +/* Attach an unattached component to a master. */
> +static void component_attach_master(struct master *master, struct component *c)
> +{
> +       c->master = master;
> +
> +       list_add_tail(&c->master_node, &master->components);
> +}
> +
> +/* Detach a component from a master. */
> +static void component_detach_master(struct master *master, struct component *c)
> +{
> +       list_del(&c->master_node);
> +
> +       c->master = NULL;
> +}
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data)
> +{
> +       struct component *c;
> +       int ret = -ENXIO;
> +
> +       list_for_each_entry(c, &component_list, node) {
> +               if (c->master)
> +                       continue;
> +
> +               if (compare(c->dev, compare_data)) {
> +                       component_attach_master(master, c);
> +                       ret = 0;
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add_child);
> +
> +/* Detach all attached components from this master */
> +static void master_remove_components(struct master *master)
> +{
> +       while (!list_empty(&master->components)) {
> +               struct component *c = list_first_entry(&master->components,
> +                                       struct component, master_node);
> +
> +               WARN_ON(c->master != master);
> +
> +               component_detach_master(master, c);
> +       }
> +}
> +
> +/*
> + * Try to bring up a master.  If component is NULL, we're interested in
> + * this master, otherwise it's a component which must be present to try
> + * and bring up the master.
> + *
> + * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
> + */
> +static int try_to_bring_up_master(struct master *master,
> +       struct component *component)
> +{
> +       int ret = 0;
> +
> +       if (!master->bound) {
> +               /*
> +                * Search the list of components, looking for components that
> +                * belong to this master, and attach them to the master.
> +                */
> +               if (master->ops->add_components(master->dev, master)) {
> +                       /* Failed to find all components */
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               if (component && component->master != master) {
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               /* Found all components */
> +               ret = master->ops->bind(master->dev);
> +               if (ret < 0) {
> +                       master_remove_components(master);
> +                       goto out;
> +               }
> +
> +               master->bound = true;
> +               ret = 1;
> +       }
> +out:
> +
> +       return ret;
> +}
> +
> +static int try_to_bring_up_masters(struct component *component)
> +{
> +       struct master *m;
> +       int ret = 0;
> +
> +       list_for_each_entry(m, &masters, node) {
> +               ret = try_to_bring_up_master(m, component);
> +               if (ret != 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static void take_down_master(struct master *master)
> +{
> +       if (master->bound) {
> +               master->ops->unbind(master->dev);
> +               master->bound = false;
> +       }
> +
> +       master_remove_components(master);
> +}
> +
> +int component_master_add(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +       int ret;
> +
> +       master = kzalloc(sizeof(*master), GFP_KERNEL);
> +       if (!master)
> +               return -ENOMEM;
> +
> +       master->dev = dev;
> +       master->ops = ops;
> +       INIT_LIST_HEAD(&master->components);
> +
> +       /* Add to the list of available masters. */
> +       mutex_lock(&component_mutex);
> +       list_add(&master->node, &masters);
> +
> +       ret = try_to_bring_up_master(master, NULL);
> +
> +       if (ret < 0) {
> +               /* Delete off the list if we weren't successful */
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add);
> +
> +void component_master_del(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +
> +       mutex_lock(&component_mutex);
> +       master = __master_find(dev, ops);
> +       if (master) {
> +               take_down_master(master);
> +
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +}
> +EXPORT_SYMBOL_GPL(component_master_del);
> +
> +static void component_unbind(struct component *component,
> +       struct master *master, void *data)
> +{
> +       WARN_ON(!component->bound);
> +
> +       component->ops->unbind(component->dev, master->dev, data);
> +       component->bound = false;
> +
> +       /* Release all resources claimed in the binding of this component */
> +       devres_release_group(component->dev, component);
> +}
> +
> +void component_unbind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return;
> +
> +       list_for_each_entry_reverse(c, &master->components, master_node)
> +               component_unbind(c, master, data);
> +}
> +EXPORT_SYMBOL_GPL(component_unbind_all);
> +
> +static int component_bind(struct component *component, struct master *master,
> +       void *data)
> +{
> +       int ret;
> +
> +       /*
> +        * Each component initialises inside its own devres group.
> +        * This allows us to roll-back a failed component without
> +        * affecting anything else.
> +        */
> +       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
> +               return -ENOMEM;
> +
> +       /*
> +        * Also open a group for the device itself: this allows us
> +        * to release the resources claimed against the sub-device
> +        * at the appropriate moment.
> +        */
> +       if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
> +               devres_release_group(master->dev, NULL);
> +               return -ENOMEM;
> +       }
> +
> +       dev_dbg(master->dev, "binding %s (ops %ps)\n",
> +               dev_name(component->dev), component->ops);
> +
> +       ret = component->ops->bind(component->dev, master->dev, data);
> +       if (!ret) {
> +               component->bound = true;
> +
> +               /*
> +                * Close the component device's group so that resources
> +                * allocated in the binding are encapsulated for removal
> +                * at unbind.  Remove the group on the DRM device as we
> +                * can clean those resources up independently.
> +                */
> +               devres_close_group(component->dev, NULL);
> +               devres_remove_group(master->dev, NULL);
> +
> +               dev_info(master->dev, "bound %s (ops %ps)\n",
> +                        dev_name(component->dev), component->ops);
> +       } else {
> +               devres_release_group(component->dev, NULL);
> +               devres_release_group(master->dev, NULL);
> +
> +               dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
> +                       dev_name(component->dev), component->ops, ret);
> +       }
> +
> +       return ret;
> +}
> +
> +int component_bind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +       int ret = 0;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return -EINVAL;
> +
> +       list_for_each_entry(c, &master->components, master_node) {
> +               ret = component_bind(c, master, data);
> +               if (ret)
> +                       break;
> +       }
> +
> +       if (ret != 0) {
> +               list_for_each_entry_continue_reverse(c, &master->components,
> +                                                    master_node)
> +                       component_unbind(c, master, data);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_bind_all);
> +
> +int component_add(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *component;
> +       int ret;
> +
> +       component = kzalloc(sizeof(*component), GFP_KERNEL);
> +       if (!component)
> +               return -ENOMEM;
> +
> +       component->ops = ops;
> +       component->dev = dev;
> +
> +       dev_dbg(dev, "adding component (ops %ps)\n", ops);
> +
> +       mutex_lock(&component_mutex);
> +       list_add_tail(&component->node, &component_list);
> +
> +       ret = try_to_bring_up_masters(component);
> +       if (ret < 0) {
> +               list_del(&component->node);
> +
> +               kfree(component);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_add);
> +
> +void component_del(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *c, *component = NULL;
> +
> +       mutex_lock(&component_mutex);
> +       list_for_each_entry(c, &component_list, node)
> +               if (c->dev == dev && c->ops == ops) {
> +                       list_del(&c->node);
> +                       component = c;
> +                       break;
> +               }
> +
> +       if (component && component->master)
> +               take_down_master(component->master);
> +
> +       mutex_unlock(&component_mutex);
> +
> +       WARN_ON(!component);
> +       kfree(component);
> +}
> +EXPORT_SYMBOL_GPL(component_del);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/component.h b/include/linux/component.h
> new file mode 100644
> index 000000000000..73657636db0b
> --- /dev/null
> +++ b/include/linux/component.h
> @@ -0,0 +1,31 @@
> +#ifndef COMPONENT_H
> +#define COMPONENT_H
> +
> +struct device;
> +
> +struct component_ops {
> +       int (*bind)(struct device *, struct device *, void *);
> +       void (*unbind)(struct device *, struct device *, void *);
> +};
> +
> +int component_add(struct device *, const struct component_ops *);
> +void component_del(struct device *, const struct component_ops *);
> +
> +int component_bind_all(struct device *, void *);
> +void component_unbind_all(struct device *, void *);
> +
> +struct master;
> +
> +struct component_master_ops {
> +       int (*add_components)(struct device *, struct master *);
> +       int (*bind)(struct device *);
> +       void (*unbind)(struct device *);
> +};
> +
> +int component_master_add(struct device *, const struct component_master_ops *);
> +void component_master_del(struct device *, const struct component_master_ops *);
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data);
> +
> +#endif
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel



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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07  9:04     ` Daniel Vetter
  0 siblings, 0 replies; 219+ messages in thread
From: Daniel Vetter @ 2014-02-07  9:04 UTC (permalink / raw)
  To: Russell King
  Cc: devel, alsa-devel, Greg Kroah-Hartman, dri-devel, Takashi Iwai,
	Sascha Hauer, linux-arm-kernel, linux-media

I've chatted a bit with Hans Verkuil about this topic at fosdem and
apparently both v4l and alsa have something like this already in their
helper libraries. Adding more people as fyi in case they want to
switch to the new driver core stuff from Russell.
-Daniel

On Thu, Jan 2, 2014 at 10:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
>
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
>
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
>
>         imx-drm {
>                 compatible = "fsl,drm";
>                 crtcs = <&ipu1>;
>                 connectors = <&hdmi>;
>         };
>
> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
>
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/base/Makefile     |    2 +-
>  drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/component.h |   31 ++++
>  3 files changed, 411 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/base/component.c
>  create mode 100644 include/linux/component.h
>
> diff --git a/drivers/base/Makefile b/drivers/base/Makefile
> index 94e8a80e87f8..870ecfd503af 100644
> --- a/drivers/base/Makefile
> +++ b/drivers/base/Makefile
> @@ -1,6 +1,6 @@
>  # Makefile for the Linux device tree
>
> -obj-y                  := core.o bus.o dd.o syscore.o \
> +obj-y                  := component.o core.o bus.o dd.o syscore.o \
>                            driver.o class.o platform.o \
>                            cpu.o firmware.o init.o map.o devres.o \
>                            attribute_container.o transport_class.o \
> diff --git a/drivers/base/component.c b/drivers/base/component.c
> new file mode 100644
> index 000000000000..5492cd8d2247
> --- /dev/null
> +++ b/drivers/base/component.c
> @@ -0,0 +1,379 @@
> +/*
> + * Componentized device handling.
> + *
> + * 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.
> + *
> + * This is work in progress.  We gather up the component devices into a list,
> + * and bind them when instructed.  At the moment, we're specific to the DRM
> + * subsystem, and only handles one master device, but this doesn't have to be
> + * the case.
> + */
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +struct master {
> +       struct list_head node;
> +       struct list_head components;
> +       bool bound;
> +
> +       const struct component_master_ops *ops;
> +       struct device *dev;
> +};
> +
> +struct component {
> +       struct list_head node;
> +       struct list_head master_node;
> +       struct master *master;
> +       bool bound;
> +
> +       const struct component_ops *ops;
> +       struct device *dev;
> +};
> +
> +static DEFINE_MUTEX(component_mutex);
> +static LIST_HEAD(component_list);
> +static LIST_HEAD(masters);
> +
> +static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *m;
> +
> +       list_for_each_entry(m, &masters, node)
> +               if (m->dev == dev && (!ops || m->ops == ops))
> +                       return m;
> +
> +       return NULL;
> +}
> +
> +/* Attach an unattached component to a master. */
> +static void component_attach_master(struct master *master, struct component *c)
> +{
> +       c->master = master;
> +
> +       list_add_tail(&c->master_node, &master->components);
> +}
> +
> +/* Detach a component from a master. */
> +static void component_detach_master(struct master *master, struct component *c)
> +{
> +       list_del(&c->master_node);
> +
> +       c->master = NULL;
> +}
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data)
> +{
> +       struct component *c;
> +       int ret = -ENXIO;
> +
> +       list_for_each_entry(c, &component_list, node) {
> +               if (c->master)
> +                       continue;
> +
> +               if (compare(c->dev, compare_data)) {
> +                       component_attach_master(master, c);
> +                       ret = 0;
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add_child);
> +
> +/* Detach all attached components from this master */
> +static void master_remove_components(struct master *master)
> +{
> +       while (!list_empty(&master->components)) {
> +               struct component *c = list_first_entry(&master->components,
> +                                       struct component, master_node);
> +
> +               WARN_ON(c->master != master);
> +
> +               component_detach_master(master, c);
> +       }
> +}
> +
> +/*
> + * Try to bring up a master.  If component is NULL, we're interested in
> + * this master, otherwise it's a component which must be present to try
> + * and bring up the master.
> + *
> + * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
> + */
> +static int try_to_bring_up_master(struct master *master,
> +       struct component *component)
> +{
> +       int ret = 0;
> +
> +       if (!master->bound) {
> +               /*
> +                * Search the list of components, looking for components that
> +                * belong to this master, and attach them to the master.
> +                */
> +               if (master->ops->add_components(master->dev, master)) {
> +                       /* Failed to find all components */
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               if (component && component->master != master) {
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               /* Found all components */
> +               ret = master->ops->bind(master->dev);
> +               if (ret < 0) {
> +                       master_remove_components(master);
> +                       goto out;
> +               }
> +
> +               master->bound = true;
> +               ret = 1;
> +       }
> +out:
> +
> +       return ret;
> +}
> +
> +static int try_to_bring_up_masters(struct component *component)
> +{
> +       struct master *m;
> +       int ret = 0;
> +
> +       list_for_each_entry(m, &masters, node) {
> +               ret = try_to_bring_up_master(m, component);
> +               if (ret != 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static void take_down_master(struct master *master)
> +{
> +       if (master->bound) {
> +               master->ops->unbind(master->dev);
> +               master->bound = false;
> +       }
> +
> +       master_remove_components(master);
> +}
> +
> +int component_master_add(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +       int ret;
> +
> +       master = kzalloc(sizeof(*master), GFP_KERNEL);
> +       if (!master)
> +               return -ENOMEM;
> +
> +       master->dev = dev;
> +       master->ops = ops;
> +       INIT_LIST_HEAD(&master->components);
> +
> +       /* Add to the list of available masters. */
> +       mutex_lock(&component_mutex);
> +       list_add(&master->node, &masters);
> +
> +       ret = try_to_bring_up_master(master, NULL);
> +
> +       if (ret < 0) {
> +               /* Delete off the list if we weren't successful */
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add);
> +
> +void component_master_del(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +
> +       mutex_lock(&component_mutex);
> +       master = __master_find(dev, ops);
> +       if (master) {
> +               take_down_master(master);
> +
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +}
> +EXPORT_SYMBOL_GPL(component_master_del);
> +
> +static void component_unbind(struct component *component,
> +       struct master *master, void *data)
> +{
> +       WARN_ON(!component->bound);
> +
> +       component->ops->unbind(component->dev, master->dev, data);
> +       component->bound = false;
> +
> +       /* Release all resources claimed in the binding of this component */
> +       devres_release_group(component->dev, component);
> +}
> +
> +void component_unbind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return;
> +
> +       list_for_each_entry_reverse(c, &master->components, master_node)
> +               component_unbind(c, master, data);
> +}
> +EXPORT_SYMBOL_GPL(component_unbind_all);
> +
> +static int component_bind(struct component *component, struct master *master,
> +       void *data)
> +{
> +       int ret;
> +
> +       /*
> +        * Each component initialises inside its own devres group.
> +        * This allows us to roll-back a failed component without
> +        * affecting anything else.
> +        */
> +       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
> +               return -ENOMEM;
> +
> +       /*
> +        * Also open a group for the device itself: this allows us
> +        * to release the resources claimed against the sub-device
> +        * at the appropriate moment.
> +        */
> +       if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
> +               devres_release_group(master->dev, NULL);
> +               return -ENOMEM;
> +       }
> +
> +       dev_dbg(master->dev, "binding %s (ops %ps)\n",
> +               dev_name(component->dev), component->ops);
> +
> +       ret = component->ops->bind(component->dev, master->dev, data);
> +       if (!ret) {
> +               component->bound = true;
> +
> +               /*
> +                * Close the component device's group so that resources
> +                * allocated in the binding are encapsulated for removal
> +                * at unbind.  Remove the group on the DRM device as we
> +                * can clean those resources up independently.
> +                */
> +               devres_close_group(component->dev, NULL);
> +               devres_remove_group(master->dev, NULL);
> +
> +               dev_info(master->dev, "bound %s (ops %ps)\n",
> +                        dev_name(component->dev), component->ops);
> +       } else {
> +               devres_release_group(component->dev, NULL);
> +               devres_release_group(master->dev, NULL);
> +
> +               dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
> +                       dev_name(component->dev), component->ops, ret);
> +       }
> +
> +       return ret;
> +}
> +
> +int component_bind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +       int ret = 0;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return -EINVAL;
> +
> +       list_for_each_entry(c, &master->components, master_node) {
> +               ret = component_bind(c, master, data);
> +               if (ret)
> +                       break;
> +       }
> +
> +       if (ret != 0) {
> +               list_for_each_entry_continue_reverse(c, &master->components,
> +                                                    master_node)
> +                       component_unbind(c, master, data);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_bind_all);
> +
> +int component_add(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *component;
> +       int ret;
> +
> +       component = kzalloc(sizeof(*component), GFP_KERNEL);
> +       if (!component)
> +               return -ENOMEM;
> +
> +       component->ops = ops;
> +       component->dev = dev;
> +
> +       dev_dbg(dev, "adding component (ops %ps)\n", ops);
> +
> +       mutex_lock(&component_mutex);
> +       list_add_tail(&component->node, &component_list);
> +
> +       ret = try_to_bring_up_masters(component);
> +       if (ret < 0) {
> +               list_del(&component->node);
> +
> +               kfree(component);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_add);
> +
> +void component_del(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *c, *component = NULL;
> +
> +       mutex_lock(&component_mutex);
> +       list_for_each_entry(c, &component_list, node)
> +               if (c->dev == dev && c->ops == ops) {
> +                       list_del(&c->node);
> +                       component = c;
> +                       break;
> +               }
> +
> +       if (component && component->master)
> +               take_down_master(component->master);
> +
> +       mutex_unlock(&component_mutex);
> +
> +       WARN_ON(!component);
> +       kfree(component);
> +}
> +EXPORT_SYMBOL_GPL(component_del);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/component.h b/include/linux/component.h
> new file mode 100644
> index 000000000000..73657636db0b
> --- /dev/null
> +++ b/include/linux/component.h
> @@ -0,0 +1,31 @@
> +#ifndef COMPONENT_H
> +#define COMPONENT_H
> +
> +struct device;
> +
> +struct component_ops {
> +       int (*bind)(struct device *, struct device *, void *);
> +       void (*unbind)(struct device *, struct device *, void *);
> +};
> +
> +int component_add(struct device *, const struct component_ops *);
> +void component_del(struct device *, const struct component_ops *);
> +
> +int component_bind_all(struct device *, void *);
> +void component_unbind_all(struct device *, void *);
> +
> +struct master;
> +
> +struct component_master_ops {
> +       int (*add_components)(struct device *, struct master *);
> +       int (*bind)(struct device *);
> +       void (*unbind)(struct device *);
> +};
> +
> +int component_master_add(struct device *, const struct component_master_ops *);
> +void component_master_del(struct device *, const struct component_master_ops *);
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data);
> +
> +#endif
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel



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

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07  9:04     ` Daniel Vetter
  0 siblings, 0 replies; 219+ messages in thread
From: Daniel Vetter @ 2014-02-07  9:04 UTC (permalink / raw)
  To: linux-arm-kernel

I've chatted a bit with Hans Verkuil about this topic at fosdem and
apparently both v4l and alsa have something like this already in their
helper libraries. Adding more people as fyi in case they want to
switch to the new driver core stuff from Russell.
-Daniel

On Thu, Jan 2, 2014 at 10:27 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:
> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
>
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
>
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
>
>         imx-drm {
>                 compatible = "fsl,drm";
>                 crtcs = <&ipu1>;
>                 connectors = <&hdmi>;
>         };
>
> The superdevice is declared into the component support, along with the
> subcomponents.  The superdevice receives callbacks to locate the
> subcomponents, and identify when all components are present.  At this
> point, we bind the superdevice, which causes the appropriate subsystem
> to be initialised in the conventional way.
>
> When any of the components or superdevice are removed from the system,
> we unbind the superdevice, thereby taking the subsystem down.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
>  drivers/base/Makefile     |    2 +-
>  drivers/base/component.c  |  379 +++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/component.h |   31 ++++
>  3 files changed, 411 insertions(+), 1 deletions(-)
>  create mode 100644 drivers/base/component.c
>  create mode 100644 include/linux/component.h
>
> diff --git a/drivers/base/Makefile b/drivers/base/Makefile
> index 94e8a80e87f8..870ecfd503af 100644
> --- a/drivers/base/Makefile
> +++ b/drivers/base/Makefile
> @@ -1,6 +1,6 @@
>  # Makefile for the Linux device tree
>
> -obj-y                  := core.o bus.o dd.o syscore.o \
> +obj-y                  := component.o core.o bus.o dd.o syscore.o \
>                            driver.o class.o platform.o \
>                            cpu.o firmware.o init.o map.o devres.o \
>                            attribute_container.o transport_class.o \
> diff --git a/drivers/base/component.c b/drivers/base/component.c
> new file mode 100644
> index 000000000000..5492cd8d2247
> --- /dev/null
> +++ b/drivers/base/component.c
> @@ -0,0 +1,379 @@
> +/*
> + * Componentized device handling.
> + *
> + * 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.
> + *
> + * This is work in progress.  We gather up the component devices into a list,
> + * and bind them when instructed.  At the moment, we're specific to the DRM
> + * subsystem, and only handles one master device, but this doesn't have to be
> + * the case.
> + */
> +#include <linux/component.h>
> +#include <linux/device.h>
> +#include <linux/kref.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/slab.h>
> +
> +struct master {
> +       struct list_head node;
> +       struct list_head components;
> +       bool bound;
> +
> +       const struct component_master_ops *ops;
> +       struct device *dev;
> +};
> +
> +struct component {
> +       struct list_head node;
> +       struct list_head master_node;
> +       struct master *master;
> +       bool bound;
> +
> +       const struct component_ops *ops;
> +       struct device *dev;
> +};
> +
> +static DEFINE_MUTEX(component_mutex);
> +static LIST_HEAD(component_list);
> +static LIST_HEAD(masters);
> +
> +static struct master *__master_find(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *m;
> +
> +       list_for_each_entry(m, &masters, node)
> +               if (m->dev == dev && (!ops || m->ops == ops))
> +                       return m;
> +
> +       return NULL;
> +}
> +
> +/* Attach an unattached component to a master. */
> +static void component_attach_master(struct master *master, struct component *c)
> +{
> +       c->master = master;
> +
> +       list_add_tail(&c->master_node, &master->components);
> +}
> +
> +/* Detach a component from a master. */
> +static void component_detach_master(struct master *master, struct component *c)
> +{
> +       list_del(&c->master_node);
> +
> +       c->master = NULL;
> +}
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data)
> +{
> +       struct component *c;
> +       int ret = -ENXIO;
> +
> +       list_for_each_entry(c, &component_list, node) {
> +               if (c->master)
> +                       continue;
> +
> +               if (compare(c->dev, compare_data)) {
> +                       component_attach_master(master, c);
> +                       ret = 0;
> +                       break;
> +               }
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add_child);
> +
> +/* Detach all attached components from this master */
> +static void master_remove_components(struct master *master)
> +{
> +       while (!list_empty(&master->components)) {
> +               struct component *c = list_first_entry(&master->components,
> +                                       struct component, master_node);
> +
> +               WARN_ON(c->master != master);
> +
> +               component_detach_master(master, c);
> +       }
> +}
> +
> +/*
> + * Try to bring up a master.  If component is NULL, we're interested in
> + * this master, otherwise it's a component which must be present to try
> + * and bring up the master.
> + *
> + * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
> + */
> +static int try_to_bring_up_master(struct master *master,
> +       struct component *component)
> +{
> +       int ret = 0;
> +
> +       if (!master->bound) {
> +               /*
> +                * Search the list of components, looking for components that
> +                * belong to this master, and attach them to the master.
> +                */
> +               if (master->ops->add_components(master->dev, master)) {
> +                       /* Failed to find all components */
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               if (component && component->master != master) {
> +                       master_remove_components(master);
> +                       ret = 0;
> +                       goto out;
> +               }
> +
> +               /* Found all components */
> +               ret = master->ops->bind(master->dev);
> +               if (ret < 0) {
> +                       master_remove_components(master);
> +                       goto out;
> +               }
> +
> +               master->bound = true;
> +               ret = 1;
> +       }
> +out:
> +
> +       return ret;
> +}
> +
> +static int try_to_bring_up_masters(struct component *component)
> +{
> +       struct master *m;
> +       int ret = 0;
> +
> +       list_for_each_entry(m, &masters, node) {
> +               ret = try_to_bring_up_master(m, component);
> +               if (ret != 0)
> +                       break;
> +       }
> +
> +       return ret;
> +}
> +
> +static void take_down_master(struct master *master)
> +{
> +       if (master->bound) {
> +               master->ops->unbind(master->dev);
> +               master->bound = false;
> +       }
> +
> +       master_remove_components(master);
> +}
> +
> +int component_master_add(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +       int ret;
> +
> +       master = kzalloc(sizeof(*master), GFP_KERNEL);
> +       if (!master)
> +               return -ENOMEM;
> +
> +       master->dev = dev;
> +       master->ops = ops;
> +       INIT_LIST_HEAD(&master->components);
> +
> +       /* Add to the list of available masters. */
> +       mutex_lock(&component_mutex);
> +       list_add(&master->node, &masters);
> +
> +       ret = try_to_bring_up_master(master, NULL);
> +
> +       if (ret < 0) {
> +               /* Delete off the list if we weren't successful */
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_master_add);
> +
> +void component_master_del(struct device *dev, const struct component_master_ops *ops)
> +{
> +       struct master *master;
> +
> +       mutex_lock(&component_mutex);
> +       master = __master_find(dev, ops);
> +       if (master) {
> +               take_down_master(master);
> +
> +               list_del(&master->node);
> +               kfree(master);
> +       }
> +       mutex_unlock(&component_mutex);
> +}
> +EXPORT_SYMBOL_GPL(component_master_del);
> +
> +static void component_unbind(struct component *component,
> +       struct master *master, void *data)
> +{
> +       WARN_ON(!component->bound);
> +
> +       component->ops->unbind(component->dev, master->dev, data);
> +       component->bound = false;
> +
> +       /* Release all resources claimed in the binding of this component */
> +       devres_release_group(component->dev, component);
> +}
> +
> +void component_unbind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return;
> +
> +       list_for_each_entry_reverse(c, &master->components, master_node)
> +               component_unbind(c, master, data);
> +}
> +EXPORT_SYMBOL_GPL(component_unbind_all);
> +
> +static int component_bind(struct component *component, struct master *master,
> +       void *data)
> +{
> +       int ret;
> +
> +       /*
> +        * Each component initialises inside its own devres group.
> +        * This allows us to roll-back a failed component without
> +        * affecting anything else.
> +        */
> +       if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
> +               return -ENOMEM;
> +
> +       /*
> +        * Also open a group for the device itself: this allows us
> +        * to release the resources claimed against the sub-device
> +        * at the appropriate moment.
> +        */
> +       if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
> +               devres_release_group(master->dev, NULL);
> +               return -ENOMEM;
> +       }
> +
> +       dev_dbg(master->dev, "binding %s (ops %ps)\n",
> +               dev_name(component->dev), component->ops);
> +
> +       ret = component->ops->bind(component->dev, master->dev, data);
> +       if (!ret) {
> +               component->bound = true;
> +
> +               /*
> +                * Close the component device's group so that resources
> +                * allocated in the binding are encapsulated for removal
> +                * at unbind.  Remove the group on the DRM device as we
> +                * can clean those resources up independently.
> +                */
> +               devres_close_group(component->dev, NULL);
> +               devres_remove_group(master->dev, NULL);
> +
> +               dev_info(master->dev, "bound %s (ops %ps)\n",
> +                        dev_name(component->dev), component->ops);
> +       } else {
> +               devres_release_group(component->dev, NULL);
> +               devres_release_group(master->dev, NULL);
> +
> +               dev_err(master->dev, "failed to bind %s (ops %ps): %d\n",
> +                       dev_name(component->dev), component->ops, ret);
> +       }
> +
> +       return ret;
> +}
> +
> +int component_bind_all(struct device *master_dev, void *data)
> +{
> +       struct master *master;
> +       struct component *c;
> +       int ret = 0;
> +
> +       WARN_ON(!mutex_is_locked(&component_mutex));
> +
> +       master = __master_find(master_dev, NULL);
> +       if (!master)
> +               return -EINVAL;
> +
> +       list_for_each_entry(c, &master->components, master_node) {
> +               ret = component_bind(c, master, data);
> +               if (ret)
> +                       break;
> +       }
> +
> +       if (ret != 0) {
> +               list_for_each_entry_continue_reverse(c, &master->components,
> +                                                    master_node)
> +                       component_unbind(c, master, data);
> +       }
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL_GPL(component_bind_all);
> +
> +int component_add(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *component;
> +       int ret;
> +
> +       component = kzalloc(sizeof(*component), GFP_KERNEL);
> +       if (!component)
> +               return -ENOMEM;
> +
> +       component->ops = ops;
> +       component->dev = dev;
> +
> +       dev_dbg(dev, "adding component (ops %ps)\n", ops);
> +
> +       mutex_lock(&component_mutex);
> +       list_add_tail(&component->node, &component_list);
> +
> +       ret = try_to_bring_up_masters(component);
> +       if (ret < 0) {
> +               list_del(&component->node);
> +
> +               kfree(component);
> +       }
> +       mutex_unlock(&component_mutex);
> +
> +       return ret < 0 ? ret : 0;
> +}
> +EXPORT_SYMBOL_GPL(component_add);
> +
> +void component_del(struct device *dev, const struct component_ops *ops)
> +{
> +       struct component *c, *component = NULL;
> +
> +       mutex_lock(&component_mutex);
> +       list_for_each_entry(c, &component_list, node)
> +               if (c->dev == dev && c->ops == ops) {
> +                       list_del(&c->node);
> +                       component = c;
> +                       break;
> +               }
> +
> +       if (component && component->master)
> +               take_down_master(component->master);
> +
> +       mutex_unlock(&component_mutex);
> +
> +       WARN_ON(!component);
> +       kfree(component);
> +}
> +EXPORT_SYMBOL_GPL(component_del);
> +
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/component.h b/include/linux/component.h
> new file mode 100644
> index 000000000000..73657636db0b
> --- /dev/null
> +++ b/include/linux/component.h
> @@ -0,0 +1,31 @@
> +#ifndef COMPONENT_H
> +#define COMPONENT_H
> +
> +struct device;
> +
> +struct component_ops {
> +       int (*bind)(struct device *, struct device *, void *);
> +       void (*unbind)(struct device *, struct device *, void *);
> +};
> +
> +int component_add(struct device *, const struct component_ops *);
> +void component_del(struct device *, const struct component_ops *);
> +
> +int component_bind_all(struct device *, void *);
> +void component_unbind_all(struct device *, void *);
> +
> +struct master;
> +
> +struct component_master_ops {
> +       int (*add_components)(struct device *, struct master *);
> +       int (*bind)(struct device *);
> +       void (*unbind)(struct device *);
> +};
> +
> +int component_master_add(struct device *, const struct component_master_ops *);
> +void component_master_del(struct device *, const struct component_master_ops *);
> +
> +int component_master_add_child(struct master *master,
> +       int (*compare)(struct device *, void *), void *compare_data);
> +
> +#endif
> --
> 1.7.4.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel



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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-07  9:04     ` Daniel Vetter
@ 2014-02-07  9:46       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-07  9:46 UTC (permalink / raw)
  To: Daniel Vetter
  Cc: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo, devel,
	dri-devel, linux-arm-kernel, Hans Verkuil, linux-media,
	Takashi Iwai, alsa-devel

On Fri, Feb 07, 2014 at 10:04:30AM +0100, Daniel Vetter wrote:
> I've chatted a bit with Hans Verkuil about this topic at fosdem and
> apparently both v4l and alsa have something like this already in their
> helper libraries. Adding more people as fyi in case they want to
> switch to the new driver core stuff from Russell.

It's not ALSA, but ASoC which has this.  Mark is already aware of this
and will be looking at it from an ASoC perspective.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07  9:46       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-07  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 07, 2014 at 10:04:30AM +0100, Daniel Vetter wrote:
> I've chatted a bit with Hans Verkuil about this topic at fosdem and
> apparently both v4l and alsa have something like this already in their
> helper libraries. Adding more people as fyi in case they want to
> switch to the new driver core stuff from Russell.

It's not ALSA, but ASoC which has this.  Mark is already aware of this
and will be looking at it from an ASoC perspective.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-07  9:46       ` Russell King - ARM Linux
  (?)
@ 2014-02-07 11:57         ` Jean-Francois Moine
  -1 siblings, 0 replies; 219+ messages in thread
From: Jean-Francois Moine @ 2014-02-07 11:57 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Daniel Vetter, devel, alsa-devel, David Airlie,
	Greg Kroah-Hartman, dri-devel, Hans Verkuil, Takashi Iwai,
	Sascha Hauer, Shawn Guo, linux-arm-kernel, linux-media

On Fri, 7 Feb 2014 09:46:56 +0000
Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:

> On Fri, Feb 07, 2014 at 10:04:30AM +0100, Daniel Vetter wrote:
> > I've chatted a bit with Hans Verkuil about this topic at fosdem and
> > apparently both v4l and alsa have something like this already in their
> > helper libraries. Adding more people as fyi in case they want to
> > switch to the new driver core stuff from Russell.  
> 
> It's not ALSA, but ASoC which has this.  Mark is already aware of this
> and will be looking at it from an ASoC perspective.

Russell,

I started to use your code (which works fine, thanks), and it avoids a
lot of problems, especially, about probe_defer in a DT context.

I was wondering if your componentised mechanism could be extended to the
devices defined by DT.

In the DT, when a device_node is a phandle, this means it is referenced
by some other device(s), and these device(s) will not start until the
phandle device is registered.

Then, the idea is to do a component_add() for such phandle devices in
device_add() (device_register).

Pratically,

- the component_add() call in device_register would not include any
  bind/unbind callback function, so, this should be tested in
  component_bind/unbind(),

- component_add would not be called if the device being added already
  called component_add in its probe function. A simple flag in the
  struct device_node should solve this problem.

What do you think about this?

-- 
Ken ar c'hentañ	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07 11:57         ` Jean-Francois Moine
  0 siblings, 0 replies; 219+ messages in thread
From: Jean-Francois Moine @ 2014-02-07 11:57 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, alsa-devel, Sascha Hauer, Greg Kroah-Hartman, dri-devel,
	Takashi Iwai, linux-arm-kernel, linux-media

On Fri, 7 Feb 2014 09:46:56 +0000
Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:

> On Fri, Feb 07, 2014 at 10:04:30AM +0100, Daniel Vetter wrote:
> > I've chatted a bit with Hans Verkuil about this topic at fosdem and
> > apparently both v4l and alsa have something like this already in their
> > helper libraries. Adding more people as fyi in case they want to
> > switch to the new driver core stuff from Russell.  
> 
> It's not ALSA, but ASoC which has this.  Mark is already aware of this
> and will be looking at it from an ASoC perspective.

Russell,

I started to use your code (which works fine, thanks), and it avoids a
lot of problems, especially, about probe_defer in a DT context.

I was wondering if your componentised mechanism could be extended to the
devices defined by DT.

In the DT, when a device_node is a phandle, this means it is referenced
by some other device(s), and these device(s) will not start until the
phandle device is registered.

Then, the idea is to do a component_add() for such phandle devices in
device_add() (device_register).

Pratically,

- the component_add() call in device_register would not include any
  bind/unbind callback function, so, this should be tested in
  component_bind/unbind(),

- component_add would not be called if the device being added already
  called component_add in its probe function. A simple flag in the
  struct device_node should solve this problem.

What do you think about this?

-- 
Ken ar c'hentañ	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07 11:57         ` Jean-Francois Moine
  0 siblings, 0 replies; 219+ messages in thread
From: Jean-Francois Moine @ 2014-02-07 11:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 7 Feb 2014 09:46:56 +0000
Russell King - ARM Linux <linux@arm.linux.org.uk> wrote:

> On Fri, Feb 07, 2014 at 10:04:30AM +0100, Daniel Vetter wrote:
> > I've chatted a bit with Hans Verkuil about this topic at fosdem and
> > apparently both v4l and alsa have something like this already in their
> > helper libraries. Adding more people as fyi in case they want to
> > switch to the new driver core stuff from Russell.  
> 
> It's not ALSA, but ASoC which has this.  Mark is already aware of this
> and will be looking at it from an ASoC perspective.

Russell,

I started to use your code (which works fine, thanks), and it avoids a
lot of problems, especially, about probe_defer in a DT context.

I was wondering if your componentised mechanism could be extended to the
devices defined by DT.

In the DT, when a device_node is a phandle, this means it is referenced
by some other device(s), and these device(s) will not start until the
phandle device is registered.

Then, the idea is to do a component_add() for such phandle devices in
device_add() (device_register).

Pratically,

- the component_add() call in device_register would not include any
  bind/unbind callback function, so, this should be tested in
  component_bind/unbind(),

- component_add would not be called if the device being added already
  called component_add in its probe function. A simple flag in the
  struct device_node should solve this problem.

What do you think about this?

-- 
Ken ar c'henta?	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-07 11:57         ` Jean-Francois Moine
  (?)
@ 2014-02-07 12:28           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-07 12:28 UTC (permalink / raw)
  To: Jean-Francois Moine
  Cc: Daniel Vetter, devel, alsa-devel, David Airlie,
	Greg Kroah-Hartman, dri-devel, Hans Verkuil, Takashi Iwai,
	Sascha Hauer, Shawn Guo, linux-arm-kernel, linux-media

On Fri, Feb 07, 2014 at 12:57:21PM +0100, Jean-Francois Moine wrote:
> I started to use your code (which works fine, thanks), and it avoids a
> lot of problems, especially, about probe_defer in a DT context.
> 
> I was wondering if your componentised mechanism could be extended to the
> devices defined by DT.

It was developed against imx-drm, which is purely DT based.  I already
have a solution for the cubox armada DRM.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07 12:28           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-07 12:28 UTC (permalink / raw)
  To: Jean-Francois Moine
  Cc: devel, alsa-devel, Sascha Hauer, David Airlie,
	Greg Kroah-Hartman, dri-devel, Hans Verkuil, Takashi Iwai,
	Daniel Vetter, Shawn Guo, linux-arm-kernel, linux-media

On Fri, Feb 07, 2014 at 12:57:21PM +0100, Jean-Francois Moine wrote:
> I started to use your code (which works fine, thanks), and it avoids a
> lot of problems, especially, about probe_defer in a DT context.
> 
> I was wondering if your componentised mechanism could be extended to the
> devices defined by DT.

It was developed against imx-drm, which is purely DT based.  I already
have a solution for the cubox armada DRM.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-07 12:28           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-07 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 07, 2014 at 12:57:21PM +0100, Jean-Francois Moine wrote:
> I started to use your code (which works fine, thanks), and it avoids a
> lot of problems, especially, about probe_defer in a DT context.
> 
> I was wondering if your componentised mechanism could be extended to the
> devices defined by DT.

It was developed against imx-drm, which is purely DT based.  I already
have a solution for the cubox armada DRM.

-- 
FTTC broadband for 0.8mile line: 5.8Mbps down 500kbps up.  Estimation
in database were 13.1 to 19Mbit for a good line, about 7.5+ for a bad.
Estimate before purchase was "up to 13.2Mbit".

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-01-02 21:27   ` Russell King
  (?)
@ 2014-02-26 21:00     ` Guennadi Liakhovetski
  -1 siblings, 0 replies; 219+ messages in thread
From: Guennadi Liakhovetski @ 2014-02-26 21:00 UTC (permalink / raw)
  To: Russell King
  Cc: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo, devel,
	dri-devel, linux-arm-kernel, Linux Media Mailing List,
	Laurent Pinchart, Sylwester Nawrocki

Hi Russell

(I suspect this my email will be rejected by ALKML too like other my 
recent emails, but at least other MLs will pick it up and individual CCs 
too, so, if replying, maybe it would be good to keep my entire reply, all 
the more that it's going to be very short)

On Thu, 2 Jan 2014, Russell King wrote:

> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
> 
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
> 
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};

It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
notice this and other related patches in a "clean up" series, and now this 
patch is already in the mainline. But at least I'd like to ask whether the 
bindings, defined in 
Documentation/devicetree/bindings/media/video-interfaces.txt and 
implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
this job, and - if so - why have they been found unsuitable? Wouldn't it 
have been better to use and - if needed - extend them to cover any 
deficiencies? Even though the implementation is currently located under 
drivers/media/v4l2-code/ it's pretty generic and should be easily 
transferable to a more generic location.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-26 21:00     ` Guennadi Liakhovetski
  0 siblings, 0 replies; 219+ messages in thread
From: Guennadi Liakhovetski @ 2014-02-26 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell

(I suspect this my email will be rejected by ALKML too like other my 
recent emails, but at least other MLs will pick it up and individual CCs 
too, so, if replying, maybe it would be good to keep my entire reply, all 
the more that it's going to be very short)

On Thu, 2 Jan 2014, Russell King wrote:

> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
> 
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
> 
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};

It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
notice this and other related patches in a "clean up" series, and now this 
patch is already in the mainline. But at least I'd like to ask whether the 
bindings, defined in 
Documentation/devicetree/bindings/media/video-interfaces.txt and 
implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
this job, and - if so - why have they been found unsuitable? Wouldn't it 
have been better to use and - if needed - extend them to cover any 
deficiencies? Even though the implementation is currently located under 
drivers/media/v4l2-code/ it's pretty generic and should be easily 
transferable to a more generic location.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-26 21:00     ` Guennadi Liakhovetski
  0 siblings, 0 replies; 219+ messages in thread
From: Guennadi Liakhovetski @ 2014-02-26 21:00 UTC (permalink / raw)
  To: Russell King
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel,
	Laurent Pinchart, Sascha Hauer, Sylwester Nawrocki, Shawn Guo,
	linux-arm-kernel, Linux Media Mailing List

Hi Russell

(I suspect this my email will be rejected by ALKML too like other my 
recent emails, but at least other MLs will pick it up and individual CCs 
too, so, if replying, maybe it would be good to keep my entire reply, all 
the more that it's going to be very short)

On Thu, 2 Jan 2014, Russell King wrote:

> Subsystems such as ALSA, DRM and others require a single card-level
> device structure to represent a subsystem.  However, firmware tends to
> describe the individual devices and the connections between them.
> 
> Therefore, we need a way to gather up the individual component devices
> together, and indicate when we have all the component devices.
> 
> We do this in DT by providing a "superdevice" node which specifies
> the components, eg:
> 
> 	imx-drm {
> 		compatible = "fsl,drm";
> 		crtcs = <&ipu1>;
> 		connectors = <&hdmi>;
> 	};

It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
notice this and other related patches in a "clean up" series, and now this 
patch is already in the mainline. But at least I'd like to ask whether the 
bindings, defined in 
Documentation/devicetree/bindings/media/video-interfaces.txt and 
implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
this job, and - if so - why have they been found unsuitable? Wouldn't it 
have been better to use and - if needed - extend them to cover any 
deficiencies? Even though the implementation is currently located under 
drivers/media/v4l2-code/ it's pretty generic and should be easily 
transferable to a more generic location.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-26 21:00     ` Guennadi Liakhovetski
  (?)
@ 2014-02-26 22:19       ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-26 22:19 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo, devel,
	dri-devel, linux-arm-kernel, Linux Media Mailing List,
	Laurent Pinchart, Sylwester Nawrocki

On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> Hi Russell
> 
> (I suspect this my email will be rejected by ALKML too like other my 
> recent emails, but at least other MLs will pick it up and individual CCs 
> too, so, if replying, maybe it would be good to keep my entire reply, all 
> the more that it's going to be very short)
> 
> On Thu, 2 Jan 2014, Russell King wrote:
> 
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> 
> It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
> notice this and other related patches in a "clean up" series, and now this 
> patch is already in the mainline. But at least I'd like to ask whether the 
> bindings, defined in 
> Documentation/devicetree/bindings/media/video-interfaces.txt and 
> implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
> this job, and - if so - why have they been found unsuitable? Wouldn't it 
> have been better to use and - if needed - extend them to cover any 
> deficiencies? Even though the implementation is currently located under 
> drivers/media/v4l2-code/ it's pretty generic and should be easily 
> transferable to a more generic location.

The component helpers have nothing to do with DT apart from solving
the problem of how to deal with subsystems which expect a single device,
but we have a group of devices and their individual drivers to cope with.
Subsystems like DRM and ALSA.

It is completely agnostic to whether you're using platform data, DT or
even ACPI - this code could *not* care less.  None of that comes anywhere
near what this patch does.  It merely provides a way to collect up
individual devices from co-operating drivers, and control their binding
such that a subsystem like DRM or ALSA can be presented with a "card"
level view of the hardware rather than a multi-device medusa with all
the buggy, racy, crap fsckage that people come up to make that kind of
thing work.

Now, as for the binding above, first, what does "eg" mean... and
secondly, how would a binding which refers to crtcs and connectors
have anything to do with ALSA?  Clearly this isn't an example of a
binding for an ALSA use, which was talked about in the very first
line of the above commit commentry.  So it's quite clear that what is
given there is an example of how it /could/ be used.

I suppose I could have instead turned imx-drm into a completely unusable
mess by not coming up with some kind of binding, and instead submitted
a whole pile of completely untested code.  Alternatively, I could've
used the OF binding as you're suggesting, but that would mean radically
changing the /existing/ bindings for the IPU as a whole - something
which others are better suited at as they have a /much/ better
understanding of the complexities of this hardware than I.

So, what I have done is implemented - for a driver in staging which is
still subject to ongoing development and non-stable DT bindings -
something which allows forward progress with a *minimum* of disruption
to the existing DT bindings for everyone, while still allowing forward
progress.

Better bindings for imx-drm are currently being worked on.  Philipp
Zabel of Pengutronix is currently looking at it, and has posted many
RFC patches on this very subject, including moving the V4L2 OF helpers
to a more suitable location.  OF people have been involved in that
discussion over the preceding weeks, and there's a working implementation
of imx-drm using these helpers from v4l2.

I'm finding people who are working in the same area and trying to get
everyone talking to each other so that we /do/ end up with a set of
bindings for the display stuff which are suitable for everyone.  Tomi
from TI has already expressed his input to this ongoing discussion.

You're welcome to get involved in those discussions too.

I hope this makes it clear, and clears up the confusion.

Thanks.

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

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-26 22:19       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-26 22:19 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> Hi Russell
> 
> (I suspect this my email will be rejected by ALKML too like other my 
> recent emails, but at least other MLs will pick it up and individual CCs 
> too, so, if replying, maybe it would be good to keep my entire reply, all 
> the more that it's going to be very short)
> 
> On Thu, 2 Jan 2014, Russell King wrote:
> 
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> 
> It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
> notice this and other related patches in a "clean up" series, and now this 
> patch is already in the mainline. But at least I'd like to ask whether the 
> bindings, defined in 
> Documentation/devicetree/bindings/media/video-interfaces.txt and 
> implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
> this job, and - if so - why have they been found unsuitable? Wouldn't it 
> have been better to use and - if needed - extend them to cover any 
> deficiencies? Even though the implementation is currently located under 
> drivers/media/v4l2-code/ it's pretty generic and should be easily 
> transferable to a more generic location.

The component helpers have nothing to do with DT apart from solving
the problem of how to deal with subsystems which expect a single device,
but we have a group of devices and their individual drivers to cope with.
Subsystems like DRM and ALSA.

It is completely agnostic to whether you're using platform data, DT or
even ACPI - this code could *not* care less.  None of that comes anywhere
near what this patch does.  It merely provides a way to collect up
individual devices from co-operating drivers, and control their binding
such that a subsystem like DRM or ALSA can be presented with a "card"
level view of the hardware rather than a multi-device medusa with all
the buggy, racy, crap fsckage that people come up to make that kind of
thing work.

Now, as for the binding above, first, what does "eg" mean... and
secondly, how would a binding which refers to crtcs and connectors
have anything to do with ALSA?  Clearly this isn't an example of a
binding for an ALSA use, which was talked about in the very first
line of the above commit commentry.  So it's quite clear that what is
given there is an example of how it /could/ be used.

I suppose I could have instead turned imx-drm into a completely unusable
mess by not coming up with some kind of binding, and instead submitted
a whole pile of completely untested code.  Alternatively, I could've
used the OF binding as you're suggesting, but that would mean radically
changing the /existing/ bindings for the IPU as a whole - something
which others are better suited at as they have a /much/ better
understanding of the complexities of this hardware than I.

So, what I have done is implemented - for a driver in staging which is
still subject to ongoing development and non-stable DT bindings -
something which allows forward progress with a *minimum* of disruption
to the existing DT bindings for everyone, while still allowing forward
progress.

Better bindings for imx-drm are currently being worked on.  Philipp
Zabel of Pengutronix is currently looking at it, and has posted many
RFC patches on this very subject, including moving the V4L2 OF helpers
to a more suitable location.  OF people have been involved in that
discussion over the preceding weeks, and there's a working implementation
of imx-drm using these helpers from v4l2.

I'm finding people who are working in the same area and trying to get
everyone talking to each other so that we /do/ end up with a set of
bindings for the display stuff which are suitable for everyone.  Tomi
from TI has already expressed his input to this ongoing discussion.

You're welcome to get involved in those discussions too.

I hope this makes it clear, and clears up the confusion.

Thanks.

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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-02-26 22:19       ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-02-26 22:19 UTC (permalink / raw)
  To: Guennadi Liakhovetski
  Cc: devel, Greg Kroah-Hartman, dri-devel, Laurent Pinchart,
	Sascha Hauer, Sylwester Nawrocki, linux-arm-kernel,
	Linux Media Mailing List

On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> Hi Russell
> 
> (I suspect this my email will be rejected by ALKML too like other my 
> recent emails, but at least other MLs will pick it up and individual CCs 
> too, so, if replying, maybe it would be good to keep my entire reply, all 
> the more that it's going to be very short)
> 
> On Thu, 2 Jan 2014, Russell King wrote:
> 
> > Subsystems such as ALSA, DRM and others require a single card-level
> > device structure to represent a subsystem.  However, firmware tends to
> > describe the individual devices and the connections between them.
> > 
> > Therefore, we need a way to gather up the individual component devices
> > together, and indicate when we have all the component devices.
> > 
> > We do this in DT by providing a "superdevice" node which specifies
> > the components, eg:
> > 
> > 	imx-drm {
> > 		compatible = "fsl,drm";
> > 		crtcs = <&ipu1>;
> > 		connectors = <&hdmi>;
> > 	};
> 
> It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't 
> notice this and other related patches in a "clean up" series, and now this 
> patch is already in the mainline. But at least I'd like to ask whether the 
> bindings, defined in 
> Documentation/devicetree/bindings/media/video-interfaces.txt and 
> implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for 
> this job, and - if so - why have they been found unsuitable? Wouldn't it 
> have been better to use and - if needed - extend them to cover any 
> deficiencies? Even though the implementation is currently located under 
> drivers/media/v4l2-code/ it's pretty generic and should be easily 
> transferable to a more generic location.

The component helpers have nothing to do with DT apart from solving
the problem of how to deal with subsystems which expect a single device,
but we have a group of devices and their individual drivers to cope with.
Subsystems like DRM and ALSA.

It is completely agnostic to whether you're using platform data, DT or
even ACPI - this code could *not* care less.  None of that comes anywhere
near what this patch does.  It merely provides a way to collect up
individual devices from co-operating drivers, and control their binding
such that a subsystem like DRM or ALSA can be presented with a "card"
level view of the hardware rather than a multi-device medusa with all
the buggy, racy, crap fsckage that people come up to make that kind of
thing work.

Now, as for the binding above, first, what does "eg" mean... and
secondly, how would a binding which refers to crtcs and connectors
have anything to do with ALSA?  Clearly this isn't an example of a
binding for an ALSA use, which was talked about in the very first
line of the above commit commentry.  So it's quite clear that what is
given there is an example of how it /could/ be used.

I suppose I could have instead turned imx-drm into a completely unusable
mess by not coming up with some kind of binding, and instead submitted
a whole pile of completely untested code.  Alternatively, I could've
used the OF binding as you're suggesting, but that would mean radically
changing the /existing/ bindings for the IPU as a whole - something
which others are better suited at as they have a /much/ better
understanding of the complexities of this hardware than I.

So, what I have done is implemented - for a driver in staging which is
still subject to ongoing development and non-stable DT bindings -
something which allows forward progress with a *minimum* of disruption
to the existing DT bindings for everyone, while still allowing forward
progress.

Better bindings for imx-drm are currently being worked on.  Philipp
Zabel of Pengutronix is currently looking at it, and has posted many
RFC patches on this very subject, including moving the V4L2 OF helpers
to a more suitable location.  OF people have been involved in that
discussion over the preceding weeks, and there's a working implementation
of imx-drm using these helpers from v4l2.

I'm finding people who are working in the same area and trying to get
everyone talking to each other so that we /do/ end up with a set of
bindings for the display stuff which are suitable for everyone.  Tomi
from TI has already expressed his input to this ongoing discussion.

You're welcome to get involved in those discussions too.

I hope this makes it clear, and clears up the confusion.

Thanks.

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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-26 22:19       ` Russell King - ARM Linux
@ 2014-03-06 11:46         ` Guennadi Liakhovetski
  -1 siblings, 0 replies; 219+ messages in thread
From: Guennadi Liakhovetski @ 2014-03-06 11:46 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: David Airlie, Greg Kroah-Hartman, Sascha Hauer, Shawn Guo, devel,
	dri-devel, linux-arm-kernel, Linux Media Mailing List,
	Laurent Pinchart, Sylwester Nawrocki

Hi Russell,

Sorry for a long delay.

On Wed, 26 Feb 2014, Russell King - ARM Linux wrote:

[snip]

> Better bindings for imx-drm are currently being worked on.  Philipp
> Zabel of Pengutronix is currently looking at it, and has posted many
> RFC patches on this very subject, including moving the V4L2 OF helpers
> to a more suitable location.  OF people have been involved in that
> discussion over the preceding weeks, and there's a working implementation
> of imx-drm using these helpers from v4l2.

Yes, I'm aware of that patch series, and I do look at the discussion from 
time to time, unfortunately I don't have too much time for it now. But in 
any case if this work is going to be used with imx-drm too, that should be 
a good direction to take, I think.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-06 11:46         ` Guennadi Liakhovetski
  0 siblings, 0 replies; 219+ messages in thread
From: Guennadi Liakhovetski @ 2014-03-06 11:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

Sorry for a long delay.

On Wed, 26 Feb 2014, Russell King - ARM Linux wrote:

[snip]

> Better bindings for imx-drm are currently being worked on.  Philipp
> Zabel of Pengutronix is currently looking at it, and has posted many
> RFC patches on this very subject, including moving the V4L2 OF helpers
> to a more suitable location.  OF people have been involved in that
> discussion over the preceding weeks, and there's a working implementation
> of imx-drm using these helpers from v4l2.

Yes, I'm aware of that patch series, and I do look at the discussion from 
time to time, unfortunately I don't have too much time for it now. But in 
any case if this work is going to be used with imx-drm too, that should be 
a good direction to take, I think.

Thanks
Guennadi
---
Guennadi Liakhovetski, Ph.D.
Freelance Open-Source Software Developer
http://www.open-technology.de/

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-02-26 22:19       ` Russell King - ARM Linux
  (?)
@ 2014-03-06 23:24         ` Laurent Pinchart
  -1 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-06 23:24 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Guennadi Liakhovetski, David Airlie, Greg Kroah-Hartman,
	Sascha Hauer, Shawn Guo, devel, dri-devel, linux-arm-kernel,
	Linux Media Mailing List, Sylwester Nawrocki

Hi Russell,

Time for me to jump in. The more, the merrier I suppose.

On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > Hi Russell
> > 
> > (I suspect this my email will be rejected by ALKML too like other my
> > recent emails, but at least other MLs will pick it up and individual CCs
> > too, so, if replying, maybe it would be good to keep my entire reply, all
> > the more that it's going to be very short)
> > 
> > On Thu, 2 Jan 2014, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > 
> > It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't
> > notice this and other related patches in a "clean up" series, and now this
> > patch is already in the mainline. But at least I'd like to ask whether the
> > bindings, defined in
> > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for
> > this job, and - if so - why have they been found unsuitable? Wouldn't it
> > have been better to use and - if needed - extend them to cover any
> > deficiencies? Even though the implementation is currently located under
> > drivers/media/v4l2-code/ it's pretty generic and should be easily
> > transferable to a more generic location.
> 
> The component helpers have nothing to do with DT apart from solving
> the problem of how to deal with subsystems which expect a single device,
> but we have a group of devices and their individual drivers to cope with.
> Subsystems like DRM and ALSA.

(and V4L2)

Point duly taken. First of all I want to mention that your proposal is 
greatly appreciated. This is a problem that crosses subsystem boundaries, and 
should thus be addressed centrally.

However, we (as in the V4L2 community, and me personally) would have 
appreciated to be CC'ed on the proposal. As you might know we already had a 
solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
core/v4l2-async.c. Whether or not this solution should have been made generic 
instead of coming up with a new separate implementation would of course have 
been debatable, but the most important point would have been to make sure that 
v4l2-async could easily be implemented on top of the common component 
architecture.

The topic is particularly hot given that a similar solution was also proposed 
as part of the now defunct (or at least hibernating) common display framework. 
If I had replied to this mail thread without sleeping on it first I might not 
have known better and have got half-paranoid, wondereding whether there had 
been a deliberate attempt to fast-track this API before the V4L2 developers 
noticed. To be perfectly clear, there is *NO* implicit or explicit such 
accusation here, as I know better.

Let's all take this as a positive opportunity to cooperate more closely, media 
devices still need a huge effort to be cleanly supported on modern hardware, 
and we'll need all the development power we can get.

Accordingly, I would like to comment on the component API, despite the fact 
that it has been merged in mainline already. The first thing that I believe is 
missing is documentation. Do you have any pending patch for that, either as 
kerneldoc or as a text file for Documentation/ ? As I've read the code to 
understand it I might have missed so design goals, so please bear with the 
stupid questions that may follow.

I'll first provide a brief comparison of the two models to make the rest of 
the comments easier to understand.

v4l2-async calls the component master object v4l2_async_notifier. The base 
component child object is a v4l2_subdev instance instead of being a plain 
device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
the component framework stores objects, except that the list head is directly 
embedded inside the v4l2_subdev structure instead of being part of a separate 
structure allocated by the framework.

The notifier has three callback functions, bound, complete and unbind. The 
bound function is called when one component has been bound to the master. 
Similarly the unbind function is called when one component is about to be 
unbound from the master. The complete function is called when all components 
have been bound, and is thus equivalent to the bind function of the component 
framework.

Notifiers are registered along with a list of match entries. A match entry is 
roughly equivalent to the compare function passed to 
component_master_add_child, except that it includes built-in support for 
matching on an OF node, dev_name or I2C bus number and child address.

Whenever a subdev (component child) is registered with 
v4l2_async_register_subdev (equivalent to component_add), the list of 
notifiers (masters) is walked and their match entries are processed. If a 
matching entry is found the subdev is bound to the notifier immediately, 
otherwise it is added to a list of unbound subdevices (component_list). 
Whenever a notifier (component master) is registered with 
v4l2_async_notifier_register (component_master_add) the list of unbound 
subdevs is walked and every match entry of the notifier is tested. If a 
matching entry is found the subdev is bound to the notifier.

I've seen a couple of core differences in concept between your component model 
and the v4l2-async model:

- The component framework uses private master and component structures. 
Wouldn't it simplify the code from a memory management point of view to expose 
the master structure (which would then be embedded in driver-specific 
structures) and the component structure (which would be embedded in struct 
device) ? The latter would be slightly more intrusive from a struct device 
point of view, so I don't have a strong opinion there yet, exposing the master 
structure only might be better.

- The component framework requires the master to provide an add_components 
operation that will call the component_master_add_child function for every 
component it needs, with a compare function. The add child function is called 
when the master is registered, and then for every component added to the 
system. I'm not sure to understand the design decisions behind this, but these 
two levels of indirection appear pretty complex and confusing. Wouldn't it be 
simpler to pass an array of match entries to the master registration function 
instead and remove the add_components operation ? A match entry would 
basically be a structure with a compare function and a compare_data pointer.

We could also extend the match entry with explicit support for OF node and I2C 
bus number + address matching as those are the most common cases, or at least 
provide a couple of standard compare functions for those cases.

- The component framework doesn't provide partial bind support. Children are 
bound to the master only when all children are available. This makes it 
impossible in practice to implement v4l2-async on top of the component 
framework. What would you think about adding optional partial bind support ? 
The master operations would then have partial bind, complete bind, partial 
unbind and complete unbind functions. Drivers that only need full bind support 
could set the partial bind and unbind functions to NULL.

> It is completely agnostic to whether you're using platform data, DT or
> even ACPI - this code could *not* care less.  None of that comes anywhere
> near what this patch does.  It merely provides a way to collect up
> individual devices from co-operating drivers, and control their binding
> such that a subsystem like DRM or ALSA can be presented with a "card"
> level view of the hardware rather than a multi-device medusa with all
> the buggy, racy, crap fsckage that people come up to make that kind of
> thing work.
> 
> Now, as for the binding above, first, what does "eg" mean... and
> secondly, how would a binding which refers to crtcs and connectors
> have anything to do with ALSA?  Clearly this isn't an example of a
> binding for an ALSA use, which was talked about in the very first
> line of the above commit commentry.  So it's quite clear that what is
> given there is an example of how it /could/ be used.
> 
> I suppose I could have instead turned imx-drm into a completely unusable
> mess by not coming up with some kind of binding, and instead submitted
> a whole pile of completely untested code.  Alternatively, I could've
> used the OF binding as you're suggesting, but that would mean radically
> changing the /existing/ bindings for the IPU as a whole - something
> which others are better suited at as they have a /much/ better
> understanding of the complexities of this hardware than I.
> 
> So, what I have done is implemented - for a driver in staging which is
> still subject to ongoing development and non-stable DT bindings -
> something which allows forward progress with a *minimum* of disruption
> to the existing DT bindings for everyone, while still allowing forward
> progress.
> 
> Better bindings for imx-drm are currently being worked on.  Philipp
> Zabel of Pengutronix is currently looking at it, and has posted many
> RFC patches on this very subject, including moving the V4L2 OF helpers
> to a more suitable location.  OF people have been involved in that
> discussion over the preceding weeks, and there's a working implementation
> of imx-drm using these helpers from v4l2.
> 
> I'm finding people who are working in the same area and trying to get
> everyone talking to each other so that we /do/ end up with a set of
> bindings for the display stuff which are suitable for everyone.  Tomi
> from TI has already expressed his input to this ongoing discussion.
> 
> You're welcome to get involved in those discussions too.
> 
> I hope this makes it clear, and clears up the confusion.
> 
> Thanks.

-- 
Regards,

Laurent Pinchart

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-06 23:24         ` Laurent Pinchart
  0 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-06 23:24 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

Time for me to jump in. The more, the merrier I suppose.

On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > Hi Russell
> > 
> > (I suspect this my email will be rejected by ALKML too like other my
> > recent emails, but at least other MLs will pick it up and individual CCs
> > too, so, if replying, maybe it would be good to keep my entire reply, all
> > the more that it's going to be very short)
> > 
> > On Thu, 2 Jan 2014, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > 
> > It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't
> > notice this and other related patches in a "clean up" series, and now this
> > patch is already in the mainline. But at least I'd like to ask whether the
> > bindings, defined in
> > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for
> > this job, and - if so - why have they been found unsuitable? Wouldn't it
> > have been better to use and - if needed - extend them to cover any
> > deficiencies? Even though the implementation is currently located under
> > drivers/media/v4l2-code/ it's pretty generic and should be easily
> > transferable to a more generic location.
> 
> The component helpers have nothing to do with DT apart from solving
> the problem of how to deal with subsystems which expect a single device,
> but we have a group of devices and their individual drivers to cope with.
> Subsystems like DRM and ALSA.

(and V4L2)

Point duly taken. First of all I want to mention that your proposal is 
greatly appreciated. This is a problem that crosses subsystem boundaries, and 
should thus be addressed centrally.

However, we (as in the V4L2 community, and me personally) would have 
appreciated to be CC'ed on the proposal. As you might know we already had a 
solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
core/v4l2-async.c. Whether or not this solution should have been made generic 
instead of coming up with a new separate implementation would of course have 
been debatable, but the most important point would have been to make sure that 
v4l2-async could easily be implemented on top of the common component 
architecture.

The topic is particularly hot given that a similar solution was also proposed 
as part of the now defunct (or at least hibernating) common display framework. 
If I had replied to this mail thread without sleeping on it first I might not 
have known better and have got half-paranoid, wondereding whether there had 
been a deliberate attempt to fast-track this API before the V4L2 developers 
noticed. To be perfectly clear, there is *NO* implicit or explicit such 
accusation here, as I know better.

Let's all take this as a positive opportunity to cooperate more closely, media 
devices still need a huge effort to be cleanly supported on modern hardware, 
and we'll need all the development power we can get.

Accordingly, I would like to comment on the component API, despite the fact 
that it has been merged in mainline already. The first thing that I believe is 
missing is documentation. Do you have any pending patch for that, either as 
kerneldoc or as a text file for Documentation/ ? As I've read the code to 
understand it I might have missed so design goals, so please bear with the 
stupid questions that may follow.

I'll first provide a brief comparison of the two models to make the rest of 
the comments easier to understand.

v4l2-async calls the component master object v4l2_async_notifier. The base 
component child object is a v4l2_subdev instance instead of being a plain 
device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
the component framework stores objects, except that the list head is directly 
embedded inside the v4l2_subdev structure instead of being part of a separate 
structure allocated by the framework.

The notifier has three callback functions, bound, complete and unbind. The 
bound function is called when one component has been bound to the master. 
Similarly the unbind function is called when one component is about to be 
unbound from the master. The complete function is called when all components 
have been bound, and is thus equivalent to the bind function of the component 
framework.

Notifiers are registered along with a list of match entries. A match entry is 
roughly equivalent to the compare function passed to 
component_master_add_child, except that it includes built-in support for 
matching on an OF node, dev_name or I2C bus number and child address.

Whenever a subdev (component child) is registered with 
v4l2_async_register_subdev (equivalent to component_add), the list of 
notifiers (masters) is walked and their match entries are processed. If a 
matching entry is found the subdev is bound to the notifier immediately, 
otherwise it is added to a list of unbound subdevices (component_list). 
Whenever a notifier (component master) is registered with 
v4l2_async_notifier_register (component_master_add) the list of unbound 
subdevs is walked and every match entry of the notifier is tested. If a 
matching entry is found the subdev is bound to the notifier.

I've seen a couple of core differences in concept between your component model 
and the v4l2-async model:

- The component framework uses private master and component structures. 
Wouldn't it simplify the code from a memory management point of view to expose 
the master structure (which would then be embedded in driver-specific 
structures) and the component structure (which would be embedded in struct 
device) ? The latter would be slightly more intrusive from a struct device 
point of view, so I don't have a strong opinion there yet, exposing the master 
structure only might be better.

- The component framework requires the master to provide an add_components 
operation that will call the component_master_add_child function for every 
component it needs, with a compare function. The add child function is called 
when the master is registered, and then for every component added to the 
system. I'm not sure to understand the design decisions behind this, but these 
two levels of indirection appear pretty complex and confusing. Wouldn't it be 
simpler to pass an array of match entries to the master registration function 
instead and remove the add_components operation ? A match entry would 
basically be a structure with a compare function and a compare_data pointer.

We could also extend the match entry with explicit support for OF node and I2C 
bus number + address matching as those are the most common cases, or at least 
provide a couple of standard compare functions for those cases.

- The component framework doesn't provide partial bind support. Children are 
bound to the master only when all children are available. This makes it 
impossible in practice to implement v4l2-async on top of the component 
framework. What would you think about adding optional partial bind support ? 
The master operations would then have partial bind, complete bind, partial 
unbind and complete unbind functions. Drivers that only need full bind support 
could set the partial bind and unbind functions to NULL.

> It is completely agnostic to whether you're using platform data, DT or
> even ACPI - this code could *not* care less.  None of that comes anywhere
> near what this patch does.  It merely provides a way to collect up
> individual devices from co-operating drivers, and control their binding
> such that a subsystem like DRM or ALSA can be presented with a "card"
> level view of the hardware rather than a multi-device medusa with all
> the buggy, racy, crap fsckage that people come up to make that kind of
> thing work.
> 
> Now, as for the binding above, first, what does "eg" mean... and
> secondly, how would a binding which refers to crtcs and connectors
> have anything to do with ALSA?  Clearly this isn't an example of a
> binding for an ALSA use, which was talked about in the very first
> line of the above commit commentry.  So it's quite clear that what is
> given there is an example of how it /could/ be used.
> 
> I suppose I could have instead turned imx-drm into a completely unusable
> mess by not coming up with some kind of binding, and instead submitted
> a whole pile of completely untested code.  Alternatively, I could've
> used the OF binding as you're suggesting, but that would mean radically
> changing the /existing/ bindings for the IPU as a whole - something
> which others are better suited at as they have a /much/ better
> understanding of the complexities of this hardware than I.
> 
> So, what I have done is implemented - for a driver in staging which is
> still subject to ongoing development and non-stable DT bindings -
> something which allows forward progress with a *minimum* of disruption
> to the existing DT bindings for everyone, while still allowing forward
> progress.
> 
> Better bindings for imx-drm are currently being worked on.  Philipp
> Zabel of Pengutronix is currently looking at it, and has posted many
> RFC patches on this very subject, including moving the V4L2 OF helpers
> to a more suitable location.  OF people have been involved in that
> discussion over the preceding weeks, and there's a working implementation
> of imx-drm using these helpers from v4l2.
> 
> I'm finding people who are working in the same area and trying to get
> everyone talking to each other so that we /do/ end up with a set of
> bindings for the display stuff which are suitable for everyone.  Tomi
> from TI has already expressed his input to this ongoing discussion.
> 
> You're welcome to get involved in those discussions too.
> 
> I hope this makes it clear, and clears up the confusion.
> 
> Thanks.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-06 23:24         ` Laurent Pinchart
  0 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-06 23:24 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, David Airlie, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Sylwester Nawrocki, Shawn Guo, Guennadi Liakhovetski,
	linux-arm-kernel, Linux Media Mailing List

Hi Russell,

Time for me to jump in. The more, the merrier I suppose.

On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > Hi Russell
> > 
> > (I suspect this my email will be rejected by ALKML too like other my
> > recent emails, but at least other MLs will pick it up and individual CCs
> > too, so, if replying, maybe it would be good to keep my entire reply, all
> > the more that it's going to be very short)
> > 
> > On Thu, 2 Jan 2014, Russell King wrote:
> > > Subsystems such as ALSA, DRM and others require a single card-level
> > > device structure to represent a subsystem.  However, firmware tends to
> > > describe the individual devices and the connections between them.
> > > 
> > > Therefore, we need a way to gather up the individual component devices
> > > together, and indicate when we have all the component devices.
> > > 
> > > We do this in DT by providing a "superdevice" node which specifies
> > > the components, eg:
> > > 	imx-drm {
> > > 		compatible = "fsl,drm";
> > > 		crtcs = <&ipu1>;
> > > 		connectors = <&hdmi>;
> > > 	};
> > 
> > It is a pity linux-media wasn't CC'ed and apparently V4L developers didn't
> > notice this and other related patches in a "clean up" series, and now this
> > patch is already in the mainline. But at least I'd like to ask whether the
> > bindings, defined in
> > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered for
> > this job, and - if so - why have they been found unsuitable? Wouldn't it
> > have been better to use and - if needed - extend them to cover any
> > deficiencies? Even though the implementation is currently located under
> > drivers/media/v4l2-code/ it's pretty generic and should be easily
> > transferable to a more generic location.
> 
> The component helpers have nothing to do with DT apart from solving
> the problem of how to deal with subsystems which expect a single device,
> but we have a group of devices and their individual drivers to cope with.
> Subsystems like DRM and ALSA.

(and V4L2)

Point duly taken. First of all I want to mention that your proposal is 
greatly appreciated. This is a problem that crosses subsystem boundaries, and 
should thus be addressed centrally.

However, we (as in the V4L2 community, and me personally) would have 
appreciated to be CC'ed on the proposal. As you might know we already had a 
solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
core/v4l2-async.c. Whether or not this solution should have been made generic 
instead of coming up with a new separate implementation would of course have 
been debatable, but the most important point would have been to make sure that 
v4l2-async could easily be implemented on top of the common component 
architecture.

The topic is particularly hot given that a similar solution was also proposed 
as part of the now defunct (or at least hibernating) common display framework. 
If I had replied to this mail thread without sleeping on it first I might not 
have known better and have got half-paranoid, wondereding whether there had 
been a deliberate attempt to fast-track this API before the V4L2 developers 
noticed. To be perfectly clear, there is *NO* implicit or explicit such 
accusation here, as I know better.

Let's all take this as a positive opportunity to cooperate more closely, media 
devices still need a huge effort to be cleanly supported on modern hardware, 
and we'll need all the development power we can get.

Accordingly, I would like to comment on the component API, despite the fact 
that it has been merged in mainline already. The first thing that I believe is 
missing is documentation. Do you have any pending patch for that, either as 
kerneldoc or as a text file for Documentation/ ? As I've read the code to 
understand it I might have missed so design goals, so please bear with the 
stupid questions that may follow.

I'll first provide a brief comparison of the two models to make the rest of 
the comments easier to understand.

v4l2-async calls the component master object v4l2_async_notifier. The base 
component child object is a v4l2_subdev instance instead of being a plain 
device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
the component framework stores objects, except that the list head is directly 
embedded inside the v4l2_subdev structure instead of being part of a separate 
structure allocated by the framework.

The notifier has three callback functions, bound, complete and unbind. The 
bound function is called when one component has been bound to the master. 
Similarly the unbind function is called when one component is about to be 
unbound from the master. The complete function is called when all components 
have been bound, and is thus equivalent to the bind function of the component 
framework.

Notifiers are registered along with a list of match entries. A match entry is 
roughly equivalent to the compare function passed to 
component_master_add_child, except that it includes built-in support for 
matching on an OF node, dev_name or I2C bus number and child address.

Whenever a subdev (component child) is registered with 
v4l2_async_register_subdev (equivalent to component_add), the list of 
notifiers (masters) is walked and their match entries are processed. If a 
matching entry is found the subdev is bound to the notifier immediately, 
otherwise it is added to a list of unbound subdevices (component_list). 
Whenever a notifier (component master) is registered with 
v4l2_async_notifier_register (component_master_add) the list of unbound 
subdevs is walked and every match entry of the notifier is tested. If a 
matching entry is found the subdev is bound to the notifier.

I've seen a couple of core differences in concept between your component model 
and the v4l2-async model:

- The component framework uses private master and component structures. 
Wouldn't it simplify the code from a memory management point of view to expose 
the master structure (which would then be embedded in driver-specific 
structures) and the component structure (which would be embedded in struct 
device) ? The latter would be slightly more intrusive from a struct device 
point of view, so I don't have a strong opinion there yet, exposing the master 
structure only might be better.

- The component framework requires the master to provide an add_components 
operation that will call the component_master_add_child function for every 
component it needs, with a compare function. The add child function is called 
when the master is registered, and then for every component added to the 
system. I'm not sure to understand the design decisions behind this, but these 
two levels of indirection appear pretty complex and confusing. Wouldn't it be 
simpler to pass an array of match entries to the master registration function 
instead and remove the add_components operation ? A match entry would 
basically be a structure with a compare function and a compare_data pointer.

We could also extend the match entry with explicit support for OF node and I2C 
bus number + address matching as those are the most common cases, or at least 
provide a couple of standard compare functions for those cases.

- The component framework doesn't provide partial bind support. Children are 
bound to the master only when all children are available. This makes it 
impossible in practice to implement v4l2-async on top of the component 
framework. What would you think about adding optional partial bind support ? 
The master operations would then have partial bind, complete bind, partial 
unbind and complete unbind functions. Drivers that only need full bind support 
could set the partial bind and unbind functions to NULL.

> It is completely agnostic to whether you're using platform data, DT or
> even ACPI - this code could *not* care less.  None of that comes anywhere
> near what this patch does.  It merely provides a way to collect up
> individual devices from co-operating drivers, and control their binding
> such that a subsystem like DRM or ALSA can be presented with a "card"
> level view of the hardware rather than a multi-device medusa with all
> the buggy, racy, crap fsckage that people come up to make that kind of
> thing work.
> 
> Now, as for the binding above, first, what does "eg" mean... and
> secondly, how would a binding which refers to crtcs and connectors
> have anything to do with ALSA?  Clearly this isn't an example of a
> binding for an ALSA use, which was talked about in the very first
> line of the above commit commentry.  So it's quite clear that what is
> given there is an example of how it /could/ be used.
> 
> I suppose I could have instead turned imx-drm into a completely unusable
> mess by not coming up with some kind of binding, and instead submitted
> a whole pile of completely untested code.  Alternatively, I could've
> used the OF binding as you're suggesting, but that would mean radically
> changing the /existing/ bindings for the IPU as a whole - something
> which others are better suited at as they have a /much/ better
> understanding of the complexities of this hardware than I.
> 
> So, what I have done is implemented - for a driver in staging which is
> still subject to ongoing development and non-stable DT bindings -
> something which allows forward progress with a *minimum* of disruption
> to the existing DT bindings for everyone, while still allowing forward
> progress.
> 
> Better bindings for imx-drm are currently being worked on.  Philipp
> Zabel of Pengutronix is currently looking at it, and has posted many
> RFC patches on this very subject, including moving the V4L2 OF helpers
> to a more suitable location.  OF people have been involved in that
> discussion over the preceding weeks, and there's a working implementation
> of imx-drm using these helpers from v4l2.
> 
> I'm finding people who are working in the same area and trying to get
> everyone talking to each other so that we /do/ end up with a set of
> bindings for the display stuff which are suitable for everyone.  Tomi
> from TI has already expressed his input to this ongoing discussion.
> 
> You're welcome to get involved in those discussions too.
> 
> I hope this makes it clear, and clears up the confusion.
> 
> Thanks.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-03-06 23:24         ` Laurent Pinchart
  (?)
@ 2014-03-19 17:22           ` Laurent Pinchart
  -1 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-19 17:22 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: Guennadi Liakhovetski, David Airlie, Greg Kroah-Hartman,
	Sascha Hauer, Shawn Guo, devel, dri-devel, linux-arm-kernel,
	Linux Media Mailing List, Sylwester Nawrocki, Philipp Zabel

Hi Russell,

(CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
component framework)

Could you please have a look at the questions below and provide an answer when 
you'll have time ? I'd like to bridge the gap between the component and the 
V4L2 asynchronous registration implementations.

On Friday 07 March 2014 00:24:33 Laurent Pinchart wrote:
> On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> > On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > > Hi Russell
> > > 
> > > (I suspect this my email will be rejected by ALKML too like other my
> > > recent emails, but at least other MLs will pick it up and individual CCs
> > > too, so, if replying, maybe it would be good to keep my entire reply,
> > > all the more that it's going to be very short)
> > > 
> > > On Thu, 2 Jan 2014, Russell King wrote:
> > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > device structure to represent a subsystem.  However, firmware tends to
> > > > describe the individual devices and the connections between them.
> > > > 
> > > > Therefore, we need a way to gather up the individual component devices
> > > > together, and indicate when we have all the component devices.
> > > > 
> > > > We do this in DT by providing a "superdevice" node which specifies
> > > > 
> > > > the components, eg:
> > > > 	imx-drm {
> > > > 		compatible = "fsl,drm";
> > > > 		crtcs = <&ipu1>;
> > > > 		connectors = <&hdmi>;
> > > > 	};
> > > 
> > > It is a pity linux-media wasn't CC'ed and apparently V4L developers
> > > didn't notice this and other related patches in a "clean up" series, and
> > > now this patch is already in the mainline. But at least I'd like to ask
> > > whether the bindings, defined in
> > > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered
> > > for this job, and - if so - why have they been found unsuitable?
> > > Wouldn't it have been better to use and - if needed - extend them to
> > > cover any deficiencies? Even though the implementation is currently
> > > located under drivers/media/v4l2-code/ it's pretty generic and should be
> > > easily transferable to a more generic location.
> > 
> > The component helpers have nothing to do with DT apart from solving
> > the problem of how to deal with subsystems which expect a single device,
> > but we have a group of devices and their individual drivers to cope with.
> > Subsystems like DRM and ALSA.
> 
> (and V4L2)
> 
> Point duly taken. First of all I want to mention that your proposal is
> greatly appreciated. This is a problem that crosses subsystem boundaries,
> and should thus be addressed centrally.
> 
> However, we (as in the V4L2 community, and me personally) would have
> appreciated to be CC'ed on the proposal. As you might know we already had a
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c. Whether or not this solution should have been made
> generic instead of coming up with a new separate implementation would of
> course have been debatable, but the most important point would have been to
> make sure that v4l2-async could easily be implemented on top of the common
> component architecture.
> 
> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. If I had replied to this mail thread without sleeping on
> it first I might not have known better and have got half-paranoid,
> wondereding whether there had been a deliberate attempt to fast-track this
> API before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.
> 
> Let's all take this as a positive opportunity to cooperate more closely,
> media devices still need a huge effort to be cleanly supported on modern
> hardware, and we'll need all the development power we can get.
> 
> Accordingly, I would like to comment on the component API, despite the fact
> that it has been merged in mainline already. The first thing that I believe
> is missing is documentation. Do you have any pending patch for that, either
> as kerneldoc or as a text file for Documentation/ ? As I've read the code
> to understand it I might have missed so design goals, so please bear with
> the stupid questions that may follow.
> 
> I'll first provide a brief comparison of the two models to make the rest of
> the comments easier to understand.
> 
> v4l2-async calls the component master object v4l2_async_notifier. The base
> component child object is a v4l2_subdev instance instead of being a plain
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to
> how the component framework stores objects, except that the list head is
> directly embedded inside the v4l2_subdev structure instead of being part of
> a separate structure allocated by the framework.
> 
> The notifier has three callback functions, bound, complete and unbind. The
> bound function is called when one component has been bound to the master.
> Similarly the unbind function is called when one component is about to be
> unbound from the master. The complete function is called when all components
> have been bound, and is thus equivalent to the bind function of the
> component framework.
> 
> Notifiers are registered along with a list of match entries. A match entry
> is roughly equivalent to the compare function passed to
> component_master_add_child, except that it includes built-in support for
> matching on an OF node, dev_name or I2C bus number and child address.
> 
> Whenever a subdev (component child) is registered with
> v4l2_async_register_subdev (equivalent to component_add), the list of
> notifiers (masters) is walked and their match entries are processed. If a
> matching entry is found the subdev is bound to the notifier immediately,
> otherwise it is added to a list of unbound subdevices (component_list).
> Whenever a notifier (component master) is registered with
> v4l2_async_notifier_register (component_master_add) the list of unbound
> subdevs is walked and every match entry of the notifier is tested. If a
> matching entry is found the subdev is bound to the notifier.
> 
> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures.
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in
> driver-specific structures) and the component structure (which would be
> embedded in struct device) ? The latter would be slightly more intrusive
> from a struct device point of view, so I don't have a strong opinion there
> yet, exposing the master structure only might be better.
> 
> - The component framework requires the master to provide an add_components
> operation that will call the component_master_add_child function for every
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added to
> the system. I'm not sure to understand the design decisions behind this,
> but these two levels of indirection appear pretty complex and confusing.
> Wouldn't it be simpler to pass an array of match entries to the master
> registration function instead and remove the add_components operation ? A
> match entry would basically be a structure with a compare function and a
> compare_data pointer.
> 
> We could also extend the match entry with explicit support for OF node and
> I2C bus number + address matching as those are the most common cases, or at
> least provide a couple of standard compare functions for those cases.
> 
> - The component framework doesn't provide partial bind support. Children are
> bound to the master only when all children are available. This makes it
> impossible in practice to implement v4l2-async on top of the component
> framework. What would you think about adding optional partial bind support
> ? The master operations would then have partial bind, complete bind,
> partial unbind and complete unbind functions. Drivers that only need full
> bind support could set the partial bind and unbind functions to NULL.
> 
> > It is completely agnostic to whether you're using platform data, DT or
> > even ACPI - this code could *not* care less.  None of that comes anywhere
> > near what this patch does.  It merely provides a way to collect up
> > individual devices from co-operating drivers, and control their binding
> > such that a subsystem like DRM or ALSA can be presented with a "card"
> > level view of the hardware rather than a multi-device medusa with all
> > the buggy, racy, crap fsckage that people come up to make that kind of
> > thing work.
> > 
> > Now, as for the binding above, first, what does "eg" mean... and
> > secondly, how would a binding which refers to crtcs and connectors
> > have anything to do with ALSA?  Clearly this isn't an example of a
> > binding for an ALSA use, which was talked about in the very first
> > line of the above commit commentry.  So it's quite clear that what is
> > given there is an example of how it /could/ be used.
> > 
> > I suppose I could have instead turned imx-drm into a completely unusable
> > mess by not coming up with some kind of binding, and instead submitted
> > a whole pile of completely untested code.  Alternatively, I could've
> > used the OF binding as you're suggesting, but that would mean radically
> > changing the /existing/ bindings for the IPU as a whole - something
> > which others are better suited at as they have a /much/ better
> > understanding of the complexities of this hardware than I.
> > 
> > So, what I have done is implemented - for a driver in staging which is
> > still subject to ongoing development and non-stable DT bindings -
> > something which allows forward progress with a *minimum* of disruption
> > to the existing DT bindings for everyone, while still allowing forward
> > progress.
> > 
> > Better bindings for imx-drm are currently being worked on.  Philipp
> > Zabel of Pengutronix is currently looking at it, and has posted many
> > RFC patches on this very subject, including moving the V4L2 OF helpers
> > to a more suitable location.  OF people have been involved in that
> > discussion over the preceding weeks, and there's a working implementation
> > of imx-drm using these helpers from v4l2.
> > 
> > I'm finding people who are working in the same area and trying to get
> > everyone talking to each other so that we /do/ end up with a set of
> > bindings for the display stuff which are suitable for everyone.  Tomi
> > from TI has already expressed his input to this ongoing discussion.
> > 
> > You're welcome to get involved in those discussions too.
> > 
> > I hope this makes it clear, and clears up the confusion.
> > 
> > Thanks.

-- 
Regards,

Laurent Pinchart


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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-19 17:22           ` Laurent Pinchart
  0 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-19 17:22 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Russell,

(CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
component framework)

Could you please have a look at the questions below and provide an answer when 
you'll have time ? I'd like to bridge the gap between the component and the 
V4L2 asynchronous registration implementations.

On Friday 07 March 2014 00:24:33 Laurent Pinchart wrote:
> On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> > On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > > Hi Russell
> > > 
> > > (I suspect this my email will be rejected by ALKML too like other my
> > > recent emails, but at least other MLs will pick it up and individual CCs
> > > too, so, if replying, maybe it would be good to keep my entire reply,
> > > all the more that it's going to be very short)
> > > 
> > > On Thu, 2 Jan 2014, Russell King wrote:
> > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > device structure to represent a subsystem.  However, firmware tends to
> > > > describe the individual devices and the connections between them.
> > > > 
> > > > Therefore, we need a way to gather up the individual component devices
> > > > together, and indicate when we have all the component devices.
> > > > 
> > > > We do this in DT by providing a "superdevice" node which specifies
> > > > 
> > > > the components, eg:
> > > > 	imx-drm {
> > > > 		compatible = "fsl,drm";
> > > > 		crtcs = <&ipu1>;
> > > > 		connectors = <&hdmi>;
> > > > 	};
> > > 
> > > It is a pity linux-media wasn't CC'ed and apparently V4L developers
> > > didn't notice this and other related patches in a "clean up" series, and
> > > now this patch is already in the mainline. But at least I'd like to ask
> > > whether the bindings, defined in
> > > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered
> > > for this job, and - if so - why have they been found unsuitable?
> > > Wouldn't it have been better to use and - if needed - extend them to
> > > cover any deficiencies? Even though the implementation is currently
> > > located under drivers/media/v4l2-code/ it's pretty generic and should be
> > > easily transferable to a more generic location.
> > 
> > The component helpers have nothing to do with DT apart from solving
> > the problem of how to deal with subsystems which expect a single device,
> > but we have a group of devices and their individual drivers to cope with.
> > Subsystems like DRM and ALSA.
> 
> (and V4L2)
> 
> Point duly taken. First of all I want to mention that your proposal is
> greatly appreciated. This is a problem that crosses subsystem boundaries,
> and should thus be addressed centrally.
> 
> However, we (as in the V4L2 community, and me personally) would have
> appreciated to be CC'ed on the proposal. As you might know we already had a
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c. Whether or not this solution should have been made
> generic instead of coming up with a new separate implementation would of
> course have been debatable, but the most important point would have been to
> make sure that v4l2-async could easily be implemented on top of the common
> component architecture.
> 
> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. If I had replied to this mail thread without sleeping on
> it first I might not have known better and have got half-paranoid,
> wondereding whether there had been a deliberate attempt to fast-track this
> API before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.
> 
> Let's all take this as a positive opportunity to cooperate more closely,
> media devices still need a huge effort to be cleanly supported on modern
> hardware, and we'll need all the development power we can get.
> 
> Accordingly, I would like to comment on the component API, despite the fact
> that it has been merged in mainline already. The first thing that I believe
> is missing is documentation. Do you have any pending patch for that, either
> as kerneldoc or as a text file for Documentation/ ? As I've read the code
> to understand it I might have missed so design goals, so please bear with
> the stupid questions that may follow.
> 
> I'll first provide a brief comparison of the two models to make the rest of
> the comments easier to understand.
> 
> v4l2-async calls the component master object v4l2_async_notifier. The base
> component child object is a v4l2_subdev instance instead of being a plain
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to
> how the component framework stores objects, except that the list head is
> directly embedded inside the v4l2_subdev structure instead of being part of
> a separate structure allocated by the framework.
> 
> The notifier has three callback functions, bound, complete and unbind. The
> bound function is called when one component has been bound to the master.
> Similarly the unbind function is called when one component is about to be
> unbound from the master. The complete function is called when all components
> have been bound, and is thus equivalent to the bind function of the
> component framework.
> 
> Notifiers are registered along with a list of match entries. A match entry
> is roughly equivalent to the compare function passed to
> component_master_add_child, except that it includes built-in support for
> matching on an OF node, dev_name or I2C bus number and child address.
> 
> Whenever a subdev (component child) is registered with
> v4l2_async_register_subdev (equivalent to component_add), the list of
> notifiers (masters) is walked and their match entries are processed. If a
> matching entry is found the subdev is bound to the notifier immediately,
> otherwise it is added to a list of unbound subdevices (component_list).
> Whenever a notifier (component master) is registered with
> v4l2_async_notifier_register (component_master_add) the list of unbound
> subdevs is walked and every match entry of the notifier is tested. If a
> matching entry is found the subdev is bound to the notifier.
> 
> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures.
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in
> driver-specific structures) and the component structure (which would be
> embedded in struct device) ? The latter would be slightly more intrusive
> from a struct device point of view, so I don't have a strong opinion there
> yet, exposing the master structure only might be better.
> 
> - The component framework requires the master to provide an add_components
> operation that will call the component_master_add_child function for every
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added to
> the system. I'm not sure to understand the design decisions behind this,
> but these two levels of indirection appear pretty complex and confusing.
> Wouldn't it be simpler to pass an array of match entries to the master
> registration function instead and remove the add_components operation ? A
> match entry would basically be a structure with a compare function and a
> compare_data pointer.
> 
> We could also extend the match entry with explicit support for OF node and
> I2C bus number + address matching as those are the most common cases, or at
> least provide a couple of standard compare functions for those cases.
> 
> - The component framework doesn't provide partial bind support. Children are
> bound to the master only when all children are available. This makes it
> impossible in practice to implement v4l2-async on top of the component
> framework. What would you think about adding optional partial bind support
> ? The master operations would then have partial bind, complete bind,
> partial unbind and complete unbind functions. Drivers that only need full
> bind support could set the partial bind and unbind functions to NULL.
> 
> > It is completely agnostic to whether you're using platform data, DT or
> > even ACPI - this code could *not* care less.  None of that comes anywhere
> > near what this patch does.  It merely provides a way to collect up
> > individual devices from co-operating drivers, and control their binding
> > such that a subsystem like DRM or ALSA can be presented with a "card"
> > level view of the hardware rather than a multi-device medusa with all
> > the buggy, racy, crap fsckage that people come up to make that kind of
> > thing work.
> > 
> > Now, as for the binding above, first, what does "eg" mean... and
> > secondly, how would a binding which refers to crtcs and connectors
> > have anything to do with ALSA?  Clearly this isn't an example of a
> > binding for an ALSA use, which was talked about in the very first
> > line of the above commit commentry.  So it's quite clear that what is
> > given there is an example of how it /could/ be used.
> > 
> > I suppose I could have instead turned imx-drm into a completely unusable
> > mess by not coming up with some kind of binding, and instead submitted
> > a whole pile of completely untested code.  Alternatively, I could've
> > used the OF binding as you're suggesting, but that would mean radically
> > changing the /existing/ bindings for the IPU as a whole - something
> > which others are better suited at as they have a /much/ better
> > understanding of the complexities of this hardware than I.
> > 
> > So, what I have done is implemented - for a driver in staging which is
> > still subject to ongoing development and non-stable DT bindings -
> > something which allows forward progress with a *minimum* of disruption
> > to the existing DT bindings for everyone, while still allowing forward
> > progress.
> > 
> > Better bindings for imx-drm are currently being worked on.  Philipp
> > Zabel of Pengutronix is currently looking at it, and has posted many
> > RFC patches on this very subject, including moving the V4L2 OF helpers
> > to a more suitable location.  OF people have been involved in that
> > discussion over the preceding weeks, and there's a working implementation
> > of imx-drm using these helpers from v4l2.
> > 
> > I'm finding people who are working in the same area and trying to get
> > everyone talking to each other so that we /do/ end up with a set of
> > bindings for the display stuff which are suitable for everyone.  Tomi
> > from TI has already expressed his input to this ongoing discussion.
> > 
> > You're welcome to get involved in those discussions too.
> > 
> > I hope this makes it clear, and clears up the confusion.
> > 
> > Thanks.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-19 17:22           ` Laurent Pinchart
  0 siblings, 0 replies; 219+ messages in thread
From: Laurent Pinchart @ 2014-03-19 17:22 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: devel, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Sylwester Nawrocki, Guennadi Liakhovetski, linux-arm-kernel,
	Linux Media Mailing List

Hi Russell,

(CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
component framework)

Could you please have a look at the questions below and provide an answer when 
you'll have time ? I'd like to bridge the gap between the component and the 
V4L2 asynchronous registration implementations.

On Friday 07 March 2014 00:24:33 Laurent Pinchart wrote:
> On Wednesday 26 February 2014 22:19:39 Russell King - ARM Linux wrote:
> > On Wed, Feb 26, 2014 at 10:00:25PM +0100, Guennadi Liakhovetski wrote:
> > > Hi Russell
> > > 
> > > (I suspect this my email will be rejected by ALKML too like other my
> > > recent emails, but at least other MLs will pick it up and individual CCs
> > > too, so, if replying, maybe it would be good to keep my entire reply,
> > > all the more that it's going to be very short)
> > > 
> > > On Thu, 2 Jan 2014, Russell King wrote:
> > > > Subsystems such as ALSA, DRM and others require a single card-level
> > > > device structure to represent a subsystem.  However, firmware tends to
> > > > describe the individual devices and the connections between them.
> > > > 
> > > > Therefore, we need a way to gather up the individual component devices
> > > > together, and indicate when we have all the component devices.
> > > > 
> > > > We do this in DT by providing a "superdevice" node which specifies
> > > > 
> > > > the components, eg:
> > > > 	imx-drm {
> > > > 		compatible = "fsl,drm";
> > > > 		crtcs = <&ipu1>;
> > > > 		connectors = <&hdmi>;
> > > > 	};
> > > 
> > > It is a pity linux-media wasn't CC'ed and apparently V4L developers
> > > didn't notice this and other related patches in a "clean up" series, and
> > > now this patch is already in the mainline. But at least I'd like to ask
> > > whether the bindings, defined in
> > > Documentation/devicetree/bindings/media/video-interfaces.txt and
> > > implemented in drivers/media/v4l2-core/v4l2-of.c have been considered
> > > for this job, and - if so - why have they been found unsuitable?
> > > Wouldn't it have been better to use and - if needed - extend them to
> > > cover any deficiencies? Even though the implementation is currently
> > > located under drivers/media/v4l2-code/ it's pretty generic and should be
> > > easily transferable to a more generic location.
> > 
> > The component helpers have nothing to do with DT apart from solving
> > the problem of how to deal with subsystems which expect a single device,
> > but we have a group of devices and their individual drivers to cope with.
> > Subsystems like DRM and ALSA.
> 
> (and V4L2)
> 
> Point duly taken. First of all I want to mention that your proposal is
> greatly appreciated. This is a problem that crosses subsystem boundaries,
> and should thus be addressed centrally.
> 
> However, we (as in the V4L2 community, and me personally) would have
> appreciated to be CC'ed on the proposal. As you might know we already had a
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c. Whether or not this solution should have been made
> generic instead of coming up with a new separate implementation would of
> course have been debatable, but the most important point would have been to
> make sure that v4l2-async could easily be implemented on top of the common
> component architecture.
> 
> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. If I had replied to this mail thread without sleeping on
> it first I might not have known better and have got half-paranoid,
> wondereding whether there had been a deliberate attempt to fast-track this
> API before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.
> 
> Let's all take this as a positive opportunity to cooperate more closely,
> media devices still need a huge effort to be cleanly supported on modern
> hardware, and we'll need all the development power we can get.
> 
> Accordingly, I would like to comment on the component API, despite the fact
> that it has been merged in mainline already. The first thing that I believe
> is missing is documentation. Do you have any pending patch for that, either
> as kerneldoc or as a text file for Documentation/ ? As I've read the code
> to understand it I might have missed so design goals, so please bear with
> the stupid questions that may follow.
> 
> I'll first provide a brief comparison of the two models to make the rest of
> the comments easier to understand.
> 
> v4l2-async calls the component master object v4l2_async_notifier. The base
> component child object is a v4l2_subdev instance instead of being a plain
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to
> how the component framework stores objects, except that the list head is
> directly embedded inside the v4l2_subdev structure instead of being part of
> a separate structure allocated by the framework.
> 
> The notifier has three callback functions, bound, complete and unbind. The
> bound function is called when one component has been bound to the master.
> Similarly the unbind function is called when one component is about to be
> unbound from the master. The complete function is called when all components
> have been bound, and is thus equivalent to the bind function of the
> component framework.
> 
> Notifiers are registered along with a list of match entries. A match entry
> is roughly equivalent to the compare function passed to
> component_master_add_child, except that it includes built-in support for
> matching on an OF node, dev_name or I2C bus number and child address.
> 
> Whenever a subdev (component child) is registered with
> v4l2_async_register_subdev (equivalent to component_add), the list of
> notifiers (masters) is walked and their match entries are processed. If a
> matching entry is found the subdev is bound to the notifier immediately,
> otherwise it is added to a list of unbound subdevices (component_list).
> Whenever a notifier (component master) is registered with
> v4l2_async_notifier_register (component_master_add) the list of unbound
> subdevs is walked and every match entry of the notifier is tested. If a
> matching entry is found the subdev is bound to the notifier.
> 
> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures.
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in
> driver-specific structures) and the component structure (which would be
> embedded in struct device) ? The latter would be slightly more intrusive
> from a struct device point of view, so I don't have a strong opinion there
> yet, exposing the master structure only might be better.
> 
> - The component framework requires the master to provide an add_components
> operation that will call the component_master_add_child function for every
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added to
> the system. I'm not sure to understand the design decisions behind this,
> but these two levels of indirection appear pretty complex and confusing.
> Wouldn't it be simpler to pass an array of match entries to the master
> registration function instead and remove the add_components operation ? A
> match entry would basically be a structure with a compare function and a
> compare_data pointer.
> 
> We could also extend the match entry with explicit support for OF node and
> I2C bus number + address matching as those are the most common cases, or at
> least provide a couple of standard compare functions for those cases.
> 
> - The component framework doesn't provide partial bind support. Children are
> bound to the master only when all children are available. This makes it
> impossible in practice to implement v4l2-async on top of the component
> framework. What would you think about adding optional partial bind support
> ? The master operations would then have partial bind, complete bind,
> partial unbind and complete unbind functions. Drivers that only need full
> bind support could set the partial bind and unbind functions to NULL.
> 
> > It is completely agnostic to whether you're using platform data, DT or
> > even ACPI - this code could *not* care less.  None of that comes anywhere
> > near what this patch does.  It merely provides a way to collect up
> > individual devices from co-operating drivers, and control their binding
> > such that a subsystem like DRM or ALSA can be presented with a "card"
> > level view of the hardware rather than a multi-device medusa with all
> > the buggy, racy, crap fsckage that people come up to make that kind of
> > thing work.
> > 
> > Now, as for the binding above, first, what does "eg" mean... and
> > secondly, how would a binding which refers to crtcs and connectors
> > have anything to do with ALSA?  Clearly this isn't an example of a
> > binding for an ALSA use, which was talked about in the very first
> > line of the above commit commentry.  So it's quite clear that what is
> > given there is an example of how it /could/ be used.
> > 
> > I suppose I could have instead turned imx-drm into a completely unusable
> > mess by not coming up with some kind of binding, and instead submitted
> > a whole pile of completely untested code.  Alternatively, I could've
> > used the OF binding as you're suggesting, but that would mean radically
> > changing the /existing/ bindings for the IPU as a whole - something
> > which others are better suited at as they have a /much/ better
> > understanding of the complexities of this hardware than I.
> > 
> > So, what I have done is implemented - for a driver in staging which is
> > still subject to ongoing development and non-stable DT bindings -
> > something which allows forward progress with a *minimum* of disruption
> > to the existing DT bindings for everyone, while still allowing forward
> > progress.
> > 
> > Better bindings for imx-drm are currently being worked on.  Philipp
> > Zabel of Pengutronix is currently looking at it, and has posted many
> > RFC patches on this very subject, including moving the V4L2 OF helpers
> > to a more suitable location.  OF people have been involved in that
> > discussion over the preceding weeks, and there's a working implementation
> > of imx-drm using these helpers from v4l2.
> > 
> > I'm finding people who are working in the same area and trying to get
> > everyone talking to each other so that we /do/ end up with a set of
> > bindings for the display stuff which are suitable for everyone.  Tomi
> > from TI has already expressed his input to this ongoing discussion.
> > 
> > You're welcome to get involved in those discussions too.
> > 
> > I hope this makes it clear, and clears up the confusion.
> > 
> > Thanks.

-- 
Regards,

Laurent Pinchart

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-03-19 17:22           ` Laurent Pinchart
  (?)
@ 2014-03-19 17:27             ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-19 17:27 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Guennadi Liakhovetski, David Airlie, Greg Kroah-Hartman,
	Sascha Hauer, Shawn Guo, devel, dri-devel, linux-arm-kernel,
	Linux Media Mailing List, Sylwester Nawrocki, Philipp Zabel

On Wed, Mar 19, 2014 at 06:22:14PM +0100, Laurent Pinchart wrote:
> Hi Russell,
> 
> (CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
> component framework)
> 
> Could you please have a look at the questions below and provide an answer when 
> you'll have time ? I'd like to bridge the gap between the component and the 
> V4L2 asynchronous registration implementations.

I have a reply partly prepared, but I'm snowed under by the L2 cache stuff
at the moment, sorry.

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

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-19 17:27             ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-19 17:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Mar 19, 2014 at 06:22:14PM +0100, Laurent Pinchart wrote:
> Hi Russell,
> 
> (CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
> component framework)
> 
> Could you please have a look at the questions below and provide an answer when 
> you'll have time ? I'd like to bridge the gap between the component and the 
> V4L2 asynchronous registration implementations.

I have a reply partly prepared, but I'm snowed under by the L2 cache stuff
at the moment, sorry.

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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-19 17:27             ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-19 17:27 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: devel, Philipp Zabel, David Airlie, Greg Kroah-Hartman,
	dri-devel, Sascha Hauer, Sylwester Nawrocki, Shawn Guo,
	Guennadi Liakhovetski, linux-arm-kernel,
	Linux Media Mailing List

On Wed, Mar 19, 2014 at 06:22:14PM +0100, Laurent Pinchart wrote:
> Hi Russell,
> 
> (CC'ing Philipp Zabel who might be able to provide feedback as a user of the 
> component framework)
> 
> Could you please have a look at the questions below and provide an answer when 
> you'll have time ? I'd like to bridge the gap between the component and the 
> V4L2 asynchronous registration implementations.

I have a reply partly prepared, but I'm snowed under by the L2 cache stuff
at the moment, sorry.

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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
  2014-03-06 23:24         ` Laurent Pinchart
  (?)
@ 2014-03-21 12:34           ` Russell King - ARM Linux
  -1 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-21 12:34 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Guennadi Liakhovetski, David Airlie, Greg Kroah-Hartman,
	Sascha Hauer, Shawn Guo, devel, dri-devel, linux-arm-kernel,
	Linux Media Mailing List, Sylwester Nawrocki

On Fri, Mar 07, 2014 at 12:24:33AM +0100, Laurent Pinchart wrote:
> However, we (as in the V4L2 community, and me personally) would have 
> appreciated to be CC'ed on the proposal. As you might know we already had a 
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c.

There's a lot of people who would have liked to be on the Cc, but there's
two problems: 1. the Cc list would be too big for mailing lists to accept
the message, and 2. finding everyone who should be on the Cc list is quite
an impossible task.

> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. 

Yes, I am aware of CDF.  However, the annoying thing is that it's another
case of the bigger picture not being looked at - which is that we don't
need yet another subsystem specific solution to a problem which is not
subsystem specific.

The fact of the matter is that /anyone/ has the opportunity to come up
with a generic solution to this problem, and no one did... instead,
more solutions were generated - the proof is "we solved this in CDF
with a CDF specific solution". :p

> If I had replied to this mail thread without sleeping on it first I
> might not have known better and have got half-paranoid, wondereding
> whether there had been a deliberate attempt to fast-track this API
> before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.

What would have happened is that CDF would have been raised, and there
would be a big long discussion with no real resolution.  The problem
would not have been solved (even partially).  We'd be sitting here right
now still without any kind of solution that anyone can use.

Instead, what we have right now is the opportunity for people to start
making use of this and solving the real problems they have with driver
initialisation.

For example, the IPU on iMX locks up after a number of mode changes, and
it's useful to be able to unload the driver, poke about in the hardware,
and reload it.  Without this problem fixed, that's impossible without
rebooting the kernel, because removing the driver oopses the kernel due
to the broken work-arounds that it has to do - and it has to do those
because this problem has not been solved, despite it being known about
for /years/.

> Accordingly, I would like to comment on the component API, despite the fact 
> that it has been merged in mainline already. The first thing that I believe is 
> missing is documentation. Do you have any pending patch for that, either as 
> kerneldoc or as a text file for Documentation/ ? As I've read the code to 
> understand it I might have missed so design goals, so please bear with the 
> stupid questions that may follow.

There's lots of things in the kernel which you just have to read the code
for - and this is one of them at the moment. :)  (Another is PM domains...)

What I know is that this will not satisfy all your requirements - I don't
want it to initially satisfy everyone's requirements, because that's just
far too big a job, but it satisfies the common problem that most people
are suffering from and have already implemented many badly written driver
specific solutions.

In other words - this is designed to _improve_ the current situation where
we have lots of buggy implementions trying to work around this problem,
factor that code out, and fix up those problems.

Briefly, the idea is:

- there is a master device - lots of these subsystems doing this already
  have that, whether that be ALSA or DRM based stuff.
- then there are the individual component devices and their drivers.

Subsystems like ALSA and DRM are not component based subsystems.  These
subsystems have two states - either they're initialised and the entire
"card system" is known about, or they're not initialised.  There is no
possibility of a piecemeal approach, where they partially come up and
additional stuff gets added later.  With DRM, that's especially true
because of how the userspace API works - to change that probably means
changing stuff all the way through things like the X server and its
xrandr application interface.  This is probably the reason why David said
at KS that DRM isn't going to do the hotplugging of components.

The master device has a privileged position - it gets to make the decision
about which component devices are relevant to it, and when the "card system"
is fully known.  As far as DT goes, we've had a long discussion about this
approach in the past, and we've accepted this approach - we have the
"sound" node which doesn't actually refer to any hardware block, it's a
node which describes how the hardware blocks are connected together, which
gets translated into a platform device.

When a master device gets added, it gets added to the list of master
devices, and then it's asked whether all the components that it needs
are present.  Since we don't want to fixate on any one particular
method to make that decision, it calls back via a method to the master
driver for that.  The master then determines which components should
be present, and asks the component helpers to check whether they are.
The master does this in the order which the components are to be later
bound (there's subsystems which have requirements on the ordering of
individual components appearing - for example, with DRM the CRTCs
need to be available before the encoders so that you know the CRTC
indexes to bind the encoders to.)

Each component that is found is added to a master-specific list, making
it unavailable to other masters (any particular component can't be owned
by two masters.)

If a component isn't found, then this process is unwound, and we wait for
more components to show up.

When a component is added, it is added to a list of all components.  All
unbound masters are polled to see whether they require this component in
the same way as above.

When a master indicates that it is complete, the master is bound, which
kicks off what would be the standard driver probe on non-componentised
systems.  Since we now know that we have all the components associated
with this master, this is now safe to do, and the master driver gets to
decide at what point during subsystem initialisation the components
should be bound.  This will normally be when the DRM device private
structures or ALSA card has been allocated, and are available for the
components to bind themselves to.

Should any component or master return a deferred probe, that error code
(or in fact any error code) is propagated all the way back through the
chain, unwinding the effects as we go - including devres allocated
resources.  Eventually, we hit the caller to component_add() or
component_master_add(), which would be a driver probe function, and this
propagates it back to the driver model.

So, the last driver (master or component) gets to eat any errors from
the bring up - that's reasonable, because we can't return an error from
an already completed probe function.  The side effect of this is very
important though - it gets us deferred probing.

That failed driver probe with -EPROBE_DEFER will be retried later,
hopefully when the resources that any one of those components needed is
now available.

Now, that's only half the story - the other half is far more important,
because it's the one which gives the most problems with the current
driver specific implementations, and is the one which leads to kernel
oopses.  That is, what happens when a bound component or master goes
away.

Remember that ALSA and DRM can't cope with that - the only way they can
cope is by having the entire "card system" removed.  It's an all or
nothing case.  With DRM, you wouldn't be able to remove a CRTC for
example, because that would break the CRTC numbering that userspace
sees via the kernel API, and also the CRTC numbering which xrandr Xorg
applications see.

So, when any component/master of a subsystem is removed, the whole setup
is unbound: this starts with the master being unbound, and the master
controls the point at which the components are unbound.  Again, normal
devres actions happen so drivers see proper devres behaviour.

> v4l2-async calls the component master object v4l2_async_notifier. The base 
> component child object is a v4l2_subdev instance instead of being a plain 
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
> the component framework stores objects, except that the list head is directly 
> embedded inside the v4l2_subdev structure instead of being part of a separate 
> structure allocated by the framework.

Right - I didn't want to modify existing structures like struct device,
because they're already bloated enough. Given that this currently affects
a small number of devices, it is unfair to impose this overhead on all
device structures in the kernel.

> The notifier has three callback functions, bound, complete and unbind. The 
> bound function is called when one component has been bound to the master. 
> Similarly the unbind function is called when one component is about to be 
> unbound from the master. The complete function is called when all components 
> have been bound, and is thus equivalent to the bind function of the component 
> framework.

So, what happens after all components have been bound (and the complete
callback has been called), and then one component is removed from the
system?  From your description, it sounds like nothing apart from the
"unbind" callback for that component.

Moreover, what happens if that component is then added back later?
Do you get another "bind" followed by "complete"?

How would a subsystem like, DRM or ALSA, be able to fit into this model
when these subsystems can't tolerate any component going away or being
introduced after the initial bring-up?

> Notifiers are registered along with a list of match entries. A match
> entry is roughly equivalent to the compare function passed to 
> component_master_add_child, except that it includes built-in support for 
> matching on an OF node, dev_name or I2C bus number and child address.

This is something we could add to the component model.  However, one of
the target design goals is that the core should be free of the matching
method, so that we don't end up with something that is specific only to
existing ARM systems.

However, one of the issues here is how to pass this information in - it
can't be a static array (see below.)

> Whenever a subdev (component child) is registered with 
> v4l2_async_register_subdev (equivalent to component_add), the list of 
> notifiers (masters) is walked and their match entries are processed. If a 
> matching entry is found the subdev is bound to the notifier immediately, 
> otherwise it is added to a list of unbound subdevices (component_list). 
> Whenever a notifier (component master) is registered with 
> v4l2_async_notifier_register (component_master_add) the list of unbound 
> subdevs is walked and every match entry of the notifier is tested. If a 
> matching entry is found the subdev is bound to the notifier.

The more interesting question is what happens when a component is removed.
This is what kills a lot of bad implementations of this right now.  It's
basically impossible to remove any component without oopsing the kernel.

> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures. 
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in driver-specific 
> structures) and the component structure (which would be embedded in struct 
> device) ?

This doesn't work everywhere.  Take ALSA as an example.  There is struct
snd_card.  This is created by snd_card_create() and allocates your driver
private data structure for you in addition to the snd_card.

When you want to tear down the snd_card, this includes freeing all memory
associated with it, including the driver private data structure.  If a
component helper data structure were to be embedded in the driver private
data structure, it would also be freed - while still being registered
into component stuff.

Conversely, if you created the snd_card outside of the component stuff,
then you have no real way to remove the components when they go away.

Of course, the driver could allocate its own struct just for this, but
then where does it store a pointer to that?  In the driver data?  What
if the subsystem (and some do) insist on putting their own data in the
struct device driver data pointer?

DRM used to do exactly that (it's changed very recently to allow drivers
to do their own thing wrt driver_data - but this wasn't the case when the
component stuff was written, which was shortly after kernel summit.)

So, that's why I made the decision to have it as a separate structure.
Using the solution you're suggesting would result in unnecessary
restrictions on how drivers and subsystems should behave.

I don't think any of us want to go through changing the way lots of
subsystems and possibly hundreds of drivers work in this regard.  Hence,
while it may not appear the simplest solution, in the bigger picture,
it's better not to impose any kind of avoidable requirements on drivers.

> - The component framework requires the master to provide an add_components 
> operation that will call the component_master_add_child function for every 
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added
> to the system. I'm not sure to understand the design decisions behind
> this, but these two levels of indirection appear pretty complex and
> confusing. Wouldn't it be simpler to pass an array of match entries to
> the master registration function instead and remove the add_components
> operation ? A match entry would basically be a structure with a compare
> function and a compare_data pointer.

We could supply an array of match function, match data, but the issue
here is that the match data generally isn't constant - the driver would
have to allocate an array of {function, data} and register that array
into the component helper.  Not much problem with that, except it
results in more complexity.

> We could also extend the match entry with explicit support for OF node
> and I2C bus number + address matching as those are the most common cases,
> or at least provide a couple of standard compare functions for those cases.

This I don't like, because it's making assumptions about the struct
device, encoding subsystem and firmware specific knowledge.  It's
fine to do that as a match helper, but not as something core.

> - The component framework doesn't provide partial bind support. Children
> are bound to the master only when all children are available. This makes
> it impossible in practice to implement v4l2-async on top of the component 
> framework. What would you think about adding optional partial bind support ? 

As you can see from the above explanation, this is intentional in this
iteration, as this is the common requirement for these subsystems that
it's trying to solve the problem for.

That's not to say that it can't be done - at the moment I have some
concerns from the point of view of these other subsystems which don't
support partial bind, and ensuring that partial bind doesn't get
mis-used there.

In any case, there is scope for the way the master discovers its
components to be changed, and I feel that would be a pre-requisit to
partial bind support.

Philipp's work on imx-drm for example, has ended up allocating an
ordered list of devices, though there's patches around to remove that
again.  That was necessary due to a work-around for the brokenness in
existing imx-drm for the CRTC nodes (which prevents a successful match
against a previously found component) which will now be removed.

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

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

* [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-21 12:34           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-21 12:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Mar 07, 2014 at 12:24:33AM +0100, Laurent Pinchart wrote:
> However, we (as in the V4L2 community, and me personally) would have 
> appreciated to be CC'ed on the proposal. As you might know we already had a 
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c.

There's a lot of people who would have liked to be on the Cc, but there's
two problems: 1. the Cc list would be too big for mailing lists to accept
the message, and 2. finding everyone who should be on the Cc list is quite
an impossible task.

> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. 

Yes, I am aware of CDF.  However, the annoying thing is that it's another
case of the bigger picture not being looked at - which is that we don't
need yet another subsystem specific solution to a problem which is not
subsystem specific.

The fact of the matter is that /anyone/ has the opportunity to come up
with a generic solution to this problem, and no one did... instead,
more solutions were generated - the proof is "we solved this in CDF
with a CDF specific solution". :p

> If I had replied to this mail thread without sleeping on it first I
> might not have known better and have got half-paranoid, wondereding
> whether there had been a deliberate attempt to fast-track this API
> before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.

What would have happened is that CDF would have been raised, and there
would be a big long discussion with no real resolution.  The problem
would not have been solved (even partially).  We'd be sitting here right
now still without any kind of solution that anyone can use.

Instead, what we have right now is the opportunity for people to start
making use of this and solving the real problems they have with driver
initialisation.

For example, the IPU on iMX locks up after a number of mode changes, and
it's useful to be able to unload the driver, poke about in the hardware,
and reload it.  Without this problem fixed, that's impossible without
rebooting the kernel, because removing the driver oopses the kernel due
to the broken work-arounds that it has to do - and it has to do those
because this problem has not been solved, despite it being known about
for /years/.

> Accordingly, I would like to comment on the component API, despite the fact 
> that it has been merged in mainline already. The first thing that I believe is 
> missing is documentation. Do you have any pending patch for that, either as 
> kerneldoc or as a text file for Documentation/ ? As I've read the code to 
> understand it I might have missed so design goals, so please bear with the 
> stupid questions that may follow.

There's lots of things in the kernel which you just have to read the code
for - and this is one of them at the moment. :)  (Another is PM domains...)

What I know is that this will not satisfy all your requirements - I don't
want it to initially satisfy everyone's requirements, because that's just
far too big a job, but it satisfies the common problem that most people
are suffering from and have already implemented many badly written driver
specific solutions.

In other words - this is designed to _improve_ the current situation where
we have lots of buggy implementions trying to work around this problem,
factor that code out, and fix up those problems.

Briefly, the idea is:

- there is a master device - lots of these subsystems doing this already
  have that, whether that be ALSA or DRM based stuff.
- then there are the individual component devices and their drivers.

Subsystems like ALSA and DRM are not component based subsystems.  These
subsystems have two states - either they're initialised and the entire
"card system" is known about, or they're not initialised.  There is no
possibility of a piecemeal approach, where they partially come up and
additional stuff gets added later.  With DRM, that's especially true
because of how the userspace API works - to change that probably means
changing stuff all the way through things like the X server and its
xrandr application interface.  This is probably the reason why David said
at KS that DRM isn't going to do the hotplugging of components.

The master device has a privileged position - it gets to make the decision
about which component devices are relevant to it, and when the "card system"
is fully known.  As far as DT goes, we've had a long discussion about this
approach in the past, and we've accepted this approach - we have the
"sound" node which doesn't actually refer to any hardware block, it's a
node which describes how the hardware blocks are connected together, which
gets translated into a platform device.

When a master device gets added, it gets added to the list of master
devices, and then it's asked whether all the components that it needs
are present.  Since we don't want to fixate on any one particular
method to make that decision, it calls back via a method to the master
driver for that.  The master then determines which components should
be present, and asks the component helpers to check whether they are.
The master does this in the order which the components are to be later
bound (there's subsystems which have requirements on the ordering of
individual components appearing - for example, with DRM the CRTCs
need to be available before the encoders so that you know the CRTC
indexes to bind the encoders to.)

Each component that is found is added to a master-specific list, making
it unavailable to other masters (any particular component can't be owned
by two masters.)

If a component isn't found, then this process is unwound, and we wait for
more components to show up.

When a component is added, it is added to a list of all components.  All
unbound masters are polled to see whether they require this component in
the same way as above.

When a master indicates that it is complete, the master is bound, which
kicks off what would be the standard driver probe on non-componentised
systems.  Since we now know that we have all the components associated
with this master, this is now safe to do, and the master driver gets to
decide at what point during subsystem initialisation the components
should be bound.  This will normally be when the DRM device private
structures or ALSA card has been allocated, and are available for the
components to bind themselves to.

Should any component or master return a deferred probe, that error code
(or in fact any error code) is propagated all the way back through the
chain, unwinding the effects as we go - including devres allocated
resources.  Eventually, we hit the caller to component_add() or
component_master_add(), which would be a driver probe function, and this
propagates it back to the driver model.

So, the last driver (master or component) gets to eat any errors from
the bring up - that's reasonable, because we can't return an error from
an already completed probe function.  The side effect of this is very
important though - it gets us deferred probing.

That failed driver probe with -EPROBE_DEFER will be retried later,
hopefully when the resources that any one of those components needed is
now available.

Now, that's only half the story - the other half is far more important,
because it's the one which gives the most problems with the current
driver specific implementations, and is the one which leads to kernel
oopses.  That is, what happens when a bound component or master goes
away.

Remember that ALSA and DRM can't cope with that - the only way they can
cope is by having the entire "card system" removed.  It's an all or
nothing case.  With DRM, you wouldn't be able to remove a CRTC for
example, because that would break the CRTC numbering that userspace
sees via the kernel API, and also the CRTC numbering which xrandr Xorg
applications see.

So, when any component/master of a subsystem is removed, the whole setup
is unbound: this starts with the master being unbound, and the master
controls the point at which the components are unbound.  Again, normal
devres actions happen so drivers see proper devres behaviour.

> v4l2-async calls the component master object v4l2_async_notifier. The base 
> component child object is a v4l2_subdev instance instead of being a plain 
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
> the component framework stores objects, except that the list head is directly 
> embedded inside the v4l2_subdev structure instead of being part of a separate 
> structure allocated by the framework.

Right - I didn't want to modify existing structures like struct device,
because they're already bloated enough. Given that this currently affects
a small number of devices, it is unfair to impose this overhead on all
device structures in the kernel.

> The notifier has three callback functions, bound, complete and unbind. The 
> bound function is called when one component has been bound to the master. 
> Similarly the unbind function is called when one component is about to be 
> unbound from the master. The complete function is called when all components 
> have been bound, and is thus equivalent to the bind function of the component 
> framework.

So, what happens after all components have been bound (and the complete
callback has been called), and then one component is removed from the
system?  From your description, it sounds like nothing apart from the
"unbind" callback for that component.

Moreover, what happens if that component is then added back later?
Do you get another "bind" followed by "complete"?

How would a subsystem like, DRM or ALSA, be able to fit into this model
when these subsystems can't tolerate any component going away or being
introduced after the initial bring-up?

> Notifiers are registered along with a list of match entries. A match
> entry is roughly equivalent to the compare function passed to 
> component_master_add_child, except that it includes built-in support for 
> matching on an OF node, dev_name or I2C bus number and child address.

This is something we could add to the component model.  However, one of
the target design goals is that the core should be free of the matching
method, so that we don't end up with something that is specific only to
existing ARM systems.

However, one of the issues here is how to pass this information in - it
can't be a static array (see below.)

> Whenever a subdev (component child) is registered with 
> v4l2_async_register_subdev (equivalent to component_add), the list of 
> notifiers (masters) is walked and their match entries are processed. If a 
> matching entry is found the subdev is bound to the notifier immediately, 
> otherwise it is added to a list of unbound subdevices (component_list). 
> Whenever a notifier (component master) is registered with 
> v4l2_async_notifier_register (component_master_add) the list of unbound 
> subdevs is walked and every match entry of the notifier is tested. If a 
> matching entry is found the subdev is bound to the notifier.

The more interesting question is what happens when a component is removed.
This is what kills a lot of bad implementations of this right now.  It's
basically impossible to remove any component without oopsing the kernel.

> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures. 
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in driver-specific 
> structures) and the component structure (which would be embedded in struct 
> device) ?

This doesn't work everywhere.  Take ALSA as an example.  There is struct
snd_card.  This is created by snd_card_create() and allocates your driver
private data structure for you in addition to the snd_card.

When you want to tear down the snd_card, this includes freeing all memory
associated with it, including the driver private data structure.  If a
component helper data structure were to be embedded in the driver private
data structure, it would also be freed - while still being registered
into component stuff.

Conversely, if you created the snd_card outside of the component stuff,
then you have no real way to remove the components when they go away.

Of course, the driver could allocate its own struct just for this, but
then where does it store a pointer to that?  In the driver data?  What
if the subsystem (and some do) insist on putting their own data in the
struct device driver data pointer?

DRM used to do exactly that (it's changed very recently to allow drivers
to do their own thing wrt driver_data - but this wasn't the case when the
component stuff was written, which was shortly after kernel summit.)

So, that's why I made the decision to have it as a separate structure.
Using the solution you're suggesting would result in unnecessary
restrictions on how drivers and subsystems should behave.

I don't think any of us want to go through changing the way lots of
subsystems and possibly hundreds of drivers work in this regard.  Hence,
while it may not appear the simplest solution, in the bigger picture,
it's better not to impose any kind of avoidable requirements on drivers.

> - The component framework requires the master to provide an add_components 
> operation that will call the component_master_add_child function for every 
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added
> to the system. I'm not sure to understand the design decisions behind
> this, but these two levels of indirection appear pretty complex and
> confusing. Wouldn't it be simpler to pass an array of match entries to
> the master registration function instead and remove the add_components
> operation ? A match entry would basically be a structure with a compare
> function and a compare_data pointer.

We could supply an array of match function, match data, but the issue
here is that the match data generally isn't constant - the driver would
have to allocate an array of {function, data} and register that array
into the component helper.  Not much problem with that, except it
results in more complexity.

> We could also extend the match entry with explicit support for OF node
> and I2C bus number + address matching as those are the most common cases,
> or at least provide a couple of standard compare functions for those cases.

This I don't like, because it's making assumptions about the struct
device, encoding subsystem and firmware specific knowledge.  It's
fine to do that as a match helper, but not as something core.

> - The component framework doesn't provide partial bind support. Children
> are bound to the master only when all children are available. This makes
> it impossible in practice to implement v4l2-async on top of the component 
> framework. What would you think about adding optional partial bind support ? 

As you can see from the above explanation, this is intentional in this
iteration, as this is the common requirement for these subsystems that
it's trying to solve the problem for.

That's not to say that it can't be done - at the moment I have some
concerns from the point of view of these other subsystems which don't
support partial bind, and ensuring that partial bind doesn't get
mis-used there.

In any case, there is scope for the way the master discovers its
components to be changed, and I feel that would be a pre-requisit to
partial bind support.

Philipp's work on imx-drm for example, has ended up allocating an
ordered list of devices, though there's patches around to remove that
again.  That was necessary due to a work-around for the brokenness in
existing imx-drm for the CRTC nodes (which prevents a successful match
against a previously found component) which will now be removed.

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

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

* Re: [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems
@ 2014-03-21 12:34           ` Russell King - ARM Linux
  0 siblings, 0 replies; 219+ messages in thread
From: Russell King - ARM Linux @ 2014-03-21 12:34 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: devel, Greg Kroah-Hartman, dri-devel, Sascha Hauer,
	Sylwester Nawrocki, Guennadi Liakhovetski, linux-arm-kernel,
	Linux Media Mailing List

On Fri, Mar 07, 2014 at 12:24:33AM +0100, Laurent Pinchart wrote:
> However, we (as in the V4L2 community, and me personally) would have 
> appreciated to be CC'ed on the proposal. As you might know we already had a 
> solution for this problem, albeit V4L2-specific, in drivers/media/v4l2-
> core/v4l2-async.c.

There's a lot of people who would have liked to be on the Cc, but there's
two problems: 1. the Cc list would be too big for mailing lists to accept
the message, and 2. finding everyone who should be on the Cc list is quite
an impossible task.

> The topic is particularly hot given that a similar solution was also
> proposed as part of the now defunct (or at least hibernating) common
> display framework. 

Yes, I am aware of CDF.  However, the annoying thing is that it's another
case of the bigger picture not being looked at - which is that we don't
need yet another subsystem specific solution to a problem which is not
subsystem specific.

The fact of the matter is that /anyone/ has the opportunity to come up
with a generic solution to this problem, and no one did... instead,
more solutions were generated - the proof is "we solved this in CDF
with a CDF specific solution". :p

> If I had replied to this mail thread without sleeping on it first I
> might not have known better and have got half-paranoid, wondereding
> whether there had been a deliberate attempt to fast-track this API
> before the V4L2 developers noticed. To be perfectly clear, there is
> *NO* implicit or explicit such accusation here, as I know better.

What would have happened is that CDF would have been raised, and there
would be a big long discussion with no real resolution.  The problem
would not have been solved (even partially).  We'd be sitting here right
now still without any kind of solution that anyone can use.

Instead, what we have right now is the opportunity for people to start
making use of this and solving the real problems they have with driver
initialisation.

For example, the IPU on iMX locks up after a number of mode changes, and
it's useful to be able to unload the driver, poke about in the hardware,
and reload it.  Without this problem fixed, that's impossible without
rebooting the kernel, because removing the driver oopses the kernel due
to the broken work-arounds that it has to do - and it has to do those
because this problem has not been solved, despite it being known about
for /years/.

> Accordingly, I would like to comment on the component API, despite the fact 
> that it has been merged in mainline already. The first thing that I believe is 
> missing is documentation. Do you have any pending patch for that, either as 
> kerneldoc or as a text file for Documentation/ ? As I've read the code to 
> understand it I might have missed so design goals, so please bear with the 
> stupid questions that may follow.

There's lots of things in the kernel which you just have to read the code
for - and this is one of them at the moment. :)  (Another is PM domains...)

What I know is that this will not satisfy all your requirements - I don't
want it to initially satisfy everyone's requirements, because that's just
far too big a job, but it satisfies the common problem that most people
are suffering from and have already implemented many badly written driver
specific solutions.

In other words - this is designed to _improve_ the current situation where
we have lots of buggy implementions trying to work around this problem,
factor that code out, and fix up those problems.

Briefly, the idea is:

- there is a master device - lots of these subsystems doing this already
  have that, whether that be ALSA or DRM based stuff.
- then there are the individual component devices and their drivers.

Subsystems like ALSA and DRM are not component based subsystems.  These
subsystems have two states - either they're initialised and the entire
"card system" is known about, or they're not initialised.  There is no
possibility of a piecemeal approach, where they partially come up and
additional stuff gets added later.  With DRM, that's especially true
because of how the userspace API works - to change that probably means
changing stuff all the way through things like the X server and its
xrandr application interface.  This is probably the reason why David said
at KS that DRM isn't going to do the hotplugging of components.

The master device has a privileged position - it gets to make the decision
about which component devices are relevant to it, and when the "card system"
is fully known.  As far as DT goes, we've had a long discussion about this
approach in the past, and we've accepted this approach - we have the
"sound" node which doesn't actually refer to any hardware block, it's a
node which describes how the hardware blocks are connected together, which
gets translated into a platform device.

When a master device gets added, it gets added to the list of master
devices, and then it's asked whether all the components that it needs
are present.  Since we don't want to fixate on any one particular
method to make that decision, it calls back via a method to the master
driver for that.  The master then determines which components should
be present, and asks the component helpers to check whether they are.
The master does this in the order which the components are to be later
bound (there's subsystems which have requirements on the ordering of
individual components appearing - for example, with DRM the CRTCs
need to be available before the encoders so that you know the CRTC
indexes to bind the encoders to.)

Each component that is found is added to a master-specific list, making
it unavailable to other masters (any particular component can't be owned
by two masters.)

If a component isn't found, then this process is unwound, and we wait for
more components to show up.

When a component is added, it is added to a list of all components.  All
unbound masters are polled to see whether they require this component in
the same way as above.

When a master indicates that it is complete, the master is bound, which
kicks off what would be the standard driver probe on non-componentised
systems.  Since we now know that we have all the components associated
with this master, this is now safe to do, and the master driver gets to
decide at what point during subsystem initialisation the components
should be bound.  This will normally be when the DRM device private
structures or ALSA card has been allocated, and are available for the
components to bind themselves to.

Should any component or master return a deferred probe, that error code
(or in fact any error code) is propagated all the way back through the
chain, unwinding the effects as we go - including devres allocated
resources.  Eventually, we hit the caller to component_add() or
component_master_add(), which would be a driver probe function, and this
propagates it back to the driver model.

So, the last driver (master or component) gets to eat any errors from
the bring up - that's reasonable, because we can't return an error from
an already completed probe function.  The side effect of this is very
important though - it gets us deferred probing.

That failed driver probe with -EPROBE_DEFER will be retried later,
hopefully when the resources that any one of those components needed is
now available.

Now, that's only half the story - the other half is far more important,
because it's the one which gives the most problems with the current
driver specific implementations, and is the one which leads to kernel
oopses.  That is, what happens when a bound component or master goes
away.

Remember that ALSA and DRM can't cope with that - the only way they can
cope is by having the entire "card system" removed.  It's an all or
nothing case.  With DRM, you wouldn't be able to remove a CRTC for
example, because that would break the CRTC numbering that userspace
sees via the kernel API, and also the CRTC numbering which xrandr Xorg
applications see.

So, when any component/master of a subsystem is removed, the whole setup
is unbound: this starts with the master being unbound, and the master
controls the point at which the components are unbound.  Again, normal
devres actions happen so drivers see proper devres behaviour.

> v4l2-async calls the component master object v4l2_async_notifier. The base 
> component child object is a v4l2_subdev instance instead of being a plain 
> device. v4l2_subdev instances are stored in v4l2-async lists similarly to how 
> the component framework stores objects, except that the list head is directly 
> embedded inside the v4l2_subdev structure instead of being part of a separate 
> structure allocated by the framework.

Right - I didn't want to modify existing structures like struct device,
because they're already bloated enough. Given that this currently affects
a small number of devices, it is unfair to impose this overhead on all
device structures in the kernel.

> The notifier has three callback functions, bound, complete and unbind. The 
> bound function is called when one component has been bound to the master. 
> Similarly the unbind function is called when one component is about to be 
> unbound from the master. The complete function is called when all components 
> have been bound, and is thus equivalent to the bind function of the component 
> framework.

So, what happens after all components have been bound (and the complete
callback has been called), and then one component is removed from the
system?  From your description, it sounds like nothing apart from the
"unbind" callback for that component.

Moreover, what happens if that component is then added back later?
Do you get another "bind" followed by "complete"?

How would a subsystem like, DRM or ALSA, be able to fit into this model
when these subsystems can't tolerate any component going away or being
introduced after the initial bring-up?

> Notifiers are registered along with a list of match entries. A match
> entry is roughly equivalent to the compare function passed to 
> component_master_add_child, except that it includes built-in support for 
> matching on an OF node, dev_name or I2C bus number and child address.

This is something we could add to the component model.  However, one of
the target design goals is that the core should be free of the matching
method, so that we don't end up with something that is specific only to
existing ARM systems.

However, one of the issues here is how to pass this information in - it
can't be a static array (see below.)

> Whenever a subdev (component child) is registered with 
> v4l2_async_register_subdev (equivalent to component_add), the list of 
> notifiers (masters) is walked and their match entries are processed. If a 
> matching entry is found the subdev is bound to the notifier immediately, 
> otherwise it is added to a list of unbound subdevices (component_list). 
> Whenever a notifier (component master) is registered with 
> v4l2_async_notifier_register (component_master_add) the list of unbound 
> subdevs is walked and every match entry of the notifier is tested. If a 
> matching entry is found the subdev is bound to the notifier.

The more interesting question is what happens when a component is removed.
This is what kills a lot of bad implementations of this right now.  It's
basically impossible to remove any component without oopsing the kernel.

> I've seen a couple of core differences in concept between your component
> model and the v4l2-async model:
> 
> - The component framework uses private master and component structures. 
> Wouldn't it simplify the code from a memory management point of view to
> expose the master structure (which would then be embedded in driver-specific 
> structures) and the component structure (which would be embedded in struct 
> device) ?

This doesn't work everywhere.  Take ALSA as an example.  There is struct
snd_card.  This is created by snd_card_create() and allocates your driver
private data structure for you in addition to the snd_card.

When you want to tear down the snd_card, this includes freeing all memory
associated with it, including the driver private data structure.  If a
component helper data structure were to be embedded in the driver private
data structure, it would also be freed - while still being registered
into component stuff.

Conversely, if you created the snd_card outside of the component stuff,
then you have no real way to remove the components when they go away.

Of course, the driver could allocate its own struct just for this, but
then where does it store a pointer to that?  In the driver data?  What
if the subsystem (and some do) insist on putting their own data in the
struct device driver data pointer?

DRM used to do exactly that (it's changed very recently to allow drivers
to do their own thing wrt driver_data - but this wasn't the case when the
component stuff was written, which was shortly after kernel summit.)

So, that's why I made the decision to have it as a separate structure.
Using the solution you're suggesting would result in unnecessary
restrictions on how drivers and subsystems should behave.

I don't think any of us want to go through changing the way lots of
subsystems and possibly hundreds of drivers work in this regard.  Hence,
while it may not appear the simplest solution, in the bigger picture,
it's better not to impose any kind of avoidable requirements on drivers.

> - The component framework requires the master to provide an add_components 
> operation that will call the component_master_add_child function for every 
> component it needs, with a compare function. The add child function is
> called when the master is registered, and then for every component added
> to the system. I'm not sure to understand the design decisions behind
> this, but these two levels of indirection appear pretty complex and
> confusing. Wouldn't it be simpler to pass an array of match entries to
> the master registration function instead and remove the add_components
> operation ? A match entry would basically be a structure with a compare
> function and a compare_data pointer.

We could supply an array of match function, match data, but the issue
here is that the match data generally isn't constant - the driver would
have to allocate an array of {function, data} and register that array
into the component helper.  Not much problem with that, except it
results in more complexity.

> We could also extend the match entry with explicit support for OF node
> and I2C bus number + address matching as those are the most common cases,
> or at least provide a couple of standard compare functions for those cases.

This I don't like, because it's making assumptions about the struct
device, encoding subsystem and firmware specific knowledge.  It's
fine to do that as a match helper, but not as something core.

> - The component framework doesn't provide partial bind support. Children
> are bound to the master only when all children are available. This makes
> it impossible in practice to implement v4l2-async on top of the component 
> framework. What would you think about adding optional partial bind support ? 

As you can see from the above explanation, this is intentional in this
iteration, as this is the common requirement for these subsystems that
it's trying to solve the problem for.

That's not to say that it can't be done - at the moment I have some
concerns from the point of view of these other subsystems which don't
support partial bind, and ensuring that partial bind doesn't get
mis-used there.

In any case, there is scope for the way the master discovers its
components to be changed, and I feel that would be a pre-requisit to
partial bind support.

Philipp's work on imx-drm for example, has ended up allocating an
ordered list of devices, though there's patches around to remove that
again.  That was necessary due to a work-around for the brokenness in
existing imx-drm for the CRTC nodes (which prevents a successful match
against a previously found component) which will now be removed.

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

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

end of thread, other threads:[~2014-03-21 12:35 UTC | newest]

Thread overview: 219+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-01-02 21:25 [PATCH RFC 00/46] Preview of imx-drm cleanup series Russell King - ARM Linux
2014-01-02 21:25 ` Russell King - ARM Linux
2014-01-02 21:25 ` [PATCH RFC 01/46] imx-drm: imx-drm-core: use the crtc drm device for vblank Russell King
2014-01-02 21:25   ` Russell King
2014-01-02 21:25 ` [PATCH RFC 02/46] imx-drm: imx-drm-core: avoid going the long route round for drm_device Russell King
2014-01-02 21:25   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 03/46] imx-drm: imx-drm-core: merge imx_drm_crtc_register() into imx_drm_add_crtc() Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 04/46] imx-drm: ipu-v3: more inteligent DI clock selection Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 05/46] imx-drm: ipu-v3: don't use clk_round_rate() before clk_set_rate() Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 06/46] imx-drm: ipu-v3: more clocking fixes Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 07/46] imx-drm: Add mx6 hdmi transmitter support Russell King
2014-01-02 21:34   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 08/46] imx-drm: add imx6 DT configuration for HDMI Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 09/46] imx-drm: update and fix imx6 DT descriptions for v3 HDMI driver Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 10/46] imx-drm: imx-hdmi: fix PLL lock wait Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 11/46] imx-drm: imx-hdmi: fix pixel clock Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 12/46] imx-drm: imx-hdmi: fix wrong comment Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 13/46] imx-drm: imx-hdmi: get rid of pointless fb_reg Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:26 ` [PATCH RFC 14/46] imx-drm: imx-hdmi: get rid of clk manipulations in imx_hdmi_fb_registered() Russell King
2014-01-02 21:26   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 15/46] imx-drm: imx-hdmi: minor cleanups Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 16/46] imx-drm: imx-hdmi: convert HDMI clock settings to tabular form Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 17/46] imx-drm: imx-hdmi: clean up setting CSC registers Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 18/46] imx-drm: imx-hdmi: provide register modification function Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 19/46] imx-drm: imx-hdmi: clean up setting of vp_conf Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 20/46] imx-drm: imx-hdmi: fix CTS/N setup at init time Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 21/46] drm: provide a helper for the encoder possible_crtcs mask Russell King
2014-01-02 21:27   ` Russell King
2014-01-03 16:05   ` David Herrmann
2014-01-03 16:05     ` David Herrmann
2014-01-03 16:13     ` Russell King - ARM Linux
2014-01-03 16:13       ` Russell King - ARM Linux
2014-01-03 16:26       ` David Herrmann
2014-01-03 16:26         ` David Herrmann
2014-01-03 16:29         ` Russell King - ARM Linux
2014-01-03 16:29           ` Russell King - ARM Linux
2014-01-02 21:27 ` [PATCH RFC 22/46] imx-drm: imx-drm-core: sanitise imx_drm_encoder_get_mux_id() Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 23/46] imx-drm: imx-drm-core: use array instead of list for CRTCs Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 24/46] imx-drm: provide common connector mode validation function Russell King
2014-01-02 21:27   ` Russell King
2014-01-07  6:38   ` Shawn Guo
2014-01-07  6:38     ` Shawn Guo
2014-01-08 21:25     ` Russell King - ARM Linux
2014-01-08 21:25       ` Russell King - ARM Linux
2014-01-02 21:27 ` [PATCH RFC 25/46] imx-drm: simplify setup of panel format Russell King
2014-01-02 21:27   ` Russell King
2014-01-02 21:27 ` [PATCH RFC 26/46] drivers/base: provide an infrastructure for componentised subsystems Russell King
2014-01-02 21:27   ` Russell King
2014-01-03  3:10   ` Greg Kroah-Hartman
2014-01-03  3:10     ` Greg Kroah-Hartman
2014-01-03 11:00     ` Russell King - ARM Linux
2014-01-03 11:00       ` Russell King - ARM Linux
2014-01-03 11:58       ` Rafael J. Wysocki
2014-01-03 11:58         ` Rafael J. Wysocki
2014-01-03 12:18         ` Russell King - ARM Linux
2014-01-03 12:18           ` Russell King - ARM Linux
2014-01-03 13:24           ` Rafael J. Wysocki
2014-01-03 13:24             ` Rafael J. Wysocki
2014-01-03 14:14             ` Russell King - ARM Linux
2014-01-03 14:14               ` Russell King - ARM Linux
2014-01-10 14:54     ` Russell King - ARM Linux
2014-01-10 14:54       ` Russell King - ARM Linux
2014-01-10 15:07       ` Greg Kroah-Hartman
2014-01-10 15:07         ` Greg Kroah-Hartman
2014-01-10 15:11         ` Russell King - ARM Linux
2014-01-10 15:11           ` Russell King - ARM Linux
2014-01-10 15:35           ` Greg Kroah-Hartman
2014-01-10 15:35             ` Greg Kroah-Hartman
2014-01-10 16:04             ` Russell King - ARM Linux
2014-01-10 16:04               ` Russell King - ARM Linux
2014-01-10 18:30             ` Robert Schwebel
2014-01-10 18:30               ` Robert Schwebel
2014-01-10 20:42               ` Greg Kroah-Hartman
2014-01-10 20:42                 ` Greg Kroah-Hartman
2014-01-10 23:23                 ` Russell King - ARM Linux
2014-01-10 23:23                   ` Russell King - ARM Linux
2014-01-11 11:31                   ` Robert Schwebel
2014-01-11 11:31                     ` Robert Schwebel
2014-01-11 11:40                     ` Russell King - ARM Linux
2014-01-11 11:40                       ` Russell King - ARM Linux
2014-01-13  8:34                       ` Philipp Zabel
2014-01-13  8:34                         ` Philipp Zabel
2014-01-07 20:18   ` Sean Paul
2014-01-07 20:18     ` Sean Paul
2014-01-08 21:36     ` Russell King - ARM Linux
2014-01-08 21:36       ` Russell King - ARM Linux
2014-01-08 22:39       ` Sean Paul
2014-01-08 22:39         ` Sean Paul
2014-01-09  7:40         ` Sascha Hauer
2014-01-09  7:40           ` Sascha Hauer
2014-02-07  9:04   ` Daniel Vetter
2014-02-07  9:04     ` Daniel Vetter
2014-02-07  9:04     ` Daniel Vetter
2014-02-07  9:46     ` Russell King - ARM Linux
2014-02-07  9:46       ` Russell King - ARM Linux
2014-02-07 11:57       ` Jean-Francois Moine
2014-02-07 11:57         ` Jean-Francois Moine
2014-02-07 11:57         ` Jean-Francois Moine
2014-02-07 12:28         ` Russell King - ARM Linux
2014-02-07 12:28           ` Russell King - ARM Linux
2014-02-07 12:28           ` Russell King - ARM Linux
2014-02-26 21:00   ` Guennadi Liakhovetski
2014-02-26 21:00     ` Guennadi Liakhovetski
2014-02-26 21:00     ` Guennadi Liakhovetski
2014-02-26 22:19     ` Russell King - ARM Linux
2014-02-26 22:19       ` Russell King - ARM Linux
2014-02-26 22:19       ` Russell King - ARM Linux
2014-03-06 11:46       ` Guennadi Liakhovetski
2014-03-06 11:46         ` Guennadi Liakhovetski
2014-03-06 23:24       ` Laurent Pinchart
2014-03-06 23:24         ` Laurent Pinchart
2014-03-06 23:24         ` Laurent Pinchart
2014-03-19 17:22         ` Laurent Pinchart
2014-03-19 17:22           ` Laurent Pinchart
2014-03-19 17:22           ` Laurent Pinchart
2014-03-19 17:27           ` Russell King - ARM Linux
2014-03-19 17:27             ` Russell King - ARM Linux
2014-03-19 17:27             ` Russell King - ARM Linux
2014-03-21 12:34         ` Russell King - ARM Linux
2014-03-21 12:34           ` Russell King - ARM Linux
2014-03-21 12:34           ` Russell King - ARM Linux
2014-01-02 21:28 ` [PATCH RFC 27/46] imx-drm: convert to componentised device support Russell King
2014-01-02 21:28   ` Russell King
2014-01-03 16:48   ` Philipp Zabel
2014-01-03 16:48     ` Philipp Zabel
2014-01-03 17:07     ` Russell King - ARM Linux
2014-01-03 17:07       ` Russell King - ARM Linux
2014-01-03 17:26       ` Philipp Zabel
2014-01-03 17:26         ` Philipp Zabel
2014-01-03 17:38         ` Russell King - ARM Linux
2014-01-03 17:38           ` Russell King - ARM Linux
2014-01-03 19:14         ` Eric Nelson
2014-01-03 19:14           ` Eric Nelson
2014-01-06 17:41           ` Philipp Zabel
2014-01-06 17:41             ` Philipp Zabel
2014-01-06 17:46             ` Russell King - ARM Linux
2014-01-06 17:46               ` Russell King - ARM Linux
2014-01-07  2:31               ` Eric Nelson
2014-01-07  2:31                 ` Eric Nelson
2014-01-07 11:29                 ` Philipp Zabel
2014-01-07 11:29                   ` Philipp Zabel
2014-01-07 15:30                   ` Eric Nelson
2014-01-07 15:30                     ` Eric Nelson
2014-01-07 16:29                     ` Philipp Zabel
2014-01-07 16:29                       ` Philipp Zabel
2014-01-08 21:40                       ` Russell King - ARM Linux
2014-01-08 21:40                         ` Russell King - ARM Linux
2014-01-07  8:59   ` Shawn Guo
2014-01-07  8:59     ` Shawn Guo
2014-01-08 21:32     ` Russell King - ARM Linux
2014-01-08 21:32       ` Russell King - ARM Linux
2014-01-09 15:25       ` Shawn Guo
2014-01-09 15:25         ` Shawn Guo
2014-01-09 15:33         ` Russell King - ARM Linux
2014-01-09 15:33           ` Russell King - ARM Linux
2014-01-02 21:28 ` [PATCH RFC 28/46] imx-drm: imx-hdmi: convert to a component device Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 29/46] imx-drm: delay publishing sysfs connector entries Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 30/46] imx-drm: remove separate imx-fbdev Russell King
2014-01-02 21:28   ` Russell King
2014-01-07  6:49   ` Shawn Guo
2014-01-07  6:49     ` Shawn Guo
2014-01-08 21:27     ` Russell King - ARM Linux
2014-01-08 21:27       ` Russell King - ARM Linux
2014-01-02 21:28 ` [PATCH RFC 31/46] imx-drm: remove imx-fb.c Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 32/46] imx-drm: use supplied drm_device where possible Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 33/46] imx-drm: imx-drm-core: provide helper function to parse possible crtcs Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 34/46] imx-drm: imx-drm-core: provide common connector and encoder cleanup functions Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 35/46] imx-drm: parallel-display,imx-tve,imx-ldb: initialise drm components directly Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 36/46] imx-drm: imx-hdmi: " Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:28 ` [PATCH RFC 37/46] imx-drm: imx-drm-core: remove imx_drm_connector and imx_drm_encoder code Russell King
2014-01-02 21:28   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 38/46] imx-drm: imx-drm-core: get rid of drm_mode_group_init_legacy_group() Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 39/46] imx-drm: imx-drm-core: kill off mutex Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 40/46] imx-drm: imx-drm-core: move allocation of imxdrm device to driver load function Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 41/46] imx-drm: imx-drm-core: various cleanups Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 42/46] imx-drm: imx-drm-core: add core hotplug connector support Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 43/46] imx-drm: imx-hdmi: add hotplug support to HDMI component Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 44/46] imx-drm: dw-hdmi-audio: add audio driver Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 45/46] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver Russell King
2014-01-02 21:29   ` Russell King
2014-01-02 21:29 ` [PATCH RFC 46/46] imx-drm: pass an IPU ID to crtc and core (needs work) Russell King
2014-01-02 21:29   ` Russell King
2014-01-07  6:33 ` [PATCH RFC 00/46] Preview of imx-drm cleanup series Shawn Guo
2014-01-07  6:33   ` Shawn Guo
2014-01-09 13:17   ` Russell King - ARM Linux
2014-01-09 13:17     ` Russell King - ARM Linux

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.