diff --git a/patch.sh b/patch.sh
index f6ea1894e94b87816f37ae2a064b355d803b7a23..775ed5abf5f235c030e018b789f8314020b950e2 100644
--- a/patch.sh
+++ b/patch.sh
@@ -372,6 +372,58 @@ dts () {
 	${git} "${DIR}/patches/dts/0009-arm-dts-am335x-bone-common-setup-default-pinmux-http.patch"
 
 	${git} "${DIR}/patches/dts/0010-ARM-dts-omap3-beagle-xm-spidev.patch"
+	${git} "${DIR}/patches/dts/0011-hack-wand-enable-hdmi.patch"
+}
+
+imx_drm () {
+	echo "dir: imx_drm"
+	${git} "${DIR}/patches/imx_drm/0001-imx-drm-imx-hdmi-convert-HDMI-clock-settings-to-tabu.patch"
+	${git} "${DIR}/patches/imx_drm/0002-imx-drm-imx-hdmi-clean-up-setting-CSC-registers.patch"
+	${git} "${DIR}/patches/imx_drm/0003-imx-drm-imx-hdmi-provide-register-modification-funct.patch"
+	${git} "${DIR}/patches/imx_drm/0004-imx-drm-imx-hdmi-clean-up-setting-of-vp_conf.patch"
+	${git} "${DIR}/patches/imx_drm/0005-imx-drm-imx-hdmi-fix-CTS-N-setup-at-init-time.patch"
+	${git} "${DIR}/patches/imx_drm/0006-imx-drm-ipu-v3-more-inteligent-DI-clock-selection.patch"
+	${git} "${DIR}/patches/imx_drm/0007-imx-drm-ipu-v3-don-t-use-clk_round_rate-before-clk_s.patch"
+	${git} "${DIR}/patches/imx_drm/0008-imx-drm-ipu-v3-more-clocking-fixes.patch"
+	${git} "${DIR}/patches/imx_drm/0009-imx-drm-add-imx6-DT-configuration-for-HDMI.patch"
+	${git} "${DIR}/patches/imx_drm/0010-imx-drm-update-and-fix-imx6-DT-descriptions-for-v3-H.patch"
+	${git} "${DIR}/patches/imx_drm/0011-imx-drm-imx-drm-core-sanitise-imx_drm_encoder_get_mu.patch"
+	${git} "${DIR}/patches/imx_drm/0012-imx-drm-imx-drm-core-use-array-instead-of-list-for-C.patch"
+	${git} "${DIR}/patches/imx_drm/0013-imx-drm-provide-common-connector-mode-validation-fun.patch"
+	${git} "${DIR}/patches/imx_drm/0014-imx-drm-simplify-setup-of-panel-format.patch"
+	${git} "${DIR}/patches/imx_drm/0015-imx-drm-convert-to-componentised-device-support.patch"
+	${git} "${DIR}/patches/imx_drm/0016-imx-drm-imx-hdmi-convert-to-a-component-device.patch"
+	${git} "${DIR}/patches/imx_drm/0017-imx-drm-delay-publishing-sysfs-connector-entries.patch"
+	${git} "${DIR}/patches/imx_drm/0018-imx-drm-remove-separate-imx-fbdev.patch"
+	${git} "${DIR}/patches/imx_drm/0019-imx-drm-remove-imx-fb.c.patch"
+	${git} "${DIR}/patches/imx_drm/0020-imx-drm-use-supplied-drm_device-where-possible.patch"
+	${git} "${DIR}/patches/imx_drm/0021-imx-drm-imx-drm-core-provide-helper-function-to-pars.patch"
+	${git} "${DIR}/patches/imx_drm/0022-imx-drm-imx-drm-core-provide-common-connector-and-en.patch"
+	${git} "${DIR}/patches/imx_drm/0023-imx-drm-parallel-display-imx-tve-imx-ldb-initialise-.patch"
+	${git} "${DIR}/patches/imx_drm/0024-imx-drm-imx-hdmi-initialise-drm-components-directly.patch"
+	${git} "${DIR}/patches/imx_drm/0025-imx-drm-imx-drm-core-remove-imx_drm_connector-and-im.patch"
+	${git} "${DIR}/patches/imx_drm/0026-imx-drm-imx-drm-core-get-rid-of-drm_mode_group_init_.patch"
+	${git} "${DIR}/patches/imx_drm/0027-imx-drm-imx-drm-core-kill-off-mutex.patch"
+	${git} "${DIR}/patches/imx_drm/0028-imx-drm-imx-drm-core-move-allocation-of-imxdrm-devic.patch"
+	${git} "${DIR}/patches/imx_drm/0029-imx-drm-imx-drm-core-various-cleanups.patch"
+	${git} "${DIR}/patches/imx_drm/0030-imx-drm-imx-drm-core-add-core-hotplug-connector-supp.patch"
+	${git} "${DIR}/patches/imx_drm/0031-imx-drm-imx-hdmi-add-hotplug-support-to-HDMI-compone.patch"
+	${git} "${DIR}/patches/imx_drm/0032-imx-drm-dw-hdmi-audio-add-audio-driver.patch"
+	${git} "${DIR}/patches/imx_drm/0033-imx-drm-dw-hdmi-audio-parse-ELD-from-HDMI-driver.patch"
+	${git} "${DIR}/patches/imx_drm/0034-imx-drm-add-CEC-HDMI-driver.patch"
+}
+
+imx_drm_dts () {
+	echo "dir: imx_drm_dts"
+	${git} "${DIR}/patches/imx_drm_dts/0001-staging-imx-drm-core-don-t-request-probe-deferral-in.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0002-staging-imx-drm-Add-temporary-copies-of-v4l2-of-pars.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0003-staging-imx-drm-core-Use-OF-graph-to-find-components.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0004-staging-imx-drm-Document-updated-imx-drm-device-tree.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0005-staging-imx-drm-Document-imx-hdmi-device-tree-bindin.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0006-ARM-dts-imx51-Add-IPU-ports-and-endpoints-move-imx-d.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0007-ARM-dts-imx53-Add-IPU-DI-ports-and-endpoints-move-im.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0008-ARM-dts-imx6qdl-Add-IPU-DI-ports-and-endpoints-move-.patch"
+	${git} "${DIR}/patches/imx_drm_dts/0009-staging-imx-drm-Update-TODO.patch"
 }
 
 imx_video_staging () {
@@ -439,7 +491,9 @@ usb
 
 dts
 
-imx_video_staging
+imx_drm
+imx_drm_dts
+#imx_video_staging
 omap_sprz319_erratum
 
 omap3_beagle_xm_rework
diff --git a/patches/defconfig b/patches/defconfig
index 2e5c13a361099e476d2cd2737874e1a8641d912d..764cb0a8966d99d29e0108c1a010a348e9f6a90c 100644
--- a/patches/defconfig
+++ b/patches/defconfig
@@ -3583,12 +3583,12 @@ CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 CONFIG_LOGO_LINUX_CLUT224=y
 CONFIG_FB_SSD1307=y
-CONFIG_SOUND=m
+CONFIG_SOUND=y
 CONFIG_SOUND_OSS_CORE=y
 CONFIG_SOUND_OSS_CORE_PRECLAIM=y
-CONFIG_SND=m
-CONFIG_SND_TIMER=m
-CONFIG_SND_PCM=m
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
 CONFIG_SND_DMAENGINE_PCM=m
 CONFIG_SND_HWDEP=m
 CONFIG_SND_RAWMIDI=m
@@ -3598,7 +3598,7 @@ CONFIG_SND_SEQUENCER=m
 CONFIG_SND_SEQ_DUMMY=m
 CONFIG_SND_OSSEMUL=y
 CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS=y
 CONFIG_SND_PCM_OSS_PLUGINS=y
 # CONFIG_SND_SEQUENCER_OSS is not set
 CONFIG_SND_HRTIMER=m
@@ -4423,6 +4423,7 @@ CONFIG_DRM_IMX_LDB=y
 CONFIG_DRM_IMX_IPUV3_CORE=y
 CONFIG_DRM_IMX_IPUV3=y
 CONFIG_DRM_IMX_HDMI=y
+CONFIG_DRM_DW_HDMI_CEC=y
 # CONFIG_DGRP is not set
 # CONFIG_LUSTRE_FS is not set
 # CONFIG_XILLYBUS is not set
diff --git a/patches/dts/0002-ARM-dts-imx6qdl-wandboard-Add-support-for-i2c1.patch b/patches/dts/0002-ARM-dts-imx6qdl-wandboard-Add-support-for-i2c1.patch
index 703e5c9bd56d80ef8753bc51319f2bd98c85c6c7..a5d9771d2600a023a6bd5a063667cf8369264c83 100644
--- a/patches/dts/0002-ARM-dts-imx6qdl-wandboard-Add-support-for-i2c1.patch
+++ b/patches/dts/0002-ARM-dts-imx6qdl-wandboard-Add-support-for-i2c1.patch
@@ -7,11 +7,11 @@ This patch adds support for i2c1 to the wandboard common dtsi file.
 
 Signed-off-by: Michael Panetta <panetta.mike@gmail.com>
 ---
- arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 7 +++++++
- 1 file changed, 7 insertions(+)
+ arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
 
 diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
-index cc64556..6706b36 100644
+index 7f30ff7..291c527 100644
 --- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
 +++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
 @@ -62,6 +62,13 @@
@@ -21,13 +21,27 @@ index cc64556..6706b36 100644
 +&i2c1 {
 +	clock-frequency = <100000>;
 +	pinctrl-names = "default";
-+	pinctrl-0 = <&pinctrl_i2c1_1>;
++	pinctrl-0 = <&pinctrl_i2c1>;
 +	status = "okay";
 +};
 +
  &i2c2 {
  	clock-frequency = <100000>;
  	pinctrl-names = "default";
+@@ -127,6 +134,13 @@
+ 			>;
+ 		};
+ 
++		pinctrl_i2c1: i2c1grp {
++			fsl,pins = <
++				MX6QDL_PAD_EIM_D21__I2C1_SCL		0x4001b8b1
++				MX6QDL_PAD_EIM_D28__I2C1_SDA		0x4001b8b1
++			>;
++		};
++
+ 		pinctrl_i2c2: i2c2grp {
+ 			fsl,pins = <
+ 				MX6QDL_PAD_KEY_COL3__I2C2_SCL		0x4001b8b1
 -- 
 1.8.5.3
 
diff --git a/patches/dts/0011-hack-wand-enable-hdmi.patch b/patches/dts/0011-hack-wand-enable-hdmi.patch
new file mode 100644
index 0000000000000000000000000000000000000000..316fe64f15b4128d1496d117b84c105c8cc19824
--- /dev/null
+++ b/patches/dts/0011-hack-wand-enable-hdmi.patch
@@ -0,0 +1,29 @@
+From 8b059ea786fb922c869443d90436b69ee3df6b63 Mon Sep 17 00:00:00 2001
+From: Robert Nelson <robertcnelson@gmail.com>
+Date: Thu, 20 Feb 2014 13:46:50 -0600
+Subject: [PATCH 11/11] hack: wand: enable hdmi
+
+Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
+---
+ arch/arm/boot/dts/imx6qdl-wandboard.dtsi | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+index 9afec84..c0c6960 100644
+--- a/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-wandboard.dtsi
+@@ -78,6 +78,11 @@
+ 	status = "okay";
+ };
+ 
++&hdmi {
++	ddc = <&i2c1>;
++	status = "okay";
++};
++
+ &i2c1 {
+ 	clock-frequency = <100000>;
+ 	pinctrl-names = "default";
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm/0001-imx-drm-imx-hdmi-convert-HDMI-clock-settings-to-tabu.patch b/patches/imx_drm/0001-imx-drm-imx-hdmi-convert-HDMI-clock-settings-to-tabu.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7e86a24d268f5cdbe60b382df7a68979108dd418
--- /dev/null
+++ b/patches/imx_drm/0001-imx-drm-imx-hdmi-convert-HDMI-clock-settings-to-tabu.patch
@@ -0,0 +1,305 @@
+From 42b78b01aab43d0df555a9055e03db9a8fe70fd2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:09:41 +0000
+Subject: [PATCH 01/34] imx-drm: imx-hdmi: convert HDMI clock settings to
+ tabular form
+
+Rather than having large if() and switch() statements, provide a table
+to look up the register settings for various clock rates.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 250 ++++++++++++++-----------------------
+ 1 file changed, 95 insertions(+), 155 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 62ce0e8..cb316bf 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -806,19 +806,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)
+@@ -845,165 +920,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);
++	/* 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 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);
++	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.8.5.3
+
diff --git a/patches/imx_drm/0002-imx-drm-imx-hdmi-clean-up-setting-CSC-registers.patch b/patches/imx_drm/0002-imx-drm-imx-hdmi-clean-up-setting-CSC-registers.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c14fa07b3b208a809d72a983ed49628c4c93d043
--- /dev/null
+++ b/patches/imx_drm/0002-imx-drm-imx-hdmi-clean-up-setting-CSC-registers.patch
@@ -0,0 +1,77 @@
+From 128b27441f134f568fc164309624c35e34930a9a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:09:46 +0000
+Subject: [PATCH 02/34] imx-drm: imx-hdmi: clean up setting CSC registers
+
+Rather than manually writing each register sequentially, we can use a
+loop to reduce the amount of code.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 40 +++++++++++++-------------------------
+ 1 file changed, 14 insertions(+), 26 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index cb316bf..18de310 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -480,6 +480,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;
+ 
+@@ -498,32 +499,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.8.5.3
+
diff --git a/patches/imx_drm/0003-imx-drm-imx-hdmi-provide-register-modification-funct.patch b/patches/imx_drm/0003-imx-drm-imx-hdmi-provide-register-modification-funct.patch
new file mode 100644
index 0000000000000000000000000000000000000000..03ac738c10eca6d2488cf14f118258244401ae39
--- /dev/null
+++ b/patches/imx_drm/0003-imx-drm-imx-hdmi-provide-register-modification-funct.patch
@@ -0,0 +1,341 @@
+From 69c15c5787170e756ee06e764d5903bb70e7f540 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:09:51 +0000
+Subject: [PATCH 03/34] imx-drm: imx-hdmi: provide register modification
+ function
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 182 +++++++++++++------------------------
+ 1 file changed, 65 insertions(+), 117 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 18de310..2fa8658 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -156,37 +156,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);
+@@ -482,7 +479,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) {
+@@ -513,10 +509,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)
+@@ -524,7 +518,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))
+@@ -545,10 +538,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);
+ }
+@@ -603,107 +594,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,
+@@ -1000,7 +964,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;
+@@ -1008,20 +972,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)
+@@ -1245,11 +1202,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 */
+@@ -1593,7 +1546,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);
+ 
+@@ -1603,17 +1555,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.8.5.3
+
diff --git a/patches/imx_drm/0004-imx-drm-imx-hdmi-clean-up-setting-of-vp_conf.patch b/patches/imx_drm/0004-imx-drm-imx-hdmi-clean-up-setting-of-vp_conf.patch
new file mode 100644
index 0000000000000000000000000000000000000000..14fd8c6ebb61d0ff52b028fc2ddb4b14973eac7e
--- /dev/null
+++ b/patches/imx_drm/0004-imx-drm-imx-hdmi-clean-up-setting-of-vp_conf.patch
@@ -0,0 +1,98 @@
+From 57e6643d980504c919e34695209a88ff9084cd65 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:09:56 +0000
+Subject: [PATCH 04/34] imx-drm: imx-hdmi: clean up setting of vp_conf
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 49 +++++++++++++++++---------------------
+ 1 file changed, 22 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 2fa8658..ec5b5e2 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -555,7 +555,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) {
+@@ -599,47 +599,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.8.5.3
+
diff --git a/patches/imx_drm/0005-imx-drm-imx-hdmi-fix-CTS-N-setup-at-init-time.patch b/patches/imx_drm/0005-imx-drm-imx-hdmi-fix-CTS-N-setup-at-init-time.patch
new file mode 100644
index 0000000000000000000000000000000000000000..10af798eb5e7ecb2fbb61bde18591ca598f0a694
--- /dev/null
+++ b/patches/imx_drm/0005-imx-drm-imx-hdmi-fix-CTS-N-setup-at-init-time.patch
@@ -0,0 +1,123 @@
+From 38253a34a0b2dd42b84dd708e0ee13df907332e3 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:02 +0000
+Subject: [PATCH 05/34] imx-drm: imx-hdmi: fix CTS/N setup at init time
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 48 ++++++++------------------------------
+ 1 file changed, 10 insertions(+), 38 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index ec5b5e2..05cf8a0 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -134,7 +134,6 @@ struct imx_hdmi {
+ 	struct i2c_adapter *ddc;
+ 	void __iomem *regs;
+ 
+-	unsigned long pixel_clk_rate;
+ 	unsigned int sample_rate;
+ 	int ratio;
+ };
+@@ -328,34 +327,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);
+@@ -363,32 +353,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);
+ }
+ 
+ /*
+@@ -1636,6 +1606,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.8.5.3
+
diff --git a/patches/imx_drm/0006-imx-drm-ipu-v3-more-inteligent-DI-clock-selection.patch b/patches/imx_drm/0006-imx-drm-ipu-v3-more-inteligent-DI-clock-selection.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0282558224512f7857f2b16d7a47a8e58eb550b9
--- /dev/null
+++ b/patches/imx_drm/0006-imx-drm-ipu-v3-more-inteligent-DI-clock-selection.patch
@@ -0,0 +1,114 @@
+From 41a24912d8ad817925d8a397be124bca23bd1591 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:07 +0000
+Subject: [PATCH 06/34] imx-drm: ipu-v3: more inteligent DI clock selection
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/ipu-v3/ipu-di.c | 54 +++++++++++++++++++++++++++++++--
+ 1 file 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 948a49b..8c7241bb 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.8.5.3
+
diff --git a/patches/imx_drm/0007-imx-drm-ipu-v3-don-t-use-clk_round_rate-before-clk_s.patch b/patches/imx_drm/0007-imx-drm-ipu-v3-don-t-use-clk_round_rate-before-clk_s.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2e41a91b0f07c03287eb5f2289d0b9800e5332b7
--- /dev/null
+++ b/patches/imx_drm/0007-imx-drm-ipu-v3-don-t-use-clk_round_rate-before-clk_s.patch
@@ -0,0 +1,62 @@
+From c793cf51b6aff2ef3c9defa75465112694c047b9 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:12 +0000
+Subject: [PATCH 07/34] imx-drm: ipu-v3: don't use clk_round_rate() before
+ clk_set_rate()
+
+This is nonsense; clk_round_rate() is just clk_set_rate() without the
+side effect of changing the hardware.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/ipu-v3/ipu-di.c | 13 +++++++++----
+ 1 file 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 8c7241bb..d766e18 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.8.5.3
+
diff --git a/patches/imx_drm/0008-imx-drm-ipu-v3-more-clocking-fixes.patch b/patches/imx_drm/0008-imx-drm-ipu-v3-more-clocking-fixes.patch
new file mode 100644
index 0000000000000000000000000000000000000000..c574d5705c3eafcb867d2b1a579805a39afcb1e0
--- /dev/null
+++ b/patches/imx_drm/0008-imx-drm-ipu-v3-more-clocking-fixes.patch
@@ -0,0 +1,453 @@
+From 87659eff31228e0f482b14d0f6f67a46feea8c2c Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:17 +0000
+Subject: [PATCH 08/34] imx-drm: ipu-v3: more clocking fixes
+
+There's no point in using the clk API for this; we end up having to
+violate the layering this provides.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/ipu-v3/ipu-di.c | 328 ++++++++++----------------------
+ 1 file 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 d766e18..82a9eba 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.8.5.3
+
diff --git a/patches/imx_drm/0009-imx-drm-add-imx6-DT-configuration-for-HDMI.patch b/patches/imx_drm/0009-imx-drm-add-imx6-DT-configuration-for-HDMI.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ebd76a048d53469dd296d0c6a2662ef0612abe98
--- /dev/null
+++ b/patches/imx_drm/0009-imx-drm-add-imx6-DT-configuration-for-HDMI.patch
@@ -0,0 +1,66 @@
+From ef200c537fec1c55b3bccdbc5906fd5d953b8e5d Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:22 +0000
+Subject: [PATCH 09/34] imx-drm: add imx6 DT configuration for HDMI
+
+Extracted from another patch by Fabio Estevam, this adds the DT
+configuration for HDMI output on the IMX6 SoCs
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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(+)
+
+diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
+index 9c4942f..818bed3 100644
+--- a/arch/arm/boot/dts/imx6dl.dtsi
++++ b/arch/arm/boot/dts/imx6dl.dtsi
+@@ -109,3 +109,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 fadf498..0ebfea7 100644
+--- a/arch/arm/boot/dts/imx6q.dtsi
++++ b/arch/arm/boot/dts/imx6q.dtsi
+@@ -174,3 +174,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 947e463..3a4f36f 100644
+--- a/arch/arm/boot/dts/imx6qdl.dtsi
++++ b/arch/arm/boot/dts/imx6qdl.dtsi
+@@ -674,6 +674,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 IRQ_TYPE_LEVEL_HIGH>;
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm/0010-imx-drm-update-and-fix-imx6-DT-descriptions-for-v3-H.patch b/patches/imx_drm/0010-imx-drm-update-and-fix-imx6-DT-descriptions-for-v3-H.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ea52e07a656cc69e91fb860da8e809109ef35225
--- /dev/null
+++ b/patches/imx_drm/0010-imx-drm-update-and-fix-imx6-DT-descriptions-for-v3-H.patch
@@ -0,0 +1,54 @@
+From 532291100b7fb6dead5a328feed1195ed4d241a2 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:27 +0000
+Subject: [PATCH 10/34] imx-drm: update and fix imx6 DT descriptions for v3
+ HDMI driver
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 65e54b4..6dc3970 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 d2467f5..187fe33 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 400bbc6..930ebe0 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.8.5.3
+
diff --git a/patches/imx_drm/0011-imx-drm-imx-drm-core-sanitise-imx_drm_encoder_get_mu.patch b/patches/imx_drm/0011-imx-drm-imx-drm-core-sanitise-imx_drm_encoder_get_mu.patch
new file mode 100644
index 0000000000000000000000000000000000000000..00a17dc4e5c6eadd37e42fcfe5efb44c291e0cff
--- /dev/null
+++ b/patches/imx_drm/0011-imx-drm-imx-drm-core-sanitise-imx_drm_encoder_get_mu.patch
@@ -0,0 +1,135 @@
+From fc39343383c52f090d410a7e3ac03c47387e3993 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:32 +0000
+Subject: [PATCH 11/34] imx-drm: imx-drm-core: sanitise
+ imx_drm_encoder_get_mux_id()
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 236ed66..92fde89 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 {
+@@ -503,7 +504,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;
+ 
+@@ -657,22 +658,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 ae90c9c..5649f18 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 05cf8a0..a90f08d 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -1467,8 +1467,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 7e59329..4aa47ae 100644
+--- a/drivers/staging/imx-drm/imx-ldb.c
++++ b/drivers/staging/imx-drm/imx-ldb.c
+@@ -179,8 +179,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 */
+@@ -216,8 +215,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.8.5.3
+
diff --git a/patches/imx_drm/0012-imx-drm-imx-drm-core-use-array-instead-of-list-for-C.patch b/patches/imx_drm/0012-imx-drm-imx-drm-core-use-array-instead-of-list-for-C.patch
new file mode 100644
index 0000000000000000000000000000000000000000..56ffa0bad0402a433860775b82b304ce1de0c700
--- /dev/null
+++ b/patches/imx_drm/0012-imx-drm-imx-drm-core-use-array-instead-of-list-for-C.patch
@@ -0,0 +1,177 @@
+From d7c4ec1acf1402d1937298c31fcfe126202f2ae7 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:38 +0000
+Subject: [PATCH 12/34] imx-drm: imx-drm-core: use array instead of list for
+ CRTCs
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 57 ++++++++++++++--------------------
+ 1 file 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 92fde89..c526884 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;
+ 
+@@ -510,7 +505,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;
+ 
+@@ -533,7 +528,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:
+@@ -553,7 +548,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);
+ 
+@@ -660,14 +655,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);
+ 
+@@ -854,7 +844,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.8.5.3
+
diff --git a/patches/imx_drm/0013-imx-drm-provide-common-connector-mode-validation-fun.patch b/patches/imx_drm/0013-imx-drm-provide-common-connector-mode-validation-fun.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1d00f9d118810e9e98fb202629315cbe3629ccda
--- /dev/null
+++ b/patches/imx_drm/0013-imx-drm-provide-common-connector-mode-validation-fun.patch
@@ -0,0 +1,151 @@
+From ddcbc6f2846cb20086a525f169921855473395bd Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:43 +0000
+Subject: [PATCH 13/34] imx-drm: provide common connector mode validation
+ function
+
+Provide a common connector mode validation function, which can be used
+to limit the available modes according to other components in the
+system.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 c526884..7f14ed0 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 5649f18..4eb594c 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 a90f08d..4b69045 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -1406,13 +1406,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)
+ {
+@@ -1501,7 +1494,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 4aa47ae..c6ec1e9 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)
+ {
+@@ -329,7 +323,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 9abc7ca..2d4e097 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 351d61d..18a3e8a 100644
+--- a/drivers/staging/imx-drm/parallel-display.c
++++ b/drivers/staging/imx-drm/parallel-display.c
+@@ -85,12 +85,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)
+ {
+@@ -147,7 +141,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.8.5.3
+
diff --git a/patches/imx_drm/0014-imx-drm-simplify-setup-of-panel-format.patch b/patches/imx_drm/0014-imx-drm-simplify-setup-of-panel-format.patch
new file mode 100644
index 0000000000000000000000000000000000000000..bc579defd1a764eb48c2b84ba87a42c621ecd14c
--- /dev/null
+++ b/patches/imx_drm/0014-imx-drm-simplify-setup-of-panel-format.patch
@@ -0,0 +1,183 @@
+From 0ad8680c797cb91de91436e7b37afdfc1ecdb6a4 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:48 +0000
+Subject: [PATCH 14/34] imx-drm: simplify setup of panel format
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 7f14ed0..d9786ec 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 4eb594c..e3ca0c6 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 4b69045..50475e6 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -1453,8 +1453,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 c6ec1e9..dd29a4a 100644
+--- a/drivers/staging/imx-drm/imx-ldb.c
++++ b/drivers/staging/imx-drm/imx-ldb.c
+@@ -200,8 +200,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 2d4e097..77131e5 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 22be104..08e0a3b 100644
+--- a/drivers/staging/imx-drm/ipuv3-crtc.c
++++ b/drivers/staging/imx-drm/ipuv3-crtc.c
+@@ -284,6 +284,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 18a3e8a..12bcf4f 100644
+--- a/drivers/staging/imx-drm/parallel-display.c
++++ b/drivers/staging/imx-drm/parallel-display.c
+@@ -108,8 +108,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.8.5.3
+
diff --git a/patches/imx_drm/0015-imx-drm-convert-to-componentised-device-support.patch b/patches/imx_drm/0015-imx-drm-convert-to-componentised-device-support.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a42598d47ed910b92302ef4b0a864c74a023cb92
--- /dev/null
+++ b/patches/imx_drm/0015-imx-drm-convert-to-componentised-device-support.patch
@@ -0,0 +1,823 @@
+From 91e42a3b42ed03dfe1245bbabd6fc89e9e72418b Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:53 +0000
+Subject: [PATCH 15/34] imx-drm: convert to componentised device support
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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-common.dtsi    |   8 ++-
+ arch/arm/boot/dts/imx6q-sabresd.dts        |   4 ++
+ 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 +++++++--
+ 11 files changed, 246 insertions(+), 80 deletions(-)
+
+diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
+index 121dadd..ebe6c1d 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";
+@@ -92,6 +92,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 e8d11e2..d939ba8 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";
+@@ -54,6 +54,12 @@
+ 		power-supply = <&reg_backlight>;
+ 	};
+ 
++	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 55af110..a398745 100644
+--- a/arch/arm/boot/dts/imx53-mba53.dts
++++ b/arch/arm/boot/dts/imx53-mba53.dts
+@@ -35,6 +35,12 @@
+ 		status = "disabled";
+ 	};
+ 
++	imx-drm {
++		compatible = "fsl,imx-drm";
++		crtcs = <&ipu 1>;
++		connectors = <&disp1>, <&tve>;
++	};
++
+ 	regulators {
+ 		compatible = "simple-bus";
+ 		#address-cells = <1>;
+diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi
+index 2dca98b..50823d0 100644
+--- a/arch/arm/boot/dts/imx53-qsb-common.dtsi
++++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi
+@@ -17,7 +17,7 @@
+ 		reg = <0x70000000 0x40000000>;
+ 	};
+ 
+-	display@di0 {
++	display0: display@di0 {
+ 		compatible = "fsl,imx-parallel-display";
+ 		crtcs = <&ipu 0>;
+ 		interface-pix-fmt = "rgb565";
+@@ -68,6 +68,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/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 0d816d3..04487cb 100644
+--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+@@ -79,6 +79,12 @@
+ 		};
+ 	};
+ 
++	imx_drm: 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 d9786ec..82b0337 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)
+ {
+@@ -428,8 +427,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
+ 
+ 	platform_set_drvdata(drm->platformdev, drm);
+ 	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:
+@@ -809,6 +815,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_put_dev(dev_get_drvdata(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;
+@@ -819,27 +889,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_put_dev(platform_get_drvdata(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;
+@@ -852,12 +926,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;
+@@ -865,8 +933,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;
+@@ -874,7 +940,6 @@ err_pdev:
+ 
+ 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 dd29a4a..d00f93f 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>
+@@ -450,11 +451,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;
+@@ -464,17 +465,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;
+@@ -512,7 +513,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;
+ 		}
+ 
+@@ -551,7 +552,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)
+@@ -560,7 +561,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;
+ 		}
+ 
+@@ -571,14 +572,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++) {
+@@ -591,7 +593,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 77131e5..ad840d7 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 @@ static 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 08e0a3b..d779ad2 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>
+@@ -400,43 +401,60 @@ err_put_resources:
+ 	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 12bcf4f..4019cae 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>
+@@ -192,15 +193,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;
+ 
+@@ -218,7 +219,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)
+@@ -226,14 +227,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;
+ 
+@@ -241,7 +243,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.8.5.3
+
diff --git a/patches/imx_drm/0016-imx-drm-imx-hdmi-convert-to-a-component-device.patch b/patches/imx_drm/0016-imx-drm-imx-hdmi-convert-to-a-component-device.patch
new file mode 100644
index 0000000000000000000000000000000000000000..62b9ba1fc5aa0de3a37c8615ffcd8b6ff5496b4f
--- /dev/null
+++ b/patches/imx_drm/0016-imx-drm-imx-hdmi-convert-to-a-component-device.patch
@@ -0,0 +1,129 @@
+From 85adfe924160e949b48227e82a54459f03c58558 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:10:58 +0000
+Subject: [PATCH 16/34] imx-drm: imx-hdmi: convert to a component device
+
+Convert imx-hdmi to be a component device; it will bind and unbind
+at the appropriate moment in the main DRM driver's functions.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 41 +++++++++++++++++++++++++++-----------
+ 1 file changed, 29 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 50475e6..14b4a4b 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>
+@@ -1582,21 +1583,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;
+ 
+@@ -1620,13 +1622,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);
+ 
+@@ -1665,7 +1667,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),
+@@ -1699,7 +1701,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;
+ 
+@@ -1711,9 +1713,10 @@ err_isfr:
+ 	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;
+ 
+@@ -1724,7 +1727,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.8.5.3
+
diff --git a/patches/imx_drm/0017-imx-drm-delay-publishing-sysfs-connector-entries.patch b/patches/imx_drm/0017-imx-drm-delay-publishing-sysfs-connector-entries.patch
new file mode 100644
index 0000000000000000000000000000000000000000..fe8e6cfd57892d45f0e5fd0d11ca1c5d21d4c094
--- /dev/null
+++ b/patches/imx_drm/0017-imx-drm-delay-publishing-sysfs-connector-entries.patch
@@ -0,0 +1,71 @@
+From fe8f9b8adc4e3ef0efa6bf43383f1e440faea00d Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:03 +0000
+Subject: [PATCH 17/34] imx-drm: delay publishing sysfs connector entries
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 22 +++++++++++++++++++++-
+ 1 file changed, 21 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 82b0337..3cd330e 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;
+@@ -432,8 +433,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.8.5.3
+
diff --git a/patches/imx_drm/0018-imx-drm-remove-separate-imx-fbdev.patch b/patches/imx_drm/0018-imx-drm-remove-separate-imx-fbdev.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4dc7c325cb6e01b64079da23bf12f3d578957161
--- /dev/null
+++ b/patches/imx_drm/0018-imx-drm-remove-separate-imx-fbdev.patch
@@ -0,0 +1,246 @@
+From d2f8f5f2af13f2960d0e71bae5793bb75adc23ad Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:08 +0000
+Subject: [PATCH 18/34] imx-drm: remove separate imx-fbdev
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 4677585..5239f90 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 3cd330e..5a60886 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)
+@@ -80,16 +84,23 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id);
+ 
+ static void imx_drm_driver_lastclose(struct drm_device *drm)
+ {
++#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ 	struct imx_drm_device *imxdrm = drm->dev_private;
+ 
+ 	if (imxdrm->fbhelper)
+ 		drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
++#endif
+ }
+ 
+ static int imx_drm_driver_unload(struct drm_device *drm)
+ {
++#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ 	struct imx_drm_device *imxdrm = drm->dev_private;
+ 
++	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 @@ unwind_enc:
+ 	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)
+ {
+@@ -450,6 +459,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, MAX_CRTC);
++	if (IS_ERR(imxdrm->fbhelper)) {
++		ret = PTR_ERR(imxdrm->fbhelper);
++		imxdrm->fbhelper = NULL;
++		goto err_unbind;
++	}
++#endif
+ 	return 0;
+ 
+ err_unbind:
+@@ -767,14 +794,6 @@ err_busy:
+ }
+ 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 e3ca0c6..d1fb114 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 8331739..0000000
+--- 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.8.5.3
+
diff --git a/patches/imx_drm/0019-imx-drm-remove-imx-fb.c.patch b/patches/imx_drm/0019-imx-drm-remove-imx-fb.c.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7793d783e253d33c36c85052f11ecdbfd47989b1
--- /dev/null
+++ b/patches/imx_drm/0019-imx-drm-remove-imx-fb.c.patch
@@ -0,0 +1,123 @@
+From f4aa6ec9c3f2bd067af5ef67a990cfc97ade3b13 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:13 +0000
+Subject: [PATCH 19/34] imx-drm: remove imx-fb.c
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 5239f90..129e3a3 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 5a60886..3e3fd28 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 03a7b4e..0000000
+--- 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.8.5.3
+
diff --git a/patches/imx_drm/0020-imx-drm-use-supplied-drm_device-where-possible.patch b/patches/imx_drm/0020-imx-drm-use-supplied-drm_device-where-possible.patch
new file mode 100644
index 0000000000000000000000000000000000000000..eaf1c1c35c002c9f8376823bf14d71f9d4f8aaf0
--- /dev/null
+++ b/patches/imx_drm/0020-imx-drm-use-supplied-drm_device-where-possible.patch
@@ -0,0 +1,206 @@
+From d47cbb62536e5d97a35a7be953a311c46a55cd39 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:19 +0000
+Subject: [PATCH 20/34] imx-drm: use supplied drm_device where possible
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 3e3fd28..3d1c6b6 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);
+ 
+@@ -536,12 +518,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;
+ 
+@@ -575,8 +557,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;
+@@ -588,11 +568,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);
+@@ -622,8 +600,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 d1fb114..7846523 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 d779ad2..e646017 100644
+--- a/drivers/staging/imx-drm/ipuv3-crtc.c
++++ b/drivers/staging/imx-drm/ipuv3-crtc.c
+@@ -336,7 +336,7 @@ err_out:
+ }
+ 
+ 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;
+@@ -350,9 +350,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);
+@@ -404,6 +404,7 @@ err_put_resources:
+ 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;
+ 
+@@ -413,7 +414,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.8.5.3
+
diff --git a/patches/imx_drm/0021-imx-drm-imx-drm-core-provide-helper-function-to-pars.patch b/patches/imx_drm/0021-imx-drm-imx-drm-core-provide-helper-function-to-pars.patch
new file mode 100644
index 0000000000000000000000000000000000000000..7af95c5b92169fd97063b47e98adf950669c9749
--- /dev/null
+++ b/patches/imx_drm/0021-imx-drm-imx-drm-core-provide-helper-function-to-pars.patch
@@ -0,0 +1,112 @@
+From 2a9f8c0acc17669c07a4e39312d4b69880ca9518 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:24 +0000
+Subject: [PATCH 21/34] imx-drm: imx-drm-core: provide helper function to parse
+ possible crtcs
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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(+)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 3d1c6b6..5cac6ee 100644
+--- a/drivers/staging/imx-drm/imx-drm-core.c
++++ b/drivers/staging/imx-drm/imx-drm-core.c
+@@ -658,6 +658,72 @@ err_busy:
+ }
+ 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_crtc_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 7846523..49d4aaf 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.8.5.3
+
diff --git a/patches/imx_drm/0022-imx-drm-imx-drm-core-provide-common-connector-and-en.patch b/patches/imx_drm/0022-imx-drm-imx-drm-core-provide-common-connector-and-en.patch
new file mode 100644
index 0000000000000000000000000000000000000000..91635b674abe767b0b9cf78311a04427d63eda50
--- /dev/null
+++ b/patches/imx_drm/0022-imx-drm-imx-drm-core-provide-common-connector-and-en.patch
@@ -0,0 +1,65 @@
+From 492e1547ad1e36e14109a886d9a7ae7b0986e2dc Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:29 +0000
+Subject: [PATCH 22/34] imx-drm: imx-drm-core: provide common connector and
+ encoder cleanup functions
+
+Provide two helper functions to assist with cleaning up imx-drm
+connectors and encoders.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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      |  3 +++
+ 2 files changed, 16 insertions(+)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 5cac6ee..1f50acd 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 49d4aaf..0543606 100644
+--- a/drivers/staging/imx-drm/imx-drm.h
++++ b/drivers/staging/imx-drm/imx-drm.h
+@@ -8,6 +8,7 @@
+ struct drm_crtc;
+ struct drm_connector;
+ struct drm_device;
++struct drm_display_mode;
+ struct drm_encoder;
+ struct imx_drm_crtc;
+ struct drm_fbdev_cma;
+@@ -69,5 +70,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.8.5.3
+
diff --git a/patches/imx_drm/0023-imx-drm-parallel-display-imx-tve-imx-ldb-initialise-.patch b/patches/imx_drm/0023-imx-drm-parallel-display-imx-tve-imx-ldb-initialise-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..889e2b38ead344196cc6eb094b926751a06821f3
--- /dev/null
+++ b/patches/imx_drm/0023-imx-drm-parallel-display-imx-tve-imx-ldb-initialise-.patch
@@ -0,0 +1,461 @@
+From 5a9eae85f9f047c3da4aa372a7fbbe1d4c1d94b8 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:34 +0000
+Subject: [PATCH 23/34] imx-drm: parallel-display,imx-tve,imx-ldb: initialise
+ drm components directly
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 d00f93f..5168c76 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);
+@@ -308,16 +302,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 = {
+@@ -327,7 +316,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 = {
+@@ -354,45 +343,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);
+@@ -453,6 +433,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);
+@@ -523,6 +504,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) {
+@@ -565,11 +547,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);
+@@ -585,13 +565,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 ad840d7..702c0c3 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 @@ static 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 4019cae..d610f07 100644
+--- a/drivers/staging/imx-drm/parallel-display.c
++++ b/drivers/staging/imx-drm/parallel-display.c
+@@ -33,9 +33,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;
+@@ -50,11 +48,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);
+@@ -126,16 +119,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 = {
+@@ -145,7 +133,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 = {
+@@ -157,36 +145,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;
+ 
+@@ -195,6 +173,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;
+@@ -221,12 +200,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;
+@@ -236,13 +213,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.8.5.3
+
diff --git a/patches/imx_drm/0024-imx-drm-imx-hdmi-initialise-drm-components-directly.patch b/patches/imx_drm/0024-imx-drm-imx-hdmi-initialise-drm-components-directly.patch
new file mode 100644
index 0000000000000000000000000000000000000000..051ff95cf77ab0384212a2ace19986f1bbfe080c
--- /dev/null
+++ b/patches/imx_drm/0024-imx-drm-imx-hdmi-initialise-drm-components-directly.patch
@@ -0,0 +1,149 @@
+From 55c91d0127a9cf36e45801047d3ba20035622e6a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:39 +0000
+Subject: [PATCH 24/34] imx-drm: imx-hdmi: initialise drm components directly
+
+Rather than calling into imx-drm-core to setup and register the encoders
+and connectors, do this ourselves.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 56 ++++++++++----------------------------
+ 1 file changed, 15 insertions(+), 41 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 14b4a4b..8c58645 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -113,9 +113,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;
+@@ -1378,10 +1376,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,
+@@ -1467,13 +1461,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 = {
+@@ -1489,7 +1478,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 = {
+@@ -1529,34 +1518,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;
+ 
+@@ -1588,6 +1566,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;
+@@ -1695,12 +1674,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;
+@@ -1717,12 +1694,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.8.5.3
+
diff --git a/patches/imx_drm/0025-imx-drm-imx-drm-core-remove-imx_drm_connector-and-im.patch b/patches/imx_drm/0025-imx-drm-imx-drm-core-remove-imx_drm_connector-and-im.patch
new file mode 100644
index 0000000000000000000000000000000000000000..71ab52af266ff77e80f63b7eae9524b71a413ee7
--- /dev/null
+++ b/patches/imx_drm/0025-imx-drm-imx-drm-core-remove-imx_drm_connector-and-im.patch
@@ -0,0 +1,517 @@
+From a2b51b9e8c36c870a07883d1d212a368d42b5f3e Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:45 +0000
+Subject: [PATCH 25/34] imx-drm: imx-drm-core: remove imx_drm_connector and
+ imx_drm_encoder code
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 371 +--------------------------------
+ drivers/staging/imx-drm/imx-drm.h      |  14 --
+ 2 files changed, 1 insertion(+), 384 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 1f50acd..b27c425 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,12 +291,8 @@ 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;
+-	}
+-
+ 	platform_set_drvdata(drm->platformdev, drm);
++
+ 	mutex_unlock(&imxdrm->mutex);
+ 
+ 	/* Now try and bind all our sub-components */
+@@ -492,7 +340,6 @@ 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);
+@@ -502,29 +349,6 @@ err_kms:
+ 	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
+  *
+@@ -584,8 +408,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;
+@@ -622,56 +444,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
+@@ -737,49 +509,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);
+@@ -788,102 +517,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 */
+ };
+@@ -1031,8 +664,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 0543606..ae9c96d 100644
+--- a/drivers/staging/imx-drm/imx-drm.h
++++ b/drivers/staging/imx-drm/imx-drm.h
+@@ -39,18 +39,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);
+@@ -63,8 +51,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.8.5.3
+
diff --git a/patches/imx_drm/0026-imx-drm-imx-drm-core-get-rid-of-drm_mode_group_init_.patch b/patches/imx_drm/0026-imx-drm-imx-drm-core-get-rid-of-drm_mode_group_init_.patch
new file mode 100644
index 0000000000000000000000000000000000000000..68277d47076a8b2286ebe1b8a8881217a564371b
--- /dev/null
+++ b/patches/imx_drm/0026-imx-drm-imx-drm-core-get-rid-of-drm_mode_group_init_.patch
@@ -0,0 +1,39 @@
+From 592d52a2596477ab364eef2ff8bb6e62c523dfd1 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:50 +0000
+Subject: [PATCH 26/34] imx-drm: imx-drm-core: get rid of
+ drm_mode_group_init_legacy_group()
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 6 ------
+ 1 file changed, 6 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index b27c425..dd97412 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.8.5.3
+
diff --git a/patches/imx_drm/0027-imx-drm-imx-drm-core-kill-off-mutex.patch b/patches/imx_drm/0027-imx-drm-imx-drm-core-kill-off-mutex.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4979436d2be59bb2ab70c341432650e249d04464
--- /dev/null
+++ b/patches/imx_drm/0027-imx-drm-imx-drm-core-kill-off-mutex.patch
@@ -0,0 +1,136 @@
+From bb898b9ac39720f30491ca1c3654ddc62a7bd827 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:11:55 +0000
+Subject: [PATCH 27/34] imx-drm: imx-drm-core: kill off mutex
+
+This mutex doesn't protect anything anymore; get rid of it.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 26 +++-----------------------
+ 1 file 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 dd97412..d5b82cb 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);
+@@ -287,12 +283,10 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
+ 
+ 	platform_set_drvdata(drm->platformdev, drm);
+ 
+-	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
+@@ -332,13 +326,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;
+ }
+@@ -358,8 +350,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.
+@@ -386,7 +376,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;
+ 
+@@ -402,8 +391,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:
+@@ -411,7 +398,6 @@ err_register:
+ 	kfree(imx_drm_crtc);
+ err_alloc:
+ err_busy:
+-	mutex_unlock(&imxdrm->mutex);
+ 	return ret;
+ }
+ EXPORT_SYMBOL_GPL(imx_drm_add_crtc);
+@@ -421,16 +407,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;
+@@ -657,8 +639,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.8.5.3
+
diff --git a/patches/imx_drm/0028-imx-drm-imx-drm-core-move-allocation-of-imxdrm-devic.patch b/patches/imx_drm/0028-imx-drm-imx-drm-core-move-allocation-of-imxdrm-devic.patch
new file mode 100644
index 0000000000000000000000000000000000000000..71129a91d1d95fdd33a3a6f2d94e82ae9983b496
--- /dev/null
+++ b/patches/imx_drm/0028-imx-drm-imx-drm-core-move-allocation-of-imxdrm-devic.patch
@@ -0,0 +1,110 @@
+From 4bf7aba3833afd64d1bc56e6f1774c47a97d31ca Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:00 +0000
+Subject: [PATCH 28/34] imx-drm: imx-drm-core: move allocation of imxdrm device
+ to driver load function
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 47 +++++-----------------------------
+ 1 file 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 d5b82cb..35c8f7c 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;
+@@ -604,8 +600,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);
+ }
+ 
+@@ -630,36 +624,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.8.5.3
+
diff --git a/patches/imx_drm/0029-imx-drm-imx-drm-core-various-cleanups.patch b/patches/imx_drm/0029-imx-drm-imx-drm-core-various-cleanups.patch
new file mode 100644
index 0000000000000000000000000000000000000000..43aae1848b40b5c38401ba7a9e014af946c96048
--- /dev/null
+++ b/patches/imx_drm/0029-imx-drm-imx-drm-core-various-cleanups.patch
@@ -0,0 +1,160 @@
+From 992a433091047c6e39a2799dbef9bf641d1a7a39 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:05 +0000
+Subject: [PATCH 29/34] imx-drm: imx-drm-core: various cleanups
+
+Various cleanups are possible after the previous round of changes; these
+have no real functional bearing other than tidying up the code.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+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 35c8f7c..7939cea 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;
+ 
+@@ -350,26 +345,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;
+ 
+@@ -392,8 +381,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);
+@@ -429,8 +416,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_crtc_mask(imx_drm_crtc->crtc);
+ 	}
+ 
+diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
+index ae9c96d..aa21028 100644
+--- a/drivers/staging/imx-drm/imx-drm.h
++++ b/drivers/staging/imx-drm/imx-drm.h
+@@ -5,14 +5,15 @@
+ 
+ #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_display_mode;
+ 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);
+@@ -48,8 +49,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.8.5.3
+
diff --git a/patches/imx_drm/0030-imx-drm-imx-drm-core-add-core-hotplug-connector-supp.patch b/patches/imx_drm/0030-imx-drm-imx-drm-core-add-core-hotplug-connector-supp.patch
new file mode 100644
index 0000000000000000000000000000000000000000..ceb257b504cccc7adbea82b0aafb681ffb1ec5f2
--- /dev/null
+++ b/patches/imx_drm/0030-imx-drm-imx-drm-core-add-core-hotplug-connector-supp.patch
@@ -0,0 +1,91 @@
+From b7c8c869f298d28f9475a66d66bdded6cfc8f92e Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:10 +0000
+Subject: [PATCH 30/34] imx-drm: imx-drm-core: add core hotplug connector
+ support
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 21 +++++++++++++++++----
+ 1 file changed, 17 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 7939cea..dcba518 100644
+--- a/drivers/staging/imx-drm/imx-drm-core.c
++++ b/drivers/staging/imx-drm/imx-drm-core.c
+@@ -69,7 +69,11 @@ static int imx_drm_driver_unload(struct drm_device *drm)
+ {
+ #if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ 	struct imx_drm_device *imxdrm = drm->dev_private;
++#endif
++
++	drm_kms_helper_poll_fini(drm);
+ 
++#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
+ 	if (imxdrm->fbhelper)
+ 		drm_fbdev_cma_fini(imxdrm->fbhelper);
+ #endif
+@@ -77,7 +81,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 +216,18 @@ 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)
++{
++#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
++	struct imx_drm_device *imxdrm = drm->dev_private;
++
++	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 +272,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;
+@@ -313,6 +324,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:
+@@ -320,7 +334,6 @@ err_unbind:
+ err_vblank:
+ 	drm_vblank_cleanup(drm);
+ err_kms:
+-	drm_kms_helper_poll_fini(drm);
+ 	drm_mode_config_cleanup(drm);
+ 
+ 	return ret;
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm/0031-imx-drm-imx-hdmi-add-hotplug-support-to-HDMI-compone.patch b/patches/imx_drm/0031-imx-drm-imx-hdmi-add-hotplug-support-to-HDMI-compone.patch
new file mode 100644
index 0000000000000000000000000000000000000000..54783087ebf95b0daa299890dbe2387d593474c6
--- /dev/null
+++ b/patches/imx_drm/0031-imx-drm-imx-hdmi-add-hotplug-support-to-HDMI-compone.patch
@@ -0,0 +1,151 @@
+From de50a3caeba3881bc646e896569abf0a3640efd4 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:15 +0000
+Subject: [PATCH 31/34] imx-drm: imx-hdmi: add hotplug support to HDMI
+ component
+
+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.
+
+Acked-by: Philipp Zabel <p.zabel@pengutronix.de>
+Acked-by: Shawn Guo <shawn.guo@linaro.org>
+Reviewed-by: Fabio Estevam <fabio.estevam@freescale.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/imx-hdmi.c | 40 +++++++++++++++++++++++++++++++-------
+ 1 file changed, 33 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 8c58645..ab16aba 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -120,6 +120,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;
+ 
+@@ -1301,9 +1303,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;
+ }
+ 
+@@ -1372,8 +1371,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)
+@@ -1487,6 +1487,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;
+@@ -1503,17 +1515,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;
+ }
+@@ -1527,6 +1543,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);
+@@ -1578,6 +1596,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;
+ 
+@@ -1601,8 +1620,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;
+ 
+@@ -1678,6 +1698,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;
+@@ -1695,6 +1718,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.8.5.3
+
diff --git a/patches/imx_drm/0032-imx-drm-dw-hdmi-audio-add-audio-driver.patch b/patches/imx_drm/0032-imx-drm-dw-hdmi-audio-add-audio-driver.patch
new file mode 100644
index 0000000000000000000000000000000000000000..988d3f2a10e2117901dce9a1a44fe2bb0d8b049f
--- /dev/null
+++ b/patches/imx_drm/0032-imx-drm-dw-hdmi-audio-add-audio-driver.patch
@@ -0,0 +1,651 @@
+From 70d75ac722650442c2ef8831adb340202a25bcea Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:20 +0000
+Subject: [PATCH 32/34] imx-drm: dw-hdmi-audio: add audio driver
+
+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 | 499 ++++++++++++++++++++++++++++++++
+ 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, 539 insertions(+), 1 deletion(-)
+ 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 129e3a3..f554aa6 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 0000000..a17714d
+--- /dev/null
++++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
+@@ -0,0 +1,499 @@
++/*
++ * 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 0000000..82a709c
+--- /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 ab16aba..5755368 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -28,6 +28,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"
+@@ -115,6 +116,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;
+@@ -362,6 +364,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
+@@ -1701,10 +1710,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:
+@@ -1718,6 +1737,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 39b6776..8029feb 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.8.5.3
+
diff --git a/patches/imx_drm/0033-imx-drm-dw-hdmi-audio-parse-ELD-from-HDMI-driver.patch b/patches/imx_drm/0033-imx-drm-dw-hdmi-audio-parse-ELD-from-HDMI-driver.patch
new file mode 100644
index 0000000000000000000000000000000000000000..8707092c7deb6e5376ed51c23a3d512009bb9473
--- /dev/null
+++ b/patches/imx_drm/0033-imx-drm-dw-hdmi-audio-parse-ELD-from-HDMI-driver.patch
@@ -0,0 +1,126 @@
+From 2a7d2ce84f05fd886c20d3b7b237a8d0c933820a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:25 +0000
+Subject: [PATCH 33/34] imx-drm: dw-hdmi-audio: parse ELD from HDMI driver
+
+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 | 51 +++++++++++++++++++++++++++++++++
+ drivers/staging/imx-drm/imx-hdmi.c      |  8 ++++++
+ drivers/staging/imx-drm/imx-hdmi.h      |  1 +
+ 3 files changed, 60 insertions(+)
+
+diff --git a/drivers/staging/imx-drm/dw-hdmi-audio.c b/drivers/staging/imx-drm/dw-hdmi-audio.c
+index a17714d..7bff8c9 100644
+--- a/drivers/staging/imx-drm/dw-hdmi-audio.c
++++ b/drivers/staging/imx-drm/dw-hdmi-audio.c
+@@ -273,6 +273,56 @@ 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;
+@@ -301,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 5755368..df20f94 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -371,6 +371,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
+@@ -1402,6 +1408,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 8029feb..5baaa9c 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.8.5.3
+
diff --git a/patches/imx_drm/0034-imx-drm-add-CEC-HDMI-driver.patch b/patches/imx_drm/0034-imx-drm-add-CEC-HDMI-driver.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a6913de314861d3fc3e926c0b194e65c4a17f204
--- /dev/null
+++ b/patches/imx_drm/0034-imx-drm-add-CEC-HDMI-driver.patch
@@ -0,0 +1,800 @@
+From 32f4c5063d0b0caa6347660784adb4cbb005b984 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Tue, 18 Feb 2014 20:12:31 +0000
+Subject: [PATCH 34/34] imx-drm: add CEC HDMI driver
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ drivers/staging/imx-drm/Kconfig       |   8 +
+ drivers/staging/imx-drm/Makefile      |   1 +
+ drivers/staging/imx-drm/dw-hdmi-cec.c | 561 ++++++++++++++++++++++++++++++++++
+ drivers/staging/imx-drm/dw-hdmi-cec.h |  16 +
+ drivers/staging/imx-drm/imx-hdmi.c    |  66 +++-
+ drivers/staging/imx-drm/imx-hdmi.h    |   3 +
+ 6 files changed, 645 insertions(+), 10 deletions(-)
+ create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.c
+ create mode 100644 drivers/staging/imx-drm/dw-hdmi-cec.h
+
+diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig
+index 78319ad..8f4c568 100644
+--- a/drivers/staging/imx-drm/Kconfig
++++ b/drivers/staging/imx-drm/Kconfig
+@@ -59,3 +59,11 @@ config DRM_IMX_HDMI
+ 	depends on DRM_IMX
+ 	help
+ 	  Choose this if you want to use HDMI on i.MX6.
++
++config DRM_DW_HDMI_CEC
++	tristate "Synopsis Designware CEC interface"
++	depends on DRM_IMX_HDMI != n
++	help
++	  Support the CEC interface which is part of the Synposis
++	  Designware HDMI block.  This is used in conjunction with
++	  the i.MX HDMI driver.
+diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
+index f554aa6..53bc725 100644
+--- a/drivers/staging/imx-drm/Makefile
++++ b/drivers/staging/imx-drm/Makefile
+@@ -12,3 +12,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) += imxhdmi.o
++obj-$(CONFIG_DRM_DW_HDMI_CEC) += dw-hdmi-cec.o
+diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.c b/drivers/staging/imx-drm/dw-hdmi-cec.c
+new file mode 100644
+index 0000000..fee508d
+--- /dev/null
++++ b/drivers/staging/imx-drm/dw-hdmi-cec.c
+@@ -0,0 +1,561 @@
++/* http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/mxc/hdmi-cec/mxc_hdmi-cec.c?h=imx_3.0.35_4.1.0 */
++#include <linux/cdev.h>
++#include <linux/device.h>
++#include <linux/interrupt.h>
++#include <linux/io.h>
++#include <linux/list.h>
++#include <linux/module.h>
++#include <linux/mutex.h>
++#include <linux/platform_device.h>
++#include <linux/poll.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++#include <linux/wait.h>
++
++#include "imx-hdmi.h"
++#include "dw-hdmi-cec.h"
++
++#define MAX_MESSAGE_LEN 16
++#define DEV_NAME "mxc_hdmi_cec"
++
++enum {
++	CEC_STAT_DONE		= BIT(0),
++	CEC_STAT_EOM		= BIT(1),
++	CEC_STAT_NACK		= BIT(2),
++	CEC_STAT_ARBLOST	= BIT(3),
++	CEC_STAT_ERROR_INIT	= BIT(4),
++	CEC_STAT_ERROR_FOLL	= BIT(5),
++	CEC_STAT_WAKEUP		= BIT(6),
++
++	CEC_CTRL_START		= BIT(0),
++	CEC_CTRL_NORMAL		= 1 << 1,
++};
++
++static struct class *cec_class;
++static int cec_major;
++
++struct dw_hdmi_cec {
++	struct device *dev;
++	struct cdev cdev;
++	void __iomem *base;
++	const struct dw_hdmi_cec_ops *ops;
++	void *ops_data;
++	int irq;
++
++	struct mutex mutex;
++	unsigned users;
++
++	spinlock_t lock;
++	wait_queue_head_t waitq;
++	struct list_head events;
++	uint8_t write_busy;
++
++	uint8_t	retries;
++	uint16_t addresses;
++	uint16_t physical;
++};
++
++enum {
++	MESSAGE_TYPE_RECEIVE_SUCCESS = 1,
++	MESSAGE_TYPE_NOACK,
++	MESSAGE_TYPE_DISCONNECTED,
++	MESSAGE_TYPE_CONNECTED,
++	MESSAGE_TYPE_SEND_SUCCESS,
++	MESSAGE_TYPE_SEND_ERROR,
++};
++
++enum {
++	HDMICEC_IOC_MAGIC = 'H',
++	/* This is wrong: we pass the argument as a number, not a pointer */
++	HDMICEC_IOC_O_SETLOGICALADDRESS	= _IOW(HDMICEC_IOC_MAGIC, 1, unsigned char),
++	HDMICEC_IOC_SETLOGICALADDRESS	= _IO(HDMICEC_IOC_MAGIC, 1),
++	HDMICEC_IOC_STARTDEVICE		= _IO(HDMICEC_IOC_MAGIC, 2),
++	HDMICEC_IOC_STOPDEVICE		= _IO(HDMICEC_IOC_MAGIC, 3),
++	HDMICEC_IOC_GETPHYADDRESS	= _IOR(HDMICEC_IOC_MAGIC, 4, unsigned char[4]),
++};
++
++struct dw_hdmi_cec_user_event {
++	uint32_t event_type;
++	uint32_t msg_len;
++	uint8_t msg[MAX_MESSAGE_LEN];
++};
++
++struct dw_hdmi_cec_event {
++	struct dw_hdmi_cec_user_event usr;
++	struct list_head node;
++};
++
++static void dw_hdmi_event(struct dw_hdmi_cec *cec, int type)
++{
++	struct dw_hdmi_cec_event *event;
++	unsigned long flags;
++
++	event = kzalloc(sizeof(*event), GFP_ATOMIC);
++	if (event) {
++		event->usr.event_type = type;
++
++		if (type == MESSAGE_TYPE_RECEIVE_SUCCESS) {
++			unsigned i;
++
++			event->usr.msg_len = readb(cec->base + HDMI_CEC_RX_CNT);
++
++			for (i = 0; i < event->usr.msg_len; i++)
++				event->usr.msg[i] = readb(cec->base + HDMI_CEC_RX_DATA0 + i);
++
++			writeb(0, cec->base + HDMI_CEC_LOCK);
++		}
++
++		spin_lock_irqsave(&cec->lock, flags);
++		list_add_tail(&event->node, &cec->events);
++		spin_unlock_irqrestore(&cec->lock, flags);
++		wake_up(&cec->waitq);
++	}
++}
++
++static void dw_hdmi_set_address(struct dw_hdmi_cec *cec)
++{
++	writeb(cec->addresses & 255, cec->base + HDMI_CEC_ADDR_L);
++	writeb(cec->addresses >> 8, cec->base + HDMI_CEC_ADDR_H);
++}
++
++static void dw_hdmi_send_message(struct dw_hdmi_cec *cec, uint8_t *msg,
++	size_t count)
++{
++	unsigned long flags;
++	unsigned i;
++
++	for (i = 0; i < count; i++)
++		writeb(msg[i], cec->base + HDMI_CEC_TX_DATA0 + i);
++
++	writeb(count, cec->base + HDMI_CEC_TX_CNT);
++
++	spin_lock_irqsave(&cec->lock, flags);
++	cec->retries = 5;
++	cec->write_busy = 1;
++	writeb(CEC_CTRL_NORMAL | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
++	spin_unlock_irqrestore(&cec->lock, flags);
++}
++
++static int dw_hdmi_lock_write(struct dw_hdmi_cec *cec, struct file *file)
++	__acquires(cec->mutex)
++{
++	int ret;
++
++	do {
++		if (file->f_flags & O_NONBLOCK) {
++			if (cec->write_busy)
++				return -EAGAIN;
++		} else {
++			ret = wait_event_interruptible(cec->waitq,
++						       !cec->write_busy);
++			if (ret)
++				break;
++		}
++
++		ret = mutex_lock_interruptible(&cec->mutex);
++		if (ret)
++			break;
++
++		if (!cec->write_busy)
++			break;
++
++		mutex_unlock(&cec->mutex);
++	} while (1);
++
++	return ret;
++}
++
++static irqreturn_t dw_hdmi_cec_irq(int irq, void *data)
++{
++	struct dw_hdmi_cec *cec = data;
++	unsigned stat = readb(cec->base + HDMI_IH_CEC_STAT0);
++
++	if (stat == 0)
++		return IRQ_NONE;
++
++	writeb(stat, cec->base + HDMI_IH_CEC_STAT0);
++
++	if (stat & CEC_STAT_ERROR_INIT) {
++		if (cec->retries) {
++			unsigned v = readb(cec->base + HDMI_CEC_CTRL);
++			writeb(v | CEC_CTRL_START, cec->base + HDMI_CEC_CTRL);
++			cec->retries -= 1;
++		} else {
++			cec->write_busy = 0;
++			dw_hdmi_event(cec, MESSAGE_TYPE_SEND_ERROR);
++		}
++	} else if (stat & (CEC_STAT_DONE | CEC_STAT_NACK)) {
++		cec->retries = 0;
++		cec->write_busy = 0;
++		if (stat & CEC_STAT_DONE) {
++			dw_hdmi_event(cec, MESSAGE_TYPE_SEND_SUCCESS);
++		} else {
++			dw_hdmi_event(cec, MESSAGE_TYPE_NOACK);
++		}
++	}
++
++	if (stat & CEC_STAT_EOM)
++		dw_hdmi_event(cec, MESSAGE_TYPE_RECEIVE_SUCCESS);
++
++	return IRQ_HANDLED;
++}
++EXPORT_SYMBOL(dw_hdmi_cec_irq);
++
++static ssize_t dw_hdmi_cec_read(struct file *file, char __user *buf,
++	size_t count, loff_t *ppos)
++{
++	struct dw_hdmi_cec *cec = file->private_data;
++	ssize_t ret;
++
++	if (count > sizeof(struct dw_hdmi_cec_user_event))
++		count = sizeof(struct dw_hdmi_cec_user_event);
++
++	if (!access_ok(VERIFY_WRITE, buf, count))
++		return -EFAULT;
++
++	do {
++		struct dw_hdmi_cec_event *event = NULL;
++		unsigned long flags;
++
++		spin_lock_irqsave(&cec->lock, flags);
++		if (!list_empty(&cec->events)) {
++			event = list_first_entry(&cec->events,
++					struct dw_hdmi_cec_event, node);
++			list_del(&event->node);
++		}
++		spin_unlock_irqrestore(&cec->lock, flags);
++
++		if (event) {
++			ret = __copy_to_user(buf, &event->usr, count) ?
++				 -EFAULT : count;
++			kfree(event);
++			break;
++		}
++
++		if (file->f_flags & O_NONBLOCK) {
++			ret = -EAGAIN;
++			break;
++		}
++
++		ret = wait_event_interruptible(cec->waitq,
++					       !list_empty(&cec->events));
++		if (ret)
++			break;
++	} while (1);
++
++	return ret;
++}
++
++static ssize_t dw_hdmi_cec_write(struct file *file, const char __user *buf,
++	size_t count, loff_t *ppos)
++{
++	struct dw_hdmi_cec *cec = file->private_data;
++	uint8_t msg[MAX_MESSAGE_LEN];
++	int ret;
++
++	if (count > sizeof(msg))
++		return -E2BIG;
++
++	if (copy_from_user(msg, buf, count))
++		return -EFAULT;
++
++	ret = dw_hdmi_lock_write(cec, file);
++	if (ret)
++		return ret;
++
++	dw_hdmi_send_message(cec, msg, count);
++
++	mutex_unlock(&cec->mutex);
++
++	return count;
++}
++
++static long dw_hdmi_cec_ioctl(struct file *file, u_int cmd, unsigned long arg)
++{
++	struct dw_hdmi_cec *cec = file->private_data;
++	int ret;
++
++	switch (cmd) {
++	case HDMICEC_IOC_O_SETLOGICALADDRESS:
++	case HDMICEC_IOC_SETLOGICALADDRESS:
++		if (arg > 15) {
++			ret = -EINVAL;
++			break;
++		}
++
++		ret = dw_hdmi_lock_write(cec, file);
++		if (ret == 0) {
++			unsigned char msg[1];
++
++			cec->addresses = BIT(arg);
++			dw_hdmi_set_address(cec);
++
++			/*
++			 * Send a ping message with the source and destination
++			 * set to our address; the result indicates whether
++			 * unit has chosen our address simultaneously.
++			 */
++			msg[0] = arg << 4 | arg;
++			dw_hdmi_send_message(cec, msg, sizeof(msg));
++			mutex_unlock(&cec->mutex);
++		}
++		break;
++
++	case HDMICEC_IOC_STARTDEVICE:
++		ret = mutex_lock_interruptible(&cec->mutex);
++		if (ret == 0) {
++			cec->addresses = BIT(15);
++			dw_hdmi_set_address(cec);
++			mutex_unlock(&cec->mutex);
++		}
++		break;
++
++	case HDMICEC_IOC_STOPDEVICE:
++		ret = 0;
++		break;
++
++	case HDMICEC_IOC_GETPHYADDRESS:
++		ret = put_user(cec->physical, (uint16_t __user *)arg);
++		ret = -ENOIOCTLCMD;
++		break;
++
++	default:
++		ret = -ENOIOCTLCMD;
++		break;
++	}
++
++	return ret;
++}
++
++static unsigned dw_hdmi_cec_poll(struct file *file, poll_table *wait)
++{
++	struct dw_hdmi_cec *cec = file->private_data;
++	unsigned mask = 0;
++
++	poll_wait(file, &cec->waitq, wait);
++
++	if (cec->write_busy == 0)
++		mask |= POLLOUT | POLLWRNORM;
++	if (!list_empty(&cec->events))
++		mask |= POLLIN | POLLRDNORM;
++
++	return mask;
++}
++
++static int dw_hdmi_cec_open(struct inode *inode, struct file *file)
++{
++	struct dw_hdmi_cec *cec = container_of(inode->i_cdev,
++					       struct dw_hdmi_cec, cdev);
++	int ret = 0;
++
++	nonseekable_open(inode, file);
++
++	file->private_data = cec;
++
++	ret = mutex_lock_interruptible(&cec->mutex);
++	if (ret)
++		return ret;
++
++	if (cec->users++ == 0) {
++		unsigned irqs;
++
++		writeb(0, cec->base + HDMI_CEC_CTRL);
++		writeb(~0, cec->base + HDMI_IH_CEC_STAT0);
++		writeb(0, cec->base + HDMI_CEC_LOCK);
++
++		ret = request_irq(cec->irq, dw_hdmi_cec_irq, IRQF_SHARED,
++				  DEV_NAME, cec);
++		if (ret < 0) {
++			cec->users = 0;
++			goto unlock;
++		}
++
++		cec->addresses = BIT(15);
++		dw_hdmi_set_address(cec);
++
++		cec->ops->enable(cec->ops_data);
++
++		irqs = CEC_STAT_ERROR_INIT | CEC_STAT_NACK | CEC_STAT_EOM |
++		       CEC_STAT_DONE;
++		writeb(irqs, cec->base + HDMI_CEC_POLARITY);
++		writeb(~irqs, cec->base + HDMI_CEC_MASK);
++		writeb(~irqs, cec->base + HDMI_IH_MUTE_CEC_STAT0);
++	}
++ unlock:
++	mutex_unlock(&cec->mutex);
++
++	return ret;
++}
++
++static int dw_hdmi_cec_release(struct inode *inode, struct file *file)
++{
++	struct dw_hdmi_cec *cec = file->private_data;
++
++	mutex_lock(&cec->mutex);
++	if (cec->users >= 1)
++		cec->users -= 1;
++	if (cec->users == 0) {
++		/*
++		 * Wait for any write to complete before shutting down.
++		 * A message should complete in a maximum of 2.75ms *
++		 * 160 bits + 4.7ms, or 444.7ms.  Let's call that 500ms.
++		 * If we time out, shutdown anyway.
++		 */
++		wait_event_timeout(cec->waitq, !cec->write_busy,
++				   msecs_to_jiffies(500));
++
++		writeb(~0, cec->base + HDMI_CEC_MASK);
++		writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
++		writeb(0, cec->base + HDMI_CEC_POLARITY);
++
++		free_irq(cec->irq, cec);
++
++		cec->ops->disable(cec->ops_data);
++
++		while (!list_empty(&cec->events)) {
++			struct dw_hdmi_cec_event *event;
++
++			event = list_first_entry(&cec->events,
++					struct dw_hdmi_cec_event, node);
++			list_del(&event->node);
++			kfree(event);
++		}
++	}
++	mutex_unlock(&cec->mutex);
++	return 0;
++}
++
++static const struct file_operations hdmi_cec_fops = {
++	.owner = THIS_MODULE,
++	.read = dw_hdmi_cec_read,
++	.write = dw_hdmi_cec_write,
++	.open = dw_hdmi_cec_open,
++	.unlocked_ioctl = dw_hdmi_cec_ioctl,
++	.release = dw_hdmi_cec_release,
++	.poll = dw_hdmi_cec_poll,
++};
++
++static int dw_hdmi_cec_probe(struct platform_device *pdev)
++{
++	struct dw_hdmi_cec_data *data = dev_get_platdata(&pdev->dev);
++	struct dw_hdmi_cec *cec;
++	struct device *cd;
++	dev_t devn = MKDEV(cec_major, 0);
++	int ret;
++
++	if (!data)
++		return -ENXIO;
++
++	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
++	if (!cec)
++		return -ENOMEM;
++
++	cec->dev = &pdev->dev;
++	cec->base = data->base;
++	cec->irq = data->irq;
++	cec->ops = data->ops;
++	cec->ops_data = data->ops_data;
++
++	INIT_LIST_HEAD(&cec->events);
++	init_waitqueue_head(&cec->waitq);
++	spin_lock_init(&cec->lock);
++	mutex_init(&cec->mutex);
++
++	/* FIXME: soft-reset the CEC interface */
++
++	cec->addresses = BIT(15);
++	dw_hdmi_set_address(cec);
++	writeb(0, cec->base + HDMI_CEC_TX_CNT);
++	writeb(~0, cec->base + HDMI_CEC_MASK);
++	writeb(~0, cec->base + HDMI_IH_MUTE_CEC_STAT0);
++	writeb(0, cec->base + HDMI_CEC_POLARITY);
++
++	cdev_init(&cec->cdev, &hdmi_cec_fops);
++	cec->cdev.owner = THIS_MODULE;
++	ret = cdev_add(&cec->cdev, devn, 1);
++	if (ret < 0)
++		goto err_cdev;
++
++	cd = device_create(cec_class, cec->dev, devn, NULL, DEV_NAME);
++	if (IS_ERR(cd)) {
++		ret = PTR_ERR(cd);
++		dev_err(cec->dev, "can't create device: %d\n", ret);
++		goto err_dev;
++	}
++
++	return 0;
++
++ err_dev:
++	cdev_del(&cec->cdev);
++ err_cdev:
++	return ret;
++}
++
++static int dw_hdmi_cec_remove(struct platform_device *pdev)
++{
++	struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
++	dev_t devn = MKDEV(cec_major, 0);
++
++	device_destroy(cec_class, devn);
++	cdev_del(&cec->cdev);
++
++	return 0;
++}
++
++static struct platform_driver dw_hdmi_cec_driver = {
++	.probe	= dw_hdmi_cec_probe,
++	.remove	= dw_hdmi_cec_remove,
++	.driver = {
++		.name = "dw-hdmi-cec",
++		.owner = THIS_MODULE,
++	},
++};
++
++static int dw_hdmi_cec_init(void)
++{
++	dev_t dev;
++	int ret;
++
++	cec_class = class_create(THIS_MODULE, DEV_NAME);
++	if (IS_ERR(cec_class)) {
++		ret = PTR_ERR(cec_class);
++		pr_err("cec: can't create cec class: %d\n", ret);
++		goto err_class;
++	}
++
++	ret = alloc_chrdev_region(&dev, 0, 1, DEV_NAME);
++	if (ret) {
++		pr_err("cec: can't create character devices: %d\n", ret);
++		goto err_chrdev;
++	}
++
++	cec_major = MAJOR(dev);
++
++	ret = platform_driver_register(&dw_hdmi_cec_driver);
++	if (ret)
++		goto err_driver;
++
++	return 0;
++
++ err_driver:
++	unregister_chrdev_region(MKDEV(cec_major, 0), 1);
++ err_chrdev:
++	class_destroy(cec_class);
++ err_class:
++	return ret;
++}
++module_init(dw_hdmi_cec_init);
++
++static void dw_hdmi_cec_exit(void)
++{
++	platform_driver_unregister(&dw_hdmi_cec_driver);
++	unregister_chrdev_region(MKDEV(cec_major, 0), 1);
++	class_destroy(cec_class);
++}
++module_exit(dw_hdmi_cec_exit);
++
++MODULE_AUTHOR("Russell King <rmk+kernel@arm.linux.org.uk>");
++MODULE_DESCRIPTION("Synopsis Designware HDMI CEC driver for i.MX");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS(PLATFORM_MODULE_PREFIX "dw-hdmi-cec");
+diff --git a/drivers/staging/imx-drm/dw-hdmi-cec.h b/drivers/staging/imx-drm/dw-hdmi-cec.h
+new file mode 100644
+index 0000000..5ff40cc
+--- /dev/null
++++ b/drivers/staging/imx-drm/dw-hdmi-cec.h
+@@ -0,0 +1,16 @@
++#ifndef DW_HDMI_CEC_H
++#define DW_HDMI_CEC_H
++
++struct dw_hdmi_cec_ops {
++	void (*enable)(void *);
++	void (*disable)(void *);
++};
++
++struct dw_hdmi_cec_data {
++	void __iomem *base;
++	int irq;
++	const struct dw_hdmi_cec_ops *ops;
++	void *ops_data;
++};
++
++#endif
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index df20f94..6021913 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -29,6 +29,7 @@
+ #include <drm/drm_encoder_slave.h>
+ 
+ #include "dw-hdmi-audio.h"
++#include "dw-hdmi-cec.h"
+ #include "ipu-v3/imx-ipu-v3.h"
+ #include "imx-hdmi.h"
+ #include "imx-drm.h"
+@@ -116,6 +117,7 @@ struct imx_hdmi {
+ 	struct drm_connector connector;
+ 	struct drm_encoder encoder;
+ 
++	struct platform_device *cec;
+ 	struct snd_dw_hdmi *audio;
+ 	enum imx_hdmi_devtype dev_type;
+ 	struct device *dev;
+@@ -128,6 +130,7 @@ struct imx_hdmi {
+ 	int vic;
+ 
+ 	u8 edid[HDMI_EDID_LEN];
++	u8 mc_clkdis;
+ 	bool cable_plugin;
+ 
+ 	bool phy_enabled;
+@@ -1154,8 +1157,6 @@ static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
+ /* 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);
+@@ -1167,23 +1168,28 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
+ 	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);
++	hdmi->mc_clkdis |= HDMI_MC_CLKDIS_HDCPCLK_DISABLE |
++			   HDMI_MC_CLKDIS_CSCCLK_DISABLE |
++			   HDMI_MC_CLKDIS_AUDCLK_DISABLE |
++			   HDMI_MC_CLKDIS_PREPCLK_DISABLE |
++			   HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
++	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
++	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+ 
+-	clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+-	hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
++	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
++	hdmi_writeb(hdmi, hdmi->mc_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);
++		hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
++		hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+ 	}
+ }
+ 
+ static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
+ {
+-	hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
++	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE;
++	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
+ }
+ 
+ /* Workaround to clear the overflow condition */
+@@ -1578,6 +1584,27 @@ static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
+ 	return 0;
+ }
+ 
++static void imx_hdmi_cec_enable(void *data)
++{
++	struct imx_hdmi *hdmi = data;
++
++	hdmi->mc_clkdis &= ~HDMI_MC_CLKDIS_CECCLK_DISABLE;
++	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
++}
++
++static void imx_hdmi_cec_disable(void *data)
++{
++	struct imx_hdmi *hdmi = data;
++
++	hdmi->mc_clkdis |= HDMI_MC_CLKDIS_CECCLK_DISABLE;
++	hdmi_writeb(hdmi, hdmi->mc_clkdis, HDMI_MC_CLKDIS);
++}
++
++static const struct dw_hdmi_cec_ops imx_hdmi_cec_ops = {
++	.enable = imx_hdmi_cec_enable,
++	.disable = imx_hdmi_cec_disable,
++};
++
+ static struct platform_device_id imx_hdmi_devtype[] = {
+ 	{
+ 		.name = "imx6q-hdmi",
+@@ -1599,11 +1626,13 @@ MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
+ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+ {
+ 	struct platform_device *pdev = to_platform_device(dev);
++	struct platform_device_info pdevinfo;
+ 	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 dw_hdmi_cec_data cec;
+ 	struct imx_hdmi *hdmi;
+ 	struct resource *iores;
+ 	int ret, irq;
+@@ -1616,6 +1645,7 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+ 	hdmi->connector_status = connector_status_disconnected;
+ 	hdmi->sample_rate = 48000;
+ 	hdmi->ratio = 100;
++	hdmi->mc_clkdis = 0x7f;
+ 
+ 	if (of_id) {
+ 		const struct platform_device_id *device_id = of_id->data;
+@@ -1722,6 +1752,20 @@ static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
+ 	if (ret)
+ 		goto err_audio;
+ 
++	cec.base = hdmi->regs;
++	cec.irq = irq;
++	cec.ops = &imx_hdmi_cec_ops;
++	cec.ops_data = hdmi;
++
++	memset(&pdevinfo, 0, sizeof(pdevinfo));
++	pdevinfo.parent = dev;
++	pdevinfo.name = "dw-hdmi-cec";
++	pdevinfo.id = PLATFORM_DEVID_AUTO;
++	pdevinfo.data = &cec;
++	pdevinfo.size_data = sizeof(cec);
++
++	hdmi->cec = platform_device_register_full(&pdevinfo);
++
+ 	dev_set_drvdata(dev, hdmi);
+ 
+ 	return 0;
+@@ -1745,6 +1789,8 @@ static void imx_hdmi_unbind(struct device *dev, struct device *master,
+ {
+ 	struct imx_hdmi *hdmi = dev_get_drvdata(dev);
+ 
++	if (!IS_ERR(hdmi->cec))
++		platform_device_unregister(hdmi->cec);
+ 	snd_dw_hdmi_remove(hdmi->audio);
+ 
+ 	/* Disable all interrupts */
+diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h
+index 5baaa9c..3dbd376 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.h
++++ b/drivers/staging/imx-drm/imx-hdmi.h
+@@ -1034,4 +1034,7 @@ 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);
+ 
++void hdmi_enable_cec(struct imx_hdmi *hdmi);
++void hdmi_disable_cec(struct imx_hdmi *hdmi);
++
+ #endif /* __IMX_HDMI_H__ */
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0001-staging-imx-drm-core-don-t-request-probe-deferral-in.patch b/patches/imx_drm_dts/0001-staging-imx-drm-core-don-t-request-probe-deferral-in.patch
new file mode 100644
index 0000000000000000000000000000000000000000..5c39e887f55a10ee78552249d342c634135402ca
--- /dev/null
+++ b/patches/imx_drm_dts/0001-staging-imx-drm-core-don-t-request-probe-deferral-in.patch
@@ -0,0 +1,52 @@
+From 5fff65f2d8c6aec1ec57538a614a7325ef51fc30 Mon Sep 17 00:00:00 2001
+From: Lucas Stach <l.stach@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:02 +0100
+Subject: [PATCH 1/9] staging: imx-drm-core: don't request probe deferral in
+ imx_drm_encoder_parse_of
+
+Since imx_drm_encoder_parse_of is called from the encoder bind callbacks,
+it is too late to request probe deferral. Rather the core should make sure
+that the crtcs are bound before the encoders, after all needed components
+are probed.
+
+This fixes probe failure when using the LDB on i.MX6.
+
+Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 16 ++++------------
+ 1 file changed, 4 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index dcba518..98a97a2 100644
+--- a/drivers/staging/imx-drm/imx-drm-core.c
++++ b/drivers/staging/imx-drm/imx-drm-core.c
+@@ -457,21 +457,13 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
+ 			return ret;
+ 
+ 		id = args.args_count > 0 ? args.args[0] : 0;
+-		mask = imx_drm_find_crtc_mask(imxdrm, args.np, id);
++		crtc_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;
+ 	}
+ 
++	if (i == 0 || !crtc_mask)
++		return -ENOENT;
++
+ 	encoder->possible_crtcs = crtc_mask;
+ 
+ 	/* FIXME: this is the mask of outputs which can clone this output. */
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0002-staging-imx-drm-Add-temporary-copies-of-v4l2-of-pars.patch b/patches/imx_drm_dts/0002-staging-imx-drm-Add-temporary-copies-of-v4l2-of-pars.patch
new file mode 100644
index 0000000000000000000000000000000000000000..99cfb0286960616342d58c1966c097497a1817de
--- /dev/null
+++ b/patches/imx_drm_dts/0002-staging-imx-drm-Add-temporary-copies-of-v4l2-of-pars.patch
@@ -0,0 +1,187 @@
+From a4dcc84c582ac27416f4e0a340043d669fab13ef Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <philipp.zabel@gmail.com>
+Date: Tue, 18 Feb 2014 12:36:03 +0100
+Subject: [PATCH 2/9] staging: imx-drm: Add temporary copies of v4l2-of parsing
+ functions
+
+The existing v4l2-of parser functions for the video interface bindings
+described in Documentation/device-tree/bindings/media/video-interfaces.txt
+are useful for DRM drivers, too. They will be moved to drivers/media
+so they can be used by drm drivers, too. Until then, duplicate the
+v4l2-of parser functions temporarily.
+
+Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
+---
+ drivers/staging/imx-drm/Makefile     |   2 +-
+ drivers/staging/imx-drm/imx-drm-of.c | 132 +++++++++++++++++++++++++++++++++++
+ drivers/staging/imx-drm/imx-drm.h    |   6 ++
+ 3 files changed, 139 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/staging/imx-drm/imx-drm-of.c
+
+diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile
+index 53bc725..cbe4137 100644
+--- a/drivers/staging/imx-drm/Makefile
++++ b/drivers/staging/imx-drm/Makefile
+@@ -1,5 +1,5 @@
+ 
+-imxdrm-objs := imx-drm-core.o
++imxdrm-objs := imx-drm-core.o imx-drm-of.o
+ imxhdmi-objs := imx-hdmi.o dw-hdmi-audio.o
+ 
+ obj-$(CONFIG_DRM_IMX) += imxdrm.o
+diff --git a/drivers/staging/imx-drm/imx-drm-of.c b/drivers/staging/imx-drm/imx-drm-of.c
+new file mode 100644
+index 0000000..e14b4f3
+--- /dev/null
++++ b/drivers/staging/imx-drm/imx-drm-of.c
+@@ -0,0 +1,132 @@
++/*
++ * Video Interface OF binding parsing library
++ *
++ * Copyright (C) 2012 - 2013 Samsung Electronics Co., Ltd.
++ * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
++ *
++ * Copyright (C) 2012 Renesas Electronics Corp.
++ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of version 2 of the GNU General Public License as
++ * published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/of.h>
++
++/**
++ * imx_drm_of_get_next_endpoint() - get next endpoint node
++ * @parent: pointer to the parent device node
++ * @prev: previous endpoint node, or NULL to get first
++ *
++ * Return: An 'endpoint' node pointer with refcount incremented. Refcount
++ * of the passed @prev node is decremented.
++ */
++struct device_node *imx_drm_of_get_next_endpoint(
++		const struct device_node *parent, struct device_node *prev)
++{
++	struct device_node *endpoint;
++	struct device_node *port = NULL;
++
++	if (!parent)
++		return NULL;
++
++	if (!prev) {
++		struct device_node *node;
++		/*
++		 * It's the first call, we have to find a port subnode
++		 * within this node or within an optional 'ports' node.
++		 */
++		node = of_get_child_by_name(parent, "ports");
++		if (node)
++			parent = node;
++
++		port = of_get_child_by_name(parent, "port");
++
++		if (port) {
++			/* Found a port, get an endpoint. */
++			endpoint = of_get_next_child(port, NULL);
++			of_node_put(port);
++		} else {
++			endpoint = NULL;
++		}
++
++		if (!endpoint)
++			pr_err("%s(): no endpoint nodes specified for %s\n",
++			       __func__, parent->full_name);
++		of_node_put(node);
++	} else {
++		port = of_get_parent(prev);
++		if (!port) {
++			/* Hm, has someone given us the root node ?... */
++			of_node_put(prev);
++			return NULL;
++		}
++
++		endpoint = of_get_next_child(port, prev);
++		if (endpoint) {
++			of_node_put(port);
++			return endpoint;
++		}
++
++		/* No more endpoints under this port, try the next one. */
++		do {
++			port = of_get_next_child(parent, port);
++			if (!port)
++				return NULL;
++		} while (of_node_cmp(port->name, "port"));
++
++		/* Pick up the first endpoint in this port. */
++		endpoint = of_get_next_child(port, NULL);
++		of_node_put(port);
++	}
++
++	return endpoint;
++}
++EXPORT_SYMBOL_GPL(imx_drm_of_get_next_endpoint);
++
++/**
++ * imx_drm_of_get_remote_port_parent() - get remote port's parent node
++ * @node: pointer to a local endpoint device_node
++ *
++ * Return: Remote device node associated with remote endpoint node linked
++ *	   to @node. Use of_node_put() on it when done.
++ */
++struct device_node *imx_drm_of_get_remote_port_parent(
++			       const struct device_node *node)
++{
++	struct device_node *np;
++	unsigned int depth;
++
++	/* Get remote endpoint node. */
++	np = of_parse_phandle(node, "remote-endpoint", 0);
++
++	/* Walk 3 levels up only if there is 'ports' node. */
++	for (depth = 3; depth && np; depth--) {
++		np = of_get_next_parent(np);
++		if (depth == 2 && of_node_cmp(np->name, "ports"))
++			break;
++	}
++	return np;
++}
++EXPORT_SYMBOL(imx_drm_of_get_remote_port_parent);
++
++/**
++ * imx_drm_of_get_remote_port() - get remote port node
++ * @node: pointer to a local endpoint device_node
++ *
++ * Return: Remote port node associated with remote endpoint node linked
++ *	   to @node. Use of_node_put() on it when done.
++ */
++struct device_node *imx_drm_of_get_remote_port(const struct device_node *node)
++{
++	struct device_node *np;
++
++	/* Get remote endpoint node. */
++	np = of_parse_phandle(node, "remote-endpoint", 0);
++	if (!np)
++		return NULL;
++	return of_get_next_parent(np);
++}
++EXPORT_SYMBOL_GPL(imx_drm_of_get_remote_port);
+diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
+index aa21028..793a80b 100644
+--- a/drivers/staging/imx-drm/imx-drm.h
++++ b/drivers/staging/imx-drm/imx-drm.h
+@@ -58,4 +58,10 @@ int imx_drm_connector_mode_valid(struct drm_connector *connector,
+ void imx_drm_connector_destroy(struct drm_connector *connector);
+ void imx_drm_encoder_destroy(struct drm_encoder *encoder);
+ 
++struct device_node *imx_drm_of_get_next_endpoint(
++		const struct device_node *parent, struct device_node *prev);
++struct device_node *imx_drm_of_get_remote_port_parent(
++			       const struct device_node *node);
++struct device_node *imx_drm_of_get_remote_port(const struct device_node *node);
++
+ #endif /* _IMX_DRM_H_ */
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0003-staging-imx-drm-core-Use-OF-graph-to-find-components.patch b/patches/imx_drm_dts/0003-staging-imx-drm-core-Use-OF-graph-to-find-components.patch
new file mode 100644
index 0000000000000000000000000000000000000000..d2db7ebc7fb28fd05eda7c6a4a0fe8030382985e
--- /dev/null
+++ b/patches/imx_drm_dts/0003-staging-imx-drm-core-Use-OF-graph-to-find-components.patch
@@ -0,0 +1,486 @@
+From a53be7ca51806b3b0a98842a4b6bc71541e515e3 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:04 +0100
+Subject: [PATCH 3/9] staging: imx-drm-core: Use OF graph to find components
+ and connections between encoder and crtcs
+
+This patch adds support to find the involved components connected to the
+IPU display interface ports using the OF graph bindings documented in
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Each display interface needs to have an associated port node in the
+device tree. We can associate this node with the crtc platform device
+and use it to find the crtc corresponding to a given port node instead
+of using a combination of parent device node and id number, as before.
+
+Explicitly converting the void* cookie to the port device tree node
+allows to get rid of the ipu_id and di_id fields. The multiplexer
+setting on i.MX6 now can be obtained from the port id (reg property)
+in the device tree.
+
+The imx-drm node now needs a ports property that contains phandles
+to each of the IPU display interface port nodes. From there, all
+attached encoders are scanned and enabled encoders are added to a
+waiting list.
+The bind order makes sure that once all components are probed, crtcs
+are bound before encoders, so that imx_drm_encoder_parse_of can be
+called from the encoder bind callbacks.
+
+For parsing the OF graph, temporary copies of the V4L2 OF graph
+helpers are used, that can be removed again once those are available
+at a generic place.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/staging/imx-drm/imx-drm-core.c | 203 ++++++++++++++++++++++-----------
+ drivers/staging/imx-drm/imx-drm.h      |   5 +-
+ drivers/staging/imx-drm/imx-hdmi.c     |   2 +-
+ drivers/staging/imx-drm/imx-ldb.c      |   4 +-
+ drivers/staging/imx-drm/ipuv3-crtc.c   |  47 ++++++--
+ 5 files changed, 185 insertions(+), 76 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c
+index 98a97a2..92246d9 100644
+--- a/drivers/staging/imx-drm/imx-drm-core.c
++++ b/drivers/staging/imx-drm/imx-drm-core.c
+@@ -30,6 +30,11 @@
+ 
+ struct imx_drm_crtc;
+ 
++struct imx_drm_component {
++	struct device_node *of_node;
++	struct list_head list;
++};
++
+ struct imx_drm_device {
+ 	struct drm_device			*drm;
+ 	struct imx_drm_crtc			*crtc[MAX_CRTC];
+@@ -41,9 +46,7 @@ struct imx_drm_crtc {
+ 	struct drm_crtc				*crtc;
+ 	int					pipe;
+ 	struct imx_drm_crtc_helper_funcs	imx_drm_helper_funcs;
+-	void					*cookie;
+-	int					id;
+-	int					mux_id;
++	struct device_node			*port;
+ };
+ 
+ static int legacyfb_depth = 16;
+@@ -341,14 +344,11 @@ err_kms:
+ 
+ /*
+  * imx_drm_add_crtc - add a new crtc
+- *
+- * 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_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)
++		struct device_node *port)
+ {
+ 	struct imx_drm_device *imxdrm = drm->dev_private;
+ 	struct imx_drm_crtc *imx_drm_crtc;
+@@ -370,9 +370,7 @@ 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->port = port;
+ 	imx_drm_crtc->crtc = crtc;
+ 
+ 	imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
+@@ -416,21 +414,26 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
+ EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
+ 
+ /*
+- * Find the DRM CRTC possible mask for the device node cookie/id.
++ * Find the DRM CRTC possible mask for the connected endpoint.
+  *
+  * 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)
++	struct device_node *endpoint)
+ {
++	struct device_node *port;
+ 	unsigned i;
+ 
++	port = imx_drm_of_get_remote_port(endpoint);
++	if (!port)
++		return 0;
++	of_node_put(port);
++
+ 	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 &&
+-		    imx_drm_crtc->cookie == cookie)
++		if (imx_drm_crtc && imx_drm_crtc->port == port)
+ 			return drm_crtc_mask(imx_drm_crtc->crtc);
+ 	}
+ 
+@@ -441,26 +444,20 @@ 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 = 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;
++	int i;
+ 
+-		ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i,
+-						 &args);
+-		if (ret == -ENOENT)
++	for (i = 0; ; i++) {
++		ep = imx_drm_of_get_next_endpoint(np, ep);
++		if (!ep)
+ 			break;
+-		if (ret < 0)
+-			return ret;
+ 
+-		id = args.args_count > 0 ? args.args[0] : 0;
+-		crtc_mask |= imx_drm_find_crtc_mask(imxdrm, args.np, id);
+-		of_node_put(args.np);
++		crtc_mask |= imx_drm_find_crtc_mask(imxdrm, ep);
+ 	}
+ 
++	if (ep)
++		of_node_put(ep);
+ 	if (i == 0 || !crtc_mask)
+ 		return -ENOENT;
+ 
+@@ -473,11 +470,36 @@ int imx_drm_encoder_parse_of(struct drm_device *drm,
+ }
+ EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
+ 
+-int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
++/*
++ * @node: device tree node containing encoder input ports
++ * @encoder: drm_encoder
++ */
++int imx_drm_encoder_get_mux_id(struct device_node *node,
++			       struct drm_encoder *encoder)
+ {
+ 	struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
++	struct device_node *ep = NULL;
++	struct device_node *port;
++	int id, ret;
++
++	if (!node || !imx_crtc)
++		return -EINVAL;
++
++	do {
++		ep = imx_drm_of_get_next_endpoint(node, ep);
++		if (!ep)
++			break;
+ 
+-	return imx_crtc ? imx_crtc->mux_id : -EINVAL;
++		port = imx_drm_of_get_remote_port(ep);
++		of_node_put(port);
++		if (port == imx_crtc->port) {
++			ret = of_property_read_u32(ep->parent, "reg", &id);
++			of_node_put(ep);
++			return ret ? ret : id;
++		}
++	} while (ep);
++
++	return -EINVAL;
+ }
+ EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
+ 
+@@ -520,48 +542,29 @@ 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;
++	struct device_node *np = data;
+ 
+-		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;
++	/* Special case for LDB, one device for two channels */
++	if (of_node_cmp(np->name, "lvds-channel") == 0) {
++		np = of_get_parent(np);
++		of_node_put(np);
+ 	}
+ 
+-	for (i = 0; ; i++) {
+-		struct device_node *node;
++	return dev->of_node == np;
++}
+ 
+-		node = of_parse_phandle(np, "connectors", i);
+-		if (!node)
+-			break;
++static LIST_HEAD(imx_drm_components);
+ 
+-		ret = component_master_add_child(m, compare_of, node);
+-		of_node_put(node);
++static int imx_drm_add_components(struct device *master, struct master *m)
++{
++	struct imx_drm_component *component;
++	int ret;
+ 
++	list_for_each_entry(component, &imx_drm_components, list) {
++		ret = component_master_add_child(m, compare_of,
++						 component->of_node);
+ 		if (ret)
+ 			return ret;
+ 	}
+@@ -584,9 +587,81 @@ static const struct component_master_ops imx_drm_ops = {
+ 	.unbind = imx_drm_unbind,
+ };
+ 
++static struct imx_drm_component *imx_drm_find_component(struct device *dev,
++							struct device_node *node)
++{
++	struct imx_drm_component *component;
++
++	list_for_each_entry(component, &imx_drm_components, list)
++		if (component->of_node == node)
++			return component;
++
++	return NULL;
++}
++
++static int imx_drm_add_component(struct device *dev, struct device_node *node)
++{
++	struct imx_drm_component *component;
++
++	if (imx_drm_find_component(dev, node))
++		return 0;
++
++	component = devm_kzalloc(dev, sizeof(*component), GFP_KERNEL);
++	if (!component)
++		return -ENOMEM;
++
++	component->of_node = node;
++	list_add_tail(&component->list, &imx_drm_components);
++
++	return 0;
++}
++
+ static int imx_drm_platform_probe(struct platform_device *pdev)
+ {
++	struct device_node *ep, *port, *remote;
+ 	int ret;
++	int i;
++
++	/*
++	 * Bind the IPU display interface ports first, so that
++	 * imx_drm_encoder_parse_of called from encoder .bind callbacks
++	 * works as expected.
++	 */
++	for (i = 0; ; i++) {
++		port = of_parse_phandle(pdev->dev.of_node, "ports", i);
++		if (!port)
++			break;
++
++		ret = imx_drm_add_component(&pdev->dev, port);
++		if (ret < 0)
++			return ret;
++	}
++
++	if (i == 0) {
++		dev_err(&pdev->dev, "missing 'ports' property\n");
++		return -ENODEV;
++	}
++
++	/* Then bind all encoders */
++	for (i = 0; ; i++) {
++		port = of_parse_phandle(pdev->dev.of_node, "ports", i);
++		if (!port)
++			break;
++
++		for_each_child_of_node(port, ep) {
++			remote = imx_drm_of_get_remote_port_parent(ep);
++			if (!remote || !of_device_is_available(remote)) {
++				of_node_put(remote);
++				continue;
++			}
++
++			ret = imx_drm_add_component(&pdev->dev, remote);
++			of_node_put(remote);
++			if (ret < 0)
++				return ret;
++		}
++		of_node_put(port);
++	}
+ 
+ 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
+ 	if (ret)
+diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h
+index 793a80b..447ddd7 100644
+--- a/drivers/staging/imx-drm/imx-drm.h
++++ b/drivers/staging/imx-drm/imx-drm.h
+@@ -30,7 +30,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);
++		struct device_node *port);
+ int imx_drm_remove_crtc(struct imx_drm_crtc *);
+ int imx_drm_init_drm(struct platform_device *pdev,
+ 		int preferred_bpp);
+@@ -49,7 +49,8 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
+ int imx_drm_panel_format(struct drm_encoder *encoder,
+ 		u32 interface_pix_fmt);
+ 
+-int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder);
++int imx_drm_encoder_get_mux_id(struct device_node *node,
++		struct drm_encoder *encoder);
+ int imx_drm_encoder_parse_of(struct drm_device *drm,
+ 	struct drm_encoder *encoder, struct device_node *np);
+ 
+diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c
+index 6021913..5b87ed4 100644
+--- a/drivers/staging/imx-drm/imx-hdmi.c
++++ b/drivers/staging/imx-drm/imx-hdmi.c
+@@ -1477,7 +1477,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(encoder);
++	int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, 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 5168c76..301c430 100644
+--- a/drivers/staging/imx-drm/imx-ldb.c
++++ b/drivers/staging/imx-drm/imx-ldb.c
+@@ -168,7 +168,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(encoder);
++	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
+ 
+ 	if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) {
+ 		/* dual channel LVDS mode */
+@@ -203,7 +203,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(encoder);
++	int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->child, encoder);
+ 
+ 	if (dual) {
+ 		clk_prepare_enable(ldb->clk[0]);
+diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c
+index e646017..a8d0178 100644
+--- a/drivers/staging/imx-drm/ipuv3-crtc.c
++++ b/drivers/staging/imx-drm/ipuv3-crtc.c
+@@ -350,10 +350,8 @@ 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->of_node);
+ 	if (ret) {
+ 		dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
+ 		goto err_put_resources;
+@@ -401,6 +399,28 @@ err_put_resources:
+ 	return ret;
+ }
+ 
++static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
++						  int port_id)
++{
++	struct device_node *port;
++	int id, ret;
++
++	port = of_get_child_by_name(parent, "port");
++	while (port) {
++		ret = of_property_read_u32(port, "reg", &id);
++		if (!ret && id == port_id)
++			return port;
++
++		do {
++			port = of_get_next_child(parent, port);
++			if (!port)
++				return NULL;
++		} while (of_node_cmp(port->name, "port"));
++	}
++
++	return NULL;
++}
++
+ static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
+ {
+ 	struct ipu_client_platformdata *pdata = dev->platform_data;
+@@ -441,16 +461,29 @@ static const struct component_ops ipu_crtc_ops = {
+ 
+ static int ipu_drm_probe(struct platform_device *pdev)
+ {
++	struct device *dev = &pdev->dev;
++	struct ipu_client_platformdata *pdata = dev->platform_data;
+ 	int ret;
+ 
+-	if (!pdev->dev.platform_data)
++	if (!dev->platform_data)
+ 		return -EINVAL;
+ 
+-	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
++	if (!dev->of_node) {
++		/* Associate crtc device with the corresponding DI port node */
++		dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
++						      pdata->di + 2);
++		if (!dev->of_node) {
++			dev_err(dev, "missing port@%d node in %s\n",
++				pdata->di + 2, dev->parent->of_node->full_name);
++			return -ENODEV;
++		}
++	}
++
++	ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
+ 	if (ret)
+ 		return ret;
+ 
+-	return component_add(&pdev->dev, &ipu_crtc_ops);
++	return component_add(dev, &ipu_crtc_ops);
+ }
+ 
+ static int ipu_drm_remove(struct platform_device *pdev)
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0004-staging-imx-drm-Document-updated-imx-drm-device-tree.patch b/patches/imx_drm_dts/0004-staging-imx-drm-Document-updated-imx-drm-device-tree.patch
new file mode 100644
index 0000000000000000000000000000000000000000..4350639710c68a40681d700a5e44c96cfb73cefe
--- /dev/null
+++ b/patches/imx_drm_dts/0004-staging-imx-drm-Document-updated-imx-drm-device-tree.patch
@@ -0,0 +1,166 @@
+From 7dbc884962d7b3046c6781fe5399825c6419a7aa Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:05 +0100
+Subject: [PATCH 4/9] staging: imx-drm: Document updated imx-drm device tree
+ bindings
+
+This patch updates the device tree binding documentation for i.MX IPU/display
+nodes using the OF graph bindings documented in
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ .../bindings/staging/imx-drm/fsl-imx-drm.txt       | 48 +++++++++++++++++++---
+ .../devicetree/bindings/staging/imx-drm/ldb.txt    | 20 +++++++--
+ 2 files changed, 59 insertions(+), 9 deletions(-)
+
+diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+index b876d49..bfa19a4 100644
+--- a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
++++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt
+@@ -1,3 +1,22 @@
++Freescale i.MX DRM master device
++================================
++
++The freescale i.MX DRM master device is a virtual device needed to list all
++IPU or other display interface nodes that comprise the graphics subsystem.
++
++Required properties:
++- compatible: Should be "fsl,imx-drm"
++- ports: Should contain a list of phandles pointing to display interface ports
++  of IPU devices
++
++example:
++
++imx-drm {
++	compatible = "fsl,imx-drm";
++	ports = <&ipu_di0>;
++};
++
++
+ Freescale i.MX IPUv3
+ ====================
+ 
+@@ -7,18 +26,31 @@ Required properties:
+   datasheet
+ - interrupts: Should contain sync interrupt and error interrupt,
+   in this order.
+-- #crtc-cells: 1, See below
+ - resets: phandle pointing to the system reset controller and
+           reset line index, see reset/fsl,imx-src.txt for details
++Optional properties:
++- port@[0-3]: Port nodes with endpoint definitions as defined in
++  Documentation/devicetree/bindings/media/video-interfaces.txt.
++  Ports 0 and 1 should correspond to CSI0 and CSI1,
++  ports 2 and 3 should correspond to DI0 and DI1, respectively.
+ 
+ example:
+ 
+ ipu: ipu@18000000 {
+-	#crtc-cells = <1>;
++	#address-cells = <1>;
++	#size-cells = <0>;
+ 	compatible = "fsl,imx53-ipu";
+ 	reg = <0x18000000 0x080000000>;
+ 	interrupts = <11 10>;
+ 	resets = <&src 2>;
++
++	ipu_di0: port@2 {
++		reg = <2>;
++
++		ipu_di0_disp0: endpoint {
++			remote-endpoint = <&display_in>;
++		};
++	};
+ };
+ 
+ Parallel display support
+@@ -26,19 +58,25 @@ Parallel display support
+ 
+ Required properties:
+ - compatible: Should be "fsl,imx-parallel-display"
+-- crtc: the crtc this display is connected to, see below
+ Optional properties:
+ - interface_pix_fmt: How this display is connected to the
+-  crtc. Currently supported types: "rgb24", "rgb565", "bgr666"
++  display interface. Currently supported types: "rgb24", "rgb565", "bgr666"
+ - edid: verbatim EDID data block describing attached display.
+ - ddc: phandle describing the i2c bus handling the display data
+   channel
++- port: A port node with endpoint definitions as defined in
++  Documentation/devicetree/bindings/media/video-interfaces.txt.
+ 
+ example:
+ 
+ display@di0 {
+ 	compatible = "fsl,imx-parallel-display";
+ 	edid = [edid-data];
+-	crtc = <&ipu 0>;
+ 	interface-pix-fmt = "rgb24";
++
++	port {
++		display_in: endpoint {
++			remote-endpoint = <&ipu_di0_disp0>;
++		};
++	};
+ };
+diff --git a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
+index ed93778..578a1fc 100644
+--- a/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
++++ b/Documentation/devicetree/bindings/staging/imx-drm/ldb.txt
+@@ -50,12 +50,14 @@ have a look at Documentation/devicetree/bindings/video/display-timing.txt.
+ 
+ Required properties:
+  - reg : should be <0> or <1>
+- - crtcs : a list of phandles with index pointing to the IPU display interfaces
+-           that can be used as video source for this channel.
+  - fsl,data-mapping : should be "spwg" or "jeida"
+                       This describes how the color bits are laid out in the
+                       serialized LVDS signal.
+  - fsl,data-width : should be <18> or <24>
++ - port: A port node with endpoint definitions as defined in
++   Documentation/devicetree/bindings/media/video-interfaces.txt.
++   On i.MX6, there should be four ports (port@[0-3]) that correspond
++   to the four LVDS multiplexer inputs.
+ 
+ example:
+ 
+@@ -77,23 +79,33 @@ ldb: ldb@53fa8008 {
+ 
+ 	lvds-channel@0 {
+ 		reg = <0>;
+-		crtcs = <&ipu 0>;
+ 		fsl,data-mapping = "spwg";
+ 		fsl,data-width = <24>;
+ 
+ 		display-timings {
+ 			/* ... */
+ 		};
++
++		port {
++			lvds0_in: endpoint {
++				remote-endpoint = <&ipu_di0_lvds0>;
++			};
++		};
+ 	};
+ 
+ 	lvds-channel@1 {
+ 		reg = <1>;
+-		crtcs = <&ipu 1>;
+ 		fsl,data-mapping = "spwg";
+ 		fsl,data-width = <24>;
+ 
+ 		display-timings {
+ 			/* ... */
+ 		};
++
++		port {
++			lvds1_in: endpoint {
++				remote-endpoint = <&ipu_di1_lvds1>;
++			};
++		};
+ 	};
+ };
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0005-staging-imx-drm-Document-imx-hdmi-device-tree-bindin.patch b/patches/imx_drm_dts/0005-staging-imx-drm-Document-imx-hdmi-device-tree-bindin.patch
new file mode 100644
index 0000000000000000000000000000000000000000..05e7e110ae48ae69543ecc4d35a4e952ce8263aa
--- /dev/null
+++ b/patches/imx_drm_dts/0005-staging-imx-drm-Document-imx-hdmi-device-tree-bindin.patch
@@ -0,0 +1,76 @@
+From 4158c6de94991fa9f311dc7fae8f92f9c795b058 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:06 +0100
+Subject: [PATCH 5/9] staging: imx-drm: Document imx-hdmi device tree bindings
+
+This patch adds device tree binding documentation for the HDMI transmitter
+on i.MX6.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ .../devicetree/bindings/staging/imx-drm/hdmi.txt   | 53 ++++++++++++++++++++++
+ 1 file changed, 53 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
+
+diff --git a/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
+new file mode 100644
+index 0000000..7dcd673a
+--- /dev/null
++++ b/Documentation/devicetree/bindings/staging/imx-drm/hdmi.txt
+@@ -0,0 +1,53 @@
++Device-Tree bindings for HDMI Transmitter
++
++HDMI Transmitter
++================
++
++The LVDS Display Bridge device tree node contains up to two lvds-channel
++nodes describing each of the two LVDS encoder channels of the bridge.
++
++Required properties:
++ - #address-cells : should be <1>
++ - #size-cells : should be <0>
++ - compatible : should be "fsl,imx6q-hdmi" or "fsl,imx6dl-hdmi".
++ - gpr : should be <&gpr>.
++   The phandle points to the iomuxc-gpr region containing the HDMI
++   multiplexer control register.
++ - clocks, clock-names : phandles to the HDMI iahb and isrf clocks, as described
++   in Documentation/devicetree/bindings/clock/clock-bindings.txt and
++   Documentation/devicetree/bindings/clock/imx6q-clock.txt.
++ - port@[0-4]: Up to four port nodes with endpoint definitions as defined in
++   Documentation/devicetree/bindings/media/video-interfaces.txt,
++   corresponding to the four inputs to the HDMI multiplexer.
++
++example:
++
++	gpr: iomuxc-gpr@020e0000 {
++		/* ... */
++	};
++
++        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";
++
++                port@0 {
++                        reg = <0>;
++
++                        hdmi_mux_0: endpoint {
++                                remote-endpoint = <&ipu1_di0_hdmi>;
++                        };
++                };
++
++                port@1 {
++                        reg = <1>;
++
++                        hdmi_mux_1: endpoint {
++                                remote-endpoint = <&ipu1_di1_hdmi>;
++                        };
++                };
++        };
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0006-ARM-dts-imx51-Add-IPU-ports-and-endpoints-move-imx-d.patch b/patches/imx_drm_dts/0006-ARM-dts-imx51-Add-IPU-ports-and-endpoints-move-imx-d.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a609cc888c5462d4c43a50db6ec393fac12488de
--- /dev/null
+++ b/patches/imx_drm_dts/0006-ARM-dts-imx51-Add-IPU-ports-and-endpoints-move-imx-d.patch
@@ -0,0 +1,179 @@
+From 3403cbc58467086d9075614674aa5b0e6bcc1a0a Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:07 +0100
+Subject: [PATCH 6/9] ARM: dts: imx51: Add IPU ports and endpoints, move
+ imx-drm node to dtsi
+
+This patch connects IPU and and parallel display device tree
+nodes using the OF graph bindings described in
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+The IPU ports correspond to the two display interfaces. The
+order of endpoints in the ports is arbitrary.
+
+Since the imx-drm node now only needs to contain links to the
+display interfaces, it can be moved to the SoC dtsi level. At
+the board level, only connections between the display interface
+ports and panels have to be added.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ arch/arm/boot/dts/imx51-apf51dev.dts | 11 ++++++++++-
+ arch/arm/boot/dts/imx51-babbage.dts  | 28 ++++++++++++++++++++--------
+ arch/arm/boot/dts/imx51.dtsi         | 22 +++++++++++++++++++++-
+ 3 files changed, 51 insertions(+), 10 deletions(-)
+
+diff --git a/arch/arm/boot/dts/imx51-apf51dev.dts b/arch/arm/boot/dts/imx51-apf51dev.dts
+index c29cfa9..c5a9a24 100644
+--- a/arch/arm/boot/dts/imx51-apf51dev.dts
++++ b/arch/arm/boot/dts/imx51-apf51dev.dts
+@@ -18,7 +18,6 @@
+ 
+ 	display@di1 {
+ 		compatible = "fsl,imx-parallel-display";
+-		crtcs = <&ipu 0>;
+ 		interface-pix-fmt = "bgr666";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&pinctrl_ipu_disp1>;
+@@ -41,6 +40,12 @@
+ 				pixelclk-active = <0>;
+ 			};
+ 		};
++
++		port {
++			display_in: endpoint {
++				remote-endpoint = <&ipu_di0_disp0>;
++			};
++		};
+ 	};
+ 
+ 	gpio-keys {
+@@ -200,3 +205,7 @@
+ 		};
+ 	};
+ };
++
++&ipu_di0_disp0 {
++	remote-endpoint = <&display_in>;
++};
+diff --git a/arch/arm/boot/dts/imx51-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts
+index ebe6c1d..9e9deb2 100644
+--- a/arch/arm/boot/dts/imx51-babbage.dts
++++ b/arch/arm/boot/dts/imx51-babbage.dts
+@@ -23,7 +23,6 @@
+ 
+ 	display0: display@di0 {
+ 		compatible = "fsl,imx-parallel-display";
+-		crtcs = <&ipu 0>;
+ 		interface-pix-fmt = "rgb24";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&pinctrl_ipu_disp1>;
+@@ -41,11 +40,16 @@
+ 				vsync-len = <10>;
+ 			};
+ 		};
++
++		port {
++			display0_in: endpoint {
++				remote-endpoint = <&ipu_di0_disp0>;
++			};
++		};
+ 	};
+ 
+ 	display1: display@di1 {
+ 		compatible = "fsl,imx-parallel-display";
+-		crtcs = <&ipu 1>;
+ 		interface-pix-fmt = "rgb565";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&pinctrl_ipu_disp2>;
+@@ -68,6 +72,12 @@
+ 				pixelclk-active = <0>;
+ 			};
+ 		};
++
++		port {
++			display1_in: endpoint {
++				remote-endpoint = <&ipu_di1_disp1>;
++			};
++		};
+ 	};
+ 
+ 	gpio-keys {
+@@ -92,12 +102,6 @@
+ 		};
+ 	};
+ 
+-	imx-drm {
+-		compatible = "fsl,imx-drm";
+-		crtcs = <&ipu 0>, <&ipu 1>;
+-		connectors = <&display0>, <&display1>;
+-	};
+-
+ 	sound {
+ 		compatible = "fsl,imx51-babbage-sgtl5000",
+ 			     "fsl,imx-audio-sgtl5000";
+@@ -276,6 +280,14 @@
+ 	};
+ };
+ 
++&ipu_di0_disp0 {
++	remote-endpoint = <&display0_in>;
++};
++
++&ipu_di1_disp1 {
++	remote-endpoint = <&display1_in>;
++};
++
+ &ssi2 {
+ 	fsl,mode = "i2s-slave";
+ 	status = "okay";
+diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
+index e4b07d1..3528bb6 100644
+--- a/arch/arm/boot/dts/imx51.dtsi
++++ b/arch/arm/boot/dts/imx51.dtsi
+@@ -101,6 +101,11 @@
+ 		};
+ 	};
+ 
++	imx-drm {
++		compatible = "fsl,imx-drm";
++		ports = <&ipu_di0>, <&ipu_di1>;
++	};
++
+ 	soc {
+ 		#address-cells = <1>;
+ 		#size-cells = <1>;
+@@ -114,7 +119,8 @@
+ 		};
+ 
+ 		ipu: ipu@40000000 {
+-			#crtc-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
+ 			compatible = "fsl,imx51-ipu";
+ 			reg = <0x40000000 0x20000000>;
+ 			interrupts = <11 10>;
+@@ -123,6 +129,20 @@
+ 			         <&clks IMX5_CLK_IPU_DI1_GATE>;
+ 			clock-names = "bus", "di0", "di1";
+ 			resets = <&src 2>;
++
++			ipu_di0: port@2 {
++				reg = <2>;
++
++				ipu_di0_disp0: endpoint {
++				};
++			};
++
++			ipu_di1: port@3 {
++				reg = <3>;
++
++				ipu_di1_disp1: endpoint {
++				};
++			};
+ 		};
+ 
+ 		aips@70000000 { /* AIPS1 */
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0007-ARM-dts-imx53-Add-IPU-DI-ports-and-endpoints-move-im.patch b/patches/imx_drm_dts/0007-ARM-dts-imx53-Add-IPU-DI-ports-and-endpoints-move-im.patch
new file mode 100644
index 0000000000000000000000000000000000000000..2cba7d9350a015f70d1cd3831a82b435f2f7efa9
--- /dev/null
+++ b/patches/imx_drm_dts/0007-ARM-dts-imx53-Add-IPU-DI-ports-and-endpoints-move-im.patch
@@ -0,0 +1,274 @@
+From 8dcf3f81055176963a1a8c88be50c55db23a96f1 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:08 +0100
+Subject: [PATCH 7/9] ARM: dts: imx53: Add IPU DI ports and endpoints, move
+ imx-drm node to dtsi
+
+This patch connects IPU and display encoder (VGA, LVDS)
+device tree nodes, as well as parallel displays on the DISP0
+and DISP1 outputs, using the OF graph bindings described in
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+The IPU ports correspond to the two display interfaces. The
+order of endpoints in the ports is arbitrary.
+
+Since the imx-drm node now only needs to contain links to the
+display interfaces, it can be moved to the SoC dtsi level. At
+the board level, only connections between the display interface
+ports and encoders or panels have to be added.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ arch/arm/boot/dts/imx53-m53evk.dts      | 17 +++++----
+ arch/arm/boot/dts/imx53-mba53.dts       | 15 ++++----
+ arch/arm/boot/dts/imx53-qsb-common.dtsi | 17 +++++----
+ arch/arm/boot/dts/imx53.dtsi            | 64 ++++++++++++++++++++++++++++++---
+ 4 files changed, 89 insertions(+), 24 deletions(-)
+
+diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts
+index d939ba8..f6d3ac3 100644
+--- a/arch/arm/boot/dts/imx53-m53evk.dts
++++ b/arch/arm/boot/dts/imx53-m53evk.dts
+@@ -23,7 +23,6 @@
+ 	soc {
+ 		display1: display@di1 {
+ 			compatible = "fsl,imx-parallel-display";
+-			crtcs = <&ipu 1>;
+ 			interface-pix-fmt = "bgr666";
+ 			pinctrl-names = "default";
+ 			pinctrl-0 = <&pinctrl_ipu_disp1>;
+@@ -44,6 +43,12 @@
+ 				};
+ 			};
+ 		};
++
++		port {
++			display1_in: endpoint {
++				remote-endpoint = <&ipu_di1_disp1>;
++			};
++		};
+ 	};
+ 
+ 	backlight {
+@@ -54,12 +59,6 @@
+ 		power-supply = <&reg_backlight>;
+ 	};
+ 
+-	imx-drm {
+-		compatible = "fsl,imx-drm";
+-		crtcs = <&ipu 1>;
+-		connectors = <&display1>;
+-	};
+-
+ 	leds {
+ 		compatible = "gpio-leds";
+ 		pinctrl-names = "default";
+@@ -406,6 +405,10 @@
+ 	};
+ };
+ 
++&ipu_di1_disp1 {
++	remote-endpoint = <&display1_in>;
++};
++
+ &nfc {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&pinctrl_nand>;
+diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts
+index a398745..7cb4cac 100644
+--- a/arch/arm/boot/dts/imx53-mba53.dts
++++ b/arch/arm/boot/dts/imx53-mba53.dts
+@@ -30,15 +30,14 @@
+ 		compatible = "fsl,imx-parallel-display";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&pinctrl_disp1_1>;
+-		crtcs = <&ipu 1>;
+ 		interface-pix-fmt = "rgb24";
+ 		status = "disabled";
+-	};
+ 
+-	imx-drm {
+-		compatible = "fsl,imx-drm";
+-		crtcs = <&ipu 1>;
+-		connectors = <&disp1>, <&tve>;
++		port {
++			display1_in: endpoint {
++				remote-endpoint = <&ipu_di1_disp1>;
++			};
++		};
+ 	};
+ 
+ 	regulators {
+@@ -154,6 +153,10 @@
+ 	};
+ };
+ 
++&ipu_di1_disp1 {
++	remote-endpoint = <&display1_in>;
++};
++
+ &cspi {
+ 	status = "okay";
+ };
+diff --git a/arch/arm/boot/dts/imx53-qsb-common.dtsi b/arch/arm/boot/dts/imx53-qsb-common.dtsi
+index 50823d0..3f825a6 100644
+--- a/arch/arm/boot/dts/imx53-qsb-common.dtsi
++++ b/arch/arm/boot/dts/imx53-qsb-common.dtsi
+@@ -19,7 +19,6 @@
+ 
+ 	display0: display@di0 {
+ 		compatible = "fsl,imx-parallel-display";
+-		crtcs = <&ipu 0>;
+ 		interface-pix-fmt = "rgb565";
+ 		pinctrl-names = "default";
+ 		pinctrl-0 = <&pinctrl_ipu_disp0>;
+@@ -42,6 +41,12 @@
+ 				pixelclk-active = <0>;
+ 			};
+ 		};
++
++		port {
++			display0_in: endpoint {
++				remote-endpoint = <&ipu_di0_disp0>;
++			};
++		};
+ 	};
+ 
+ 	gpio-keys {
+@@ -68,12 +73,6 @@
+ 		};
+ 	};
+ 
+-	imx-drm {
+-		compatible = "fsl,imx-drm";
+-		crtcs = <&ipu 0>;
+-		connectors = <&display0>;
+-	};
+-
+ 	leds {
+ 		compatible = "gpio-leds";
+ 		pinctrl-names = "default";
+@@ -132,6 +131,10 @@
+ 	status = "okay";
+ };
+ 
++&ipu_di0_disp0 {
++	remote-endpoint = <&display0_in>;
++};
++
+ &ssi2 {
+ 	fsl,mode = "i2s-slave";
+ 	status = "okay";
+diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
+index 80615df..25c92a8 100644
+--- a/arch/arm/boot/dts/imx53.dtsi
++++ b/arch/arm/boot/dts/imx53.dtsi
+@@ -52,6 +52,11 @@
+ 		};
+ 	};
+ 
++	imx-drm {
++		compatible = "fsl,imx-drm";
++		ports = <&ipu_di0>, <&ipu_di1>;
++	};
++
+ 	tzic: tz-interrupt-controller@0fffc000 {
+ 		compatible = "fsl,imx53-tzic", "fsl,tzic";
+ 		interrupt-controller;
+@@ -103,7 +108,8 @@
+ 		};
+ 
+ 		ipu: ipu@18000000 {
+-			#crtc-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
+ 			compatible = "fsl,imx53-ipu";
+ 			reg = <0x18000000 0x080000000>;
+ 			interrupts = <11 10>;
+@@ -112,6 +118,41 @@
+ 			         <&clks IMX5_CLK_IPU_DI1_GATE>;
+ 			clock-names = "bus", "di0", "di1";
+ 			resets = <&src 2>;
++
++			ipu_di0: port@2 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <2>;
++
++				ipu_di0_disp0: endpoint@0 {
++					reg = <0>;
++				};
++
++				ipu_di0_lvds0: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&lvds0_in>;
++				};
++			};
++
++			ipu_di1: port@3 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <3>;
++
++				ipu_di1_disp1: endpoint@0 {
++					reg = <0>;
++				};
++
++				ipu_di1_lvds1: endpoint@1 {
++					reg = <1>;
++					remote-endpoint = <&lvds1_in>;
++				};
++
++				ipu_di1_tve: endpoint@2 {
++					reg = <2>;
++					remote-endpoint = <&tve_in>;
++				};
++			};
+ 		};
+ 
+ 		aips@50000000 { /* AIPS1 */
+@@ -374,14 +415,24 @@
+ 
+ 				lvds-channel@0 {
+ 					reg = <0>;
+-					crtcs = <&ipu 0>;
+ 					status = "disabled";
++
++					port {
++						lvds0_in: endpoint {
++							remote-endpoint = <&ipu_di0_lvds0>;
++						};
++					};
+ 				};
+ 
+ 				lvds-channel@1 {
+ 					reg = <1>;
+-					crtcs = <&ipu 1>;
+ 					status = "disabled";
++
++					port {
++						lvds1_in: endpoint {
++							remote-endpoint = <&ipu_di0_lvds0>;
++						};
++					};
+ 				};
+ 			};
+ 
+@@ -655,8 +706,13 @@
+ 				clocks = <&clks IMX5_CLK_TVE_GATE>,
+ 				         <&clks IMX5_CLK_IPU_DI1_SEL>;
+ 				clock-names = "tve", "di_sel";
+-				crtcs = <&ipu 1>;
+ 				status = "disabled";
++
++				port {
++					tve_in: endpoint {
++						remote-endpoint = <&ipu_di1_tve>;
++					};
++				};
+ 			};
+ 
+ 			vpu: vpu@63ff4000 {
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0008-ARM-dts-imx6qdl-Add-IPU-DI-ports-and-endpoints-move-.patch b/patches/imx_drm_dts/0008-ARM-dts-imx6qdl-Add-IPU-DI-ports-and-endpoints-move-.patch
new file mode 100644
index 0000000000000000000000000000000000000000..1b738eb071bb061bcdc8ea71cb685e7a9d33f30a
--- /dev/null
+++ b/patches/imx_drm_dts/0008-ARM-dts-imx6qdl-Add-IPU-DI-ports-and-endpoints-move-.patch
@@ -0,0 +1,446 @@
+From dd919820508a5d686ac6fbdff674af5f436dc168 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:09 +0100
+Subject: [PATCH 8/9] ARM: dts: imx6qdl: Add IPU DI ports and endpoints, move
+ imx-drm node to dtsi
+
+This patch connects IPU and display encoder (HDMI, LVDS, MIPI)
+device tree nodes, as well as parallel displays on the DISP0
+and DISP1 outputs, using the OF graph bindings described in
+Documentation/devicetree/bindings/media/video-interfaces.txt
+
+The IPU ports correspond to the two display interfaces. The
+order of endpoints in the ports is arbitrary.
+
+Each encoder with an associated input multiplexer has multiple
+input ports in the device tree. The order and reg property of
+the ports must correspond to the multiplexer input order.
+
+Since the imx-drm node now only needs to contain links to the
+display interfaces, it can be moved to the SoC dtsi level. At
+the board level, only connections between the display interface
+ports and encoders or panels have to be added.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ arch/arm/boot/dts/imx6dl.dtsi          |  22 +++---
+ arch/arm/boot/dts/imx6q-sabresd.dts    |   4 -
+ arch/arm/boot/dts/imx6q.dtsi           | 124 +++++++++++++++++++++++++++--
+ arch/arm/boot/dts/imx6qdl-sabresd.dtsi |   6 --
+ arch/arm/boot/dts/imx6qdl.dtsi         | 138 ++++++++++++++++++++++++++++++++-
+ 5 files changed, 263 insertions(+), 31 deletions(-)
+
+diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
+index 3ab8711..082b92d 100644
+--- a/arch/arm/boot/dts/imx6dl.dtsi
++++ b/arch/arm/boot/dts/imx6dl.dtsi
+@@ -91,6 +91,15 @@
+ 			};
+ 		};
+ 	};
++
++	imx-drm {
++		compatible = "fsl,imx-drm";
++		ports = <&ipu1_di0>, <&ipu1_di1>;
++	};
++};
++
++&hdmi {
++	compatible = "fsl,imx6dl-hdmi";
+ };
+ 
+ &ldb {
+@@ -100,17 +109,4 @@
+ 	clock-names = "di0_pll", "di1_pll",
+ 		      "di0_sel", "di1_sel",
+ 		      "di0", "di1";
+-
+-	lvds-channel@0 {
+-		crtcs = <&ipu1 0>, <&ipu1 1>;
+-	};
+-
+-	lvds-channel@1 {
+-		crtcs = <&ipu1 0>, <&ipu1 1>;
+-	};
+-};
+-
+-&hdmi {
+-	compatible = "fsl,imx6dl-hdmi";
+-	crtcs = <&ipu1 0>, <&ipu1 1>;
+ };
+diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts
+index 66f220a..9cbdfe7 100644
+--- a/arch/arm/boot/dts/imx6q-sabresd.dts
++++ b/arch/arm/boot/dts/imx6q-sabresd.dts
+@@ -20,10 +20,6 @@
+ 	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/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
+index 6bb1ce9..4e8580c 100644
+--- a/arch/arm/boot/dts/imx6q.dtsi
++++ b/arch/arm/boot/dts/imx6q.dtsi
+@@ -146,7 +146,8 @@
+ 		};
+ 
+ 		ipu2: ipu@02800000 {
+-			#crtc-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
+ 			compatible = "fsl,imx6q-ipu";
+ 			reg = <0x02800000 0x400000>;
+ 			interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
+@@ -154,6 +155,76 @@
+ 			clocks = <&clks 133>, <&clks 134>, <&clks 137>;
+ 			clock-names = "bus", "di0", "di1";
+ 			resets = <&src 4>;
++
++			ipu2_di0: port@2 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <2>;
++
++				ipu2_di0_disp0: endpoint@0 {
++				};
++
++				ipu2_di0_hdmi: endpoint@1 {
++					remote-endpoint = <&hdmi_mux_2>;
++				};
++
++				ipu2_di0_mipi: endpoint@2 {
++				};
++
++				ipu2_di0_lvds0: endpoint@3 {
++					remote-endpoint = <&lvds0_mux_2>;
++				};
++
++				ipu2_di0_lvds1: endpoint@4 {
++					remote-endpoint = <&lvds1_mux_2>;
++				};
++			};
++
++			ipu2_di1: port@3 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <3>;
++
++				ipu2_di1_hdmi: endpoint@1 {
++					remote-endpoint = <&hdmi_mux_3>;
++				};
++
++				ipu2_di1_mipi: endpoint@2 {
++				};
++
++				ipu2_di1_lvds0: endpoint@3 {
++					remote-endpoint = <&lvds0_mux_3>;
++				};
++
++				ipu2_di1_lvds1: endpoint@4 {
++					remote-endpoint = <&lvds1_mux_3>;
++				};
++			};
++		};
++	};
++
++	imx-drm {
++		compatible = "fsl,imx-drm";
++		ports = <&ipu1_di0>, <&ipu1_di1>, <&ipu2_di0>, <&ipu2_di1>;
++	};
++};
++
++&hdmi {
++	compatible = "fsl,imx6q-hdmi";
++
++	port@2 {
++		reg = <2>;
++
++		hdmi_mux_2: endpoint {
++			remote-endpoint = <&ipu2_di0_hdmi>;
++		};
++	};
++
++	port@3 {
++		reg = <3>;
++
++		hdmi_mux_3: endpoint {
++			remote-endpoint = <&ipu2_di1_hdmi>;
+ 		};
+ 	};
+ };
+@@ -167,15 +238,56 @@
+ 		      "di0", "di1";
+ 
+ 	lvds-channel@0 {
+-		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
++		port@2 {
++			reg = <2>;
++
++			lvds0_mux_2: endpoint {
++				remote-endpoint = <&ipu2_di0_lvds0>;
++			};
++		};
++
++		port@3 {
++			reg = <3>;
++
++			lvds0_mux_3: endpoint {
++				remote-endpoint = <&ipu2_di1_lvds0>;
++			};
++		};
+ 	};
+ 
+ 	lvds-channel@1 {
+-		crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
++		port@2 {
++			reg = <2>;
++
++			lvds1_mux_2: endpoint {
++				remote-endpoint = <&ipu2_di0_lvds1>;
++			};
++		};
++
++		port@3 {
++			reg = <3>;
++
++			lvds1_mux_3: endpoint {
++				remote-endpoint = <&ipu2_di1_lvds1>;
++			};
++		};
+ 	};
+ };
+ 
+-&hdmi {
+-	compatible = "fsl,imx6q-hdmi";
+-	crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>;
++&mipi_dsi {
++	port@2 {
++		reg = <2>;
++
++		mipi_mux_2: endpoint {
++			remote-endpoint = <&ipu2_di0_mipi>;
++		};
++	};
++
++	port@3 {
++		reg = <3>;
++
++		mipi_mux_3: endpoint {
++			remote-endpoint = <&ipu2_di1_mipi>;
++		};
++	};
+ };
+diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+index 04487cb..0d816d3 100644
+--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
++++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+@@ -79,12 +79,6 @@
+ 		};
+ 	};
+ 
+-	imx_drm: 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/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
+index a2d5c49..a6ae3b1 100644
+--- a/arch/arm/boot/dts/imx6qdl.dtsi
++++ b/arch/arm/boot/dts/imx6qdl.dtsi
+@@ -664,23 +664,87 @@
+ 				status = "disabled";
+ 
+ 				lvds-channel@0 {
++					#address-cells = <1>;
++					#size-cells = <0>;
+ 					reg = <0>;
+ 					status = "disabled";
++
++					port@0 {
++						reg = <0>;
++
++						lvds0_mux_0: endpoint {
++							remote-endpoint = <&ipu1_di0_lvds0>;
++						};
++					};
++
++					port@1 {
++						reg = <1>;
++
++						lvds0_mux_1: endpoint {
++							remote-endpoint = <&ipu1_di1_lvds0>;
++						};
++					};
++
++					port@4 {
++						lvds0: endpoint {
++						};
++					};
+ 				};
+ 
+ 				lvds-channel@1 {
++					#address-cells = <1>;
++					#size-cells = <0>;
+ 					reg = <1>;
+ 					status = "disabled";
++
++					port@0 {
++						reg = <0>;
++
++						lvds1_mux_0: endpoint {
++							remote-endpoint = <&ipu1_di0_lvds1>;
++						};
++					};
++
++					port@1 {
++						reg = <1>;
++
++						lvds1_mux_1: endpoint {
++							remote-endpoint = <&ipu1_di1_lvds1>;
++						};
++					};
++
++					port@4 {
++						lvds1: endpoint {
++						};
++					};
+ 				};
+ 			};
+ 
+ 			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 {
++					reg = <0>;
++
++					hdmi_mux_0: endpoint {
++						remote-endpoint = <&ipu1_di0_hdmi>;
++					};
++				};
++
++				port@1 {
++					reg = <1>;
++
++					hdmi_mux_1: endpoint {
++						remote-endpoint = <&ipu1_di1_hdmi>;
++					};
++				};
+ 			};
+ 
+ 			dcic1: dcic@020e4000 {
+@@ -899,8 +963,27 @@
+ 				reg = <0x021dc000 0x4000>;
+ 			};
+ 
+-			mipi@021e0000 { /* MIPI-DSI */
++			mipi_dsi: mipi@021e0000 {
++				#address-cells = <1>;
++				#size-cells = <0>;
+ 				reg = <0x021e0000 0x4000>;
++				status = "disabled";
++
++				port@0 {
++					reg = <0>;
++
++					mipi_mux_0: endpoint {
++						remote-endpoint = <&ipu1_di0_mipi>;
++					};
++				};
++
++				port@1 {
++					reg = <1>;
++
++					mipi_mux_1: endpoint {
++						remote-endpoint = <&ipu1_di1_mipi>;
++					};
++				};
+ 			};
+ 
+ 			vdoa@021e4000 {
+@@ -954,7 +1037,8 @@
+ 		};
+ 
+ 		ipu1: ipu@02400000 {
+-			#crtc-cells = <1>;
++			#address-cells = <1>;
++			#size-cells = <0>;
+ 			compatible = "fsl,imx6q-ipu";
+ 			reg = <0x02400000 0x400000>;
+ 			interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>,
+@@ -962,6 +1046,56 @@
+ 			clocks = <&clks 130>, <&clks 131>, <&clks 132>;
+ 			clock-names = "bus", "di0", "di1";
+ 			resets = <&src 2>;
++
++			ipu1_di0: port@2 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <2>;
++
++				ipu1_di0_disp0: endpoint@0 {
++				};
++
++				ipu1_di0_hdmi: endpoint@1 {
++					remote-endpoint = <&hdmi_mux_0>;
++				};
++
++				ipu1_di0_mipi: endpoint@2 {
++					remote-endpoint = <&mipi_mux_0>;
++				};
++
++				ipu1_di0_lvds0: endpoint@3 {
++					remote-endpoint = <&lvds0_mux_0>;
++				};
++
++				ipu1_di0_lvds1: endpoint@4 {
++					remote-endpoint = <&lvds1_mux_0>;
++				};
++			};
++
++			ipu1_di1: port@3 {
++				#address-cells = <1>;
++				#size-cells = <0>;
++				reg = <3>;
++
++				ipu1_di0_disp1: endpoint@0 {
++				};
++
++				ipu1_di1_hdmi: endpoint@1 {
++					remote-endpoint = <&hdmi_mux_1>;
++				};
++
++				ipu1_di1_mipi: endpoint@2 {
++					remote-endpoint = <&mipi_mux_1>;
++				};
++
++				ipu1_di1_lvds0: endpoint@3 {
++					remote-endpoint = <&lvds0_mux_1>;
++				};
++
++				ipu1_di1_lvds1: endpoint@4 {
++					remote-endpoint = <&lvds1_mux_1>;
++				};
++			};
+ 		};
+ 	};
+ };
+-- 
+1.8.5.3
+
diff --git a/patches/imx_drm_dts/0009-staging-imx-drm-Update-TODO.patch b/patches/imx_drm_dts/0009-staging-imx-drm-Update-TODO.patch
new file mode 100644
index 0000000000000000000000000000000000000000..0ed6b1e8fca32d5b4a8885f02c5094c780777c89
--- /dev/null
+++ b/patches/imx_drm_dts/0009-staging-imx-drm-Update-TODO.patch
@@ -0,0 +1,36 @@
+From e84d2b14bd682829b5960348d6ec35a9d1c99768 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <p.zabel@pengutronix.de>
+Date: Tue, 18 Feb 2014 12:36:10 +0100
+Subject: [PATCH 9/9] staging: imx-drm: Update TODO
+
+The device tree bindings are updated regardless of the common display
+framework and in the meantime the HDMI driver was included.
+
+Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
+---
+ drivers/staging/imx-drm/TODO | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO
+index 6a9da94..29636fb 100644
+--- a/drivers/staging/imx-drm/TODO
++++ b/drivers/staging/imx-drm/TODO
+@@ -1,15 +1,10 @@
+ TODO:
+ - get DRM Maintainer review for this code
+-- Wait for common display framework to hit mainline and update the IPU
+-  driver to use it. This will most probably make changes to the devicetree
+-  bindings necessary.
+-- Factor out more code to common helper functions
+ - decide where to put the base driver. It is not specific to a subsystem
+   and would be used by DRM/KMS and media/V4L2
+ 
+ Missing features (not necessarily for moving out of staging):
+ 
+-- Add i.MX6 HDMI support
+ - Add support for IC (Image converter)
+ - Add support for CSI (CMOS Sensor interface)
+ - Add support for VDIC (Video Deinterlacer)
+-- 
+1.8.5.3
+
diff --git a/patches/imx_video_staging/0002-ARM-dts-imx6qdl-wandboard-Add-HDMI-support.patch b/patches/imx_video_staging/0002-ARM-dts-imx6qdl-wandboard-Add-HDMI-support.patch
index 4610d8ea8c59861bdcd181b49b1a24a63cf342a6..782acc374f8a7dd36fc3f9de34c840b98bafaf07 100644
--- a/patches/imx_video_staging/0002-ARM-dts-imx6qdl-wandboard-Add-HDMI-support.patch
+++ b/patches/imx_video_staging/0002-ARM-dts-imx6qdl-wandboard-Add-HDMI-support.patch
@@ -16,7 +16,7 @@ index abf0107..5e071c0 100644
  &i2c1 {
  	clock-frequency = <100000>;
  	pinctrl-names = "default";
--	pinctrl-0 = <&pinctrl_i2c1_1>;
+-	pinctrl-0 = <&pinctrl_i2c1>;
 +	pinctrl-0 = <&pinctrl_i2c1>;
 +	status = "okay";
 +};
diff --git a/version.sh b/version.sh
index 9c40794218f7ffe9c3e9309ebe58df2949021189..9509f7f094c3ab6f1ad3e4c42c010c202028c404 100644
--- a/version.sh
+++ b/version.sh
@@ -29,7 +29,7 @@ toolchain="gcc_linaro_gnueabihf_4_8"
 #Kernel/Build
 KERNEL_REL=3.14
 KERNEL_TAG=${KERNEL_REL}-rc3
-BUILD=armv7-devel-r64
+BUILD=armv7-devel-r65
 
 #v3.X-rcX + upto SHA
 KERNEL_SHA="e95003c3f9ccbfa7ab9d265e6eb703ee2fa4cfe7"