All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-04-13 15:53 weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 2/7] ARM i.MX5: Add IPU device support weitway at gmail.com
                   ` (6 more replies)
  0 siblings, 7 replies; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
features several units for image processing, this patch adds support
for the units needed for Framebuffer support, namely:

- Display Controller (dc)
- Display Interface (di)
- Display Multi Fifo Controller (dmfc)
- Display Processor (dp)
- Image DMA Controller (idmac)

This patch is based on the Freescale driver, but follows a different
approach. The Freescale code implements logical idmac channels and
the handling of the subunits is hidden in common idmac code pathes
in big switch/case statements. This patch instead just provides code
and resource management for the different subunits. The user, in this
case the framebuffer driver, decides how the different units play
together.

The IPU has other units missing in this patch:

- CMOS Sensor Interface (csi)
- Video Deinterlacer (vdi)
- Sensor Multi FIFO Controler (smfc)
- Image Converter (ic)
- Image Rotator (irt)

So expect more files to come in this directory.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 arch/arm/plat-mxc/include/mach/ipu-v3.h |   52 ++
 drivers/video/Kconfig                   |    2 +
 drivers/video/Makefile                  |    1 +
 drivers/video/imx-ipu-v3/Kconfig        |   10 +
 drivers/video/imx-ipu-v3/Makefile       |    3 +
 drivers/video/imx-ipu-v3/ipu-common.c   | 1257 +++++++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dc.c       |  442 +++++++++++
 drivers/video/imx-ipu-v3/ipu-di.c       |  572 ++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dmfc.c     |  376 +++++++++
 drivers/video/imx-ipu-v3/ipu-dp.c       |  507 +++++++++++++
 drivers/video/imx-ipu-v3/ipu-prv.h      |  288 +++++++
 include/video/imx-ipu-v3.h              |  226 ++++++
 12 files changed, 3736 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h
new file mode 100644
index 0000000..184dfe5
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef __MACH_IPU_V3_H_
+#define __MACH_IPU_V3_H_
+
+/* IPU specific extensions to struct fb_videomode flag field */
+#define FB_SYNC_OE_LOW_ACT	(1 << 8)
+#define FB_SYNC_CLK_LAT_FALL	(1 << 9)
+#define FB_SYNC_DATA_INVERT	(1 << 10)
+#define FB_SYNC_CLK_IDLE_EN	(1 << 11)
+#define FB_SYNC_SHARP_MODE	(1 << 12)
+#define FB_SYNC_SWAP_RGB	(1 << 13)
+
+struct ipuv3_fb_platform_data {
+	const struct fb_videomode	*modes;
+	int				num_modes;
+	char				*mode_str;
+	u32				interface_pix_fmt;
+
+#define IMX_IPU_FB_USE_MODEDB	(1 << 0)
+#define IMX_IPU_FB_USE_OVERLAY	(1 << 1)
+	unsigned long			flags;
+
+	int				ipu_channel_bg;
+	int				ipu_channel_fg;
+	int				dc_channel;
+	int				dp_channel;
+	int				display;
+
+	void				*ipu;
+};
+
+struct imx_ipuv3_platform_data {
+	int rev;
+	int (*init) (struct platform_device *);
+	struct ipuv3_fb_platform_data	*fb_head0_platform_data;
+	struct ipuv3_fb_platform_data	*fb_head1_platform_data;
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e0ea23f..9698c00 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
 
 source "drivers/gpu/stub/Kconfig"
 
+source "drivers/video/imx-ipu-v3/Kconfig"
+
 config VGASTATE
        tristate
        default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9a096ae..f6f15fd 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -154,6 +154,7 @@ obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 obj-$(CONFIG_FB_MXS)		  += mxsfb.o
+obj-$(CONFIG_FB_IMX_IPU_V3)	  += imx-ipu-v3/
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/imx-ipu-v3/Kconfig b/drivers/video/imx-ipu-v3/Kconfig
new file mode 100644
index 0000000..75aa483
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Kconfig
@@ -0,0 +1,10 @@
+
+config FB_IMX_IPU_V3
+	tristate "Support the Image Processing Unit (IPU) found on the i.MX5x"
+	depends on ARCH_MX51 || ARCH_MX53
+	select MFD_SUPPORT
+	select MFD_CORE
+	help
+	  Say yes here to support the IPU on i.MX5x. This is used by the fb
+	  driver and also by the i.MX5x camera support.
+
diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile
new file mode 100644
index 0000000..65b6153
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FB_IMX_IPU_V3) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c
new file mode 100644
index 0000000..082a5af
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-common.c
@@ -0,0 +1,1257 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <mach/common.h>
+#include <linux/mfd/core.h>
+#include <mach/ipu-v3.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+static inline struct ipu_soc *idmachannel2ipu(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu;
+	struct ipu_channel *base = channel - channel->num;
+
+	ipu = container_of(base, struct ipu_soc, channels[0]);
+
+	return ipu;
+}
+
+struct ipu_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+{
+	struct ipu_channel *channel;
+
+	dev_dbg(ipu->ipu_dev, "%s %d\n", __func__, num);
+
+	if (num > (IPU_IDMA_CHAN_NUM - 1))
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	channel = &ipu->channels[num];
+
+	if (channel->busy) {
+		channel = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	channel->busy = 1;
+	channel->num = num;
+
+out:
+	mutex_unlock(&ipu->ipu_channel_lock);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+
+	dev_dbg(ipu->ipu_dev, "%s %d\n", __func__, channel->num);
+
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	channel->busy = 0;
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_put);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel,
+			bool doublebuffer)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	if (doublebuffer)
+		reg |= idma_mask(channel->num);
+	else
+		reg &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+
+void ipu_idmac_select_buffer(struct ipu_channel *channel,
+			u32 buf_num)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	/* Mark buffer as ready. */
+	if (buf_num == 0)
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+	else
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 val;
+	unsigned long flags;
+
+	ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val |= idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	/* Disable DMA channel(s) */
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	/* Set channel buffers NOT to be ready */
+	ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+
+	if (ipu_idma_is_set(ipu, IPU_CHA_BUF0_RDY, channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF0_RDY(channel->num));
+	}
+	if (ipu_idma_is_set(ipu, IPU_CHA_BUF1_RDY, channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF1_RDY(channel->num));
+	}
+
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+	/* Reset the double buffer */
+	val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+
+#define __F(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_UBO		__F(0, 46, 22)
+#define IPU_FIELD_VBO		__F(0, 68, 22)
+#define IPU_FIELD_IOX		__F(0, 90, 4)
+#define IPU_FIELD_RDRW		__F(0, 94, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SLY		__F(1, 102, 14)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_SLUV		__F(1, 128, 14)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_SX		__F(0, 46, 12)
+#define IPU_FIELD_SY		__F(0, 58, 11)
+#define IPU_FIELD_NS		__F(0, 69, 10)
+#define IPU_FIELD_SDX		__F(0, 79, 7)
+#define IPU_FIELD_SM		__F(0, 86, 10)
+#define IPU_FIELD_SCC		__F(0, 96, 1)
+#define IPU_FIELD_SCE		__F(0, 97, 1)
+#define IPU_FIELD_SDY		__F(0, 98, 7)
+#define IPU_FIELD_SDRX		__F(0, 105, 1)
+#define IPU_FIELD_SDRY		__F(0, 106, 1)
+#define IPU_FIELD_BPP		__F(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	__F(0, 110, 2)
+#define IPU_FIELD_DIM		__F(0, 112, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SL		__F(1, 102, 14)
+#define IPU_FIELD_WID0		__F(1, 116, 3)
+#define IPU_FIELD_WID1		__F(1, 119, 3)
+#define IPU_FIELD_WID2		__F(1, 122, 3)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_OFS0		__F(1, 128, 5)
+#define IPU_FIELD_OFS1		__F(1, 133, 5)
+#define IPU_FIELD_OFS2		__F(1, 138, 5)
+#define IPU_FIELD_OFS3		__F(1, 143, 5)
+#define IPU_FIELD_SXYS		__F(1, 148, 1)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	__F(1, 150, 1)
+
+struct ipu_ch_param_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+static u32 ipu_bytes_per_pixel(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/* generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YUV422P:
+		return 1;
+
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		return 2;
+
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+		return 3;
+
+	case IPU_PIX_FMT_GENERIC_32:	/* generic data */
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+		return 4;
+
+	default:
+		return 1;
+	}
+}
+
+bool ipu_pixel_format_has_alpha(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+#define ipu_ch_param_addr(cpmem_base, ch) (((struct ipu_ch_param *)cpmem_base) + (ch))
+
+static inline void ipu_ch_param_set_field(struct ipu_ch_param *base, u32 wbs, u32 v)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	base->word[word].data[i] &= ~(mask << ofs);
+	base->word[word].data[i] |= v << ofs;
+
+	if ((bit + size - 1) / 32 > i) {
+		base->word[word].data[i + 1] &= ~(v >> (mask ? (32 - ofs) : 0));
+		base->word[word].data[i + 1] |= v >> (ofs ? (32 - ofs) : 0);
+	}
+}
+
+static inline u32 ipu_ch_param_read_field(struct ipu_ch_param *base, u32 wbs)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (base->word[word].data[i] >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = base->word[word].data[i + 1];
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+
+static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
+					      int red_width, int red_offset,
+					      int green_width, int green_offset,
+					      int blue_width, int blue_offset,
+					      int alpha_width, int alpha_offset)
+{
+	/* Setup red width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID0, red_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS0, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID1, green_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS1, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID2, blue_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS2, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID3, alpha_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS3, alpha_offset);
+}
+
+static inline void ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
+{
+	struct ipu_ch_param *p = ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch);
+	dev_dbg(ipu->ipu_dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+		 p->word[0].data[3], p->word[0].data[4]);
+	dev_dbg(ipu->ipu_dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+		 p->word[1].data[3], p->word[1].data[4]);
+	dev_dbg(ipu->ipu_dev, "PFS 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_PFS));
+	dev_dbg(ipu->ipu_dev, "BPP 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_BPP));
+	dev_dbg(ipu->ipu_dev, "NPB 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_NPB));
+
+	dev_dbg(ipu->ipu_dev, "FW %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FW));
+	dev_dbg(ipu->ipu_dev, "FH %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FH));
+	dev_dbg(ipu->ipu_dev, "Stride %d\n", ipu_ch_param_read_field(p, IPU_FIELD_SL));
+
+	dev_dbg(ipu->ipu_dev, "Width0 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID0));
+	dev_dbg(ipu->ipu_dev, "Width1 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID1));
+	dev_dbg(ipu->ipu_dev, "Width2 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID2));
+	dev_dbg(ipu->ipu_dev, "Width3 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID3));
+	dev_dbg(ipu->ipu_dev, "Offset0 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS0));
+	dev_dbg(ipu->ipu_dev, "Offset1 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS1));
+	dev_dbg(ipu->ipu_dev, "Offset2 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS2));
+	dev_dbg(ipu->ipu_dev, "Offset3 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS3));
+}
+
+static inline void ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
+						u32 ch, u16 burst_pixels)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_NPB,
+			       burst_pixels - 1);
+};
+
+static inline int ipu_ch_param_get_burst_size(struct ipu_soc *ipu, u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_NPB) + 1;
+};
+
+static inline int ipu_ch_param_get_bpp(struct ipu_soc *ipu, u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_BPP);
+};
+
+static inline void ipu_ch_param_set_buffer(struct ipu_soc *ipu, u32 ch, int bufNum,
+					    dma_addr_t phyaddr)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch),
+			bufNum ? IPU_FIELD_EBA1 : IPU_FIELD_EBA0,
+			phyaddr / 8);
+};
+
+#define IPU_FIELD_ROT_HF_VF		__F(0, 119, 3)
+
+static inline void ipu_ch_param_set_rotation(struct ipu_soc *ipu,
+				u32 ch, ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ROT_HF_VF, temp_rot);
+};
+
+static inline void ipu_ch_param_set_block_mode(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_BM, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
+		u32 ch, bool option)
+{
+	if (option)
+		ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALU, 1);
+	else
+		ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALU, 0);
+};
+
+static inline void ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_CRE, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, u32 ch)
+{
+	int alp_mem_idx;
+
+	switch (ch) {
+	case 14: /* PRP graphic */
+		alp_mem_idx = 0;
+		break;
+	case 15: /* PP graphic */
+		alp_mem_idx = 1;
+		break;
+	case 23: /* DP BG SYNC graphic */
+		alp_mem_idx = 4;
+		break;
+	case 27: /* DP FG SYNC graphic */
+		alp_mem_idx = 2;
+		break;
+	default:
+		dev_err(ipu->ipu_dev, "unsupported correlated channel of local alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALBM, alp_mem_idx);
+};
+
+static inline void ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, u32 ch)
+{
+	u32 stride;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SO, 1);
+	stride = ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SL) + 1;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ILO, stride / 8);
+	stride *= 2;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SLY, stride - 1);
+};
+
+static inline void ipu_ch_param_set_high_priority(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ID, 1);
+};
+
+static inline void ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, u32 ch, int alpha_width)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_WID3,
+			alpha_width - 1);
+}
+
+static int ipu_ch_param_init(struct ipu_soc *ipu,
+			int ch,
+			u32 pixel_fmt, u32 width,
+			u32 height, u32 stride,
+			u32 u, u32 v,
+			u32 uv_stride, dma_addr_t addr0,
+			dma_addr_t addr1)
+{
+	u32 u_offset = 0;
+	u32 v_offset = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_FW, width - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_FH, height - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_SLY, stride - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA0, addr0 >> 3);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA1, addr1 >> 3);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/* Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 63);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_32:
+		/* Represents 32-bit Generic data */
+		break;
+	case IPU_PIX_FMT_RGB565:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+		break;
+	case IPU_PIX_FMT_BGR24:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+		break;
+	case IPU_PIX_FMT_ABGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_UYVY:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0xA);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0x8);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);  /* burst size */
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = (v == 0) ? stride * height : v;
+		u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+		break;
+	case IPU_PIX_FMT_NV12:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 4);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		break;
+	default:
+		dev_err(ipu->ipu_dev, "mxc ipu: unimplemented pixel format: %d\n",
+			pixel_fmt);
+		return -EINVAL;
+	}
+	/* set burst size to 16 */
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, IPU_FIELD_SLUV, uv_stride - 1);
+
+	if (u > u_offset)
+		u_offset = u;
+
+	if (v > v_offset)
+		v_offset = v;
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_UBO, u_offset / 8);
+	ipu_ch_param_set_field(&params, IPU_FIELD_VBO, v_offset / 8);
+
+	dev_dbg(ipu->ipu_dev, "initializing idma ch %d @ %p\n",
+			ch, ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch));
+	memcpy(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), &params, sizeof(params));
+	return 0;
+}
+
+/*
+ * This function is called to initialize a buffer for a IPU channel.
+ *
+ * @param       channel         The IPU channel.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       rot_mode        Input parameter for rotation setting of buffer.
+ *                              A rotation setting other than
+ *                              IPU_ROTATE_VERT_FLIP
+ *                              should only be used for input buffers of
+ *                              rotation channels.
+ *
+ * @param       phyaddr_0       Input parameter buffer 0 physical address.
+ *
+ * @param       phyaddr_1       Input parameter buffer 1 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              double buffering mode.
+ *
+ * @param       u		private u offset for additional cropping,
+ *				zero if not used.
+ *
+ * @param       v		private v offset for additional cropping,
+ *				zero if not used.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u, u32 v, bool interlaced)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	int ret = 0;
+	u32 dma_chan = channel->num;
+
+	if (stride < width * ipu_bytes_per_pixel(pixel_fmt))
+		stride = width * ipu_bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu->ipu_dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+
+	ipu_get(ipu);
+
+	/* Build parameter memory data for DMA channel */
+	ret = ipu_ch_param_init(ipu, dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1);
+	if (ret)
+		goto out;
+
+	if (rot_mode)
+		ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
+
+	if (interlaced)
+		ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
+
+	if (idmac_idma_is_set(ipu, IDMAC_CHA_PRI, dma_chan))
+		ipu_ch_param_set_high_priority(ipu, dma_chan);
+
+	ipu_ch_param_dump(ipu, dma_chan);
+out:
+	ipu_put(ipu);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_init_channel_buffer);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 buf_num, dma_addr_t phyaddr)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 dma_chan = channel->num;
+
+	ipu_ch_param_set_buffer(ipu, dma_chan, buf_num, phyaddr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_update_channel_buffer);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu->ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	ipu_conf |= mask;
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, lock_flags);
+
+	return 0;
+}
+
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu->ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	ipu_conf &= ~mask;
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, lock_flags);
+
+	return 0;
+}
+
+
+/*
+ * should be called with ipu_lock.
+ */
+static void ipu_irq_update_irq_mask(struct ipu_soc *ipu)
+{
+	struct ipu_irq_handler *handler;
+	int i;
+
+	DECLARE_IPU_IRQ_BITMAP(irqs);
+
+	bitmap_zero(irqs, IPU_IRQ_COUNT);
+
+	list_for_each_entry(handler, &ipu->ipu_irq_handlers_list, list)
+		bitmap_or(irqs, irqs, handler->ipu_irqs, IPU_IRQ_COUNT);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++)
+		ipu_cm_write(ipu, irqs[i], IPU_INT_CTRL(i + 1));
+}
+
+int ipu_irq_add_handler(struct ipu_soc *ipu, struct ipu_irq_handler *ipuirq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	list_add_tail(&ipuirq->list, &ipu->ipu_irq_handlers_list);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irq_add_handler);
+
+void ipu_irq_remove_handler(struct ipu_soc *ipu, struct ipu_irq_handler *handler)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	list_del(&handler->list);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_irq_remove_handler);
+
+int ipu_irq_update_handler(struct ipu_soc *ipu,
+		struct ipu_irq_handler *handler,
+		unsigned long *bitmap)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	bitmap_copy(handler->ipu_irqs, bitmap, IPU_IRQ_COUNT);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irq_update_handler);
+
+static void ipu_completion_handler(unsigned long *bitmask, void *context)
+{
+	struct completion *completion = context;
+
+	complete(completion);
+}
+
+int ipu_wait_for_interrupt(struct ipu_soc *ipu, int interrupt, int timeout_ms)
+{
+	struct ipu_irq_handler handler;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long flags;
+	int ret;
+
+	bitmap_zero(handler.ipu_irqs, IPU_IRQ_COUNT);
+	bitmap_set(handler.ipu_irqs, interrupt, 1);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+	ipu_cm_write(ipu, 1 << (interrupt % 32), IPU_INT_STAT(interrupt / 32 + 1));
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	handler.handler = ipu_completion_handler;
+	handler.context = &completion;
+	ipu_irq_add_handler(ipu, &handler);
+
+	ret = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(timeout_ms));
+
+	ipu_irq_remove_handler(ipu, &handler);
+
+	return ret > 0 ? 0 : -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(ipu_wait_for_interrupt);
+
+static irqreturn_t ipu_irq_handler(int irq, void *desc)
+{
+	struct ipu_soc *ipu = container_of(desc, struct ipu_soc, ipu_dev);
+	DECLARE_IPU_IRQ_BITMAP(status);
+	struct ipu_irq_handler *handler;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++) {
+		status[i] = ipu_cm_read(ipu, IPU_INT_STAT(i + 1));
+		ipu_cm_write(ipu, status[i], IPU_INT_STAT(i + 1));
+	}
+
+	list_for_each_entry(handler, &ipu->ipu_irq_handlers_list, list) {
+		DECLARE_IPU_IRQ_BITMAP(tmp);
+		if (bitmap_and(tmp, status, handler->ipu_irqs, IPU_IRQ_COUNT))
+			handler->handler(tmp, handler->context);
+	}
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+ipu_color_space_t format_to_colorspace(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_LVDS666:
+	case IPU_PIX_FMT_LVDS888:
+		return RGB;
+
+	default:
+		return YCbCr;
+	}
+}
+
+static int ipu_reset(struct ipu_soc *ipu)
+{
+	int timeout = 1000;
+
+	ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+	while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+		if (!timeout--)
+			return -ETIME;
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int ipu_submodules_init(struct platform_device *pdev, unsigned long ipu_base)
+{
+	char *unit;
+	int ret;
+
+	ret = ipu_di_init(pdev, 0, ipu_base + IPU_DI0_REG_BASE,
+			IPU_CONF_DI0_EN);
+	if (ret) {
+		unit = "di0";
+		goto err_di_0;
+	}
+
+	ret = ipu_di_init(pdev, 1, ipu_base + IPU_DI1_REG_BASE,
+			IPU_CONF_DI1_EN);
+	if (ret) {
+		unit = "di1";
+		goto err_di_1;
+	}
+
+	ret = ipu_dc_init(pdev, ipu_base + IPU_DC_REG_BASE,
+			ipu_base + IPU_DC_TMPL_REG_BASE);
+	if (ret) {
+		unit = "dc_template";
+		goto err_dc;
+	}
+
+	ret = ipu_dmfc_init(pdev, ipu_base + IPU_DMFC_REG_BASE);
+	if (ret) {
+		unit = "dmfc";
+		goto err_dmfc;
+	}
+
+	ret = ipu_dp_init(pdev, ipu_base + IPU_SRM_REG_BASE);
+	if (ret) {
+		unit = "dp";
+		goto err_dp;
+	}
+
+	return 0;
+
+err_dp:
+	ipu_dmfc_exit(pdev);
+err_dmfc:
+	ipu_dc_exit(pdev);
+err_dc:
+	ipu_di_exit(pdev, 1);
+err_di_1:
+	ipu_di_exit(pdev, 0);
+err_di_0:
+	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+	return ret;
+}
+
+void ipu_get(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	ipu->ipu_use_count++;
+
+	if (ipu->ipu_use_count == 1)
+		clk_enable(ipu->ipu_clk);
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+
+void ipu_put(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	ipu->ipu_use_count--;
+
+	if (ipu->ipu_use_count == 0)
+		clk_disable(ipu->ipu_clk);
+
+	if (ipu->ipu_use_count < 0) {
+		dev_err(ipu->ipu_dev, "ipu use count < 0\n");
+		ipu->ipu_use_count = 0;
+	}
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+
+static void ipu_submodules_exit(struct platform_device *pdev,
+		unsigned long ipu_base)
+{
+	ipu_dp_exit(pdev);
+	ipu_dmfc_exit(pdev);
+	ipu_dc_exit(pdev);
+	ipu_di_exit(pdev, 1);
+	ipu_di_exit(pdev, 0);
+}
+
+static int ipu_add_subdevice_pdata(struct platform_device *pdev,
+		const char *name, int id, void *pdata, size_t pdata_size)
+{
+	struct mfd_cell cell = {
+		.platform_data = pdata,
+		.data_size = pdata_size,
+	};
+
+	cell.name = name;
+
+	return mfd_add_devices(&pdev->dev, id, &cell, 1, NULL, 0);
+}
+
+static int ipu_add_client_devices(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipuv3_fb_platform_data *fbdata;
+
+	fbdata = plat_data->fb_head0_platform_data;
+	if (fbdata) {
+		fbdata->ipu = (void *)ipu;
+		fbdata->ipu_channel_bg =
+			MX5_IPU_CHANNEL_MEM_BG_SYNC;
+		fbdata->ipu_channel_fg =
+			MX5_IPU_CHANNEL_MEM_FG_SYNC;
+		fbdata->dc_channel = 5;
+		fbdata->dp_channel = IPU_DP_FLOW_SYNC;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 0,
+				fbdata, sizeof(*fbdata));
+	}
+
+	fbdata = plat_data->fb_head1_platform_data;
+	if (fbdata) {
+		fbdata->ipu = (void *)ipu;
+		fbdata->ipu_channel_bg =
+			MX5_IPU_CHANNEL_MEM_DC_SYNC;
+		fbdata->ipu_channel_fg = -1;
+		fbdata->dc_channel = 1;
+		fbdata->dp_channel = -1;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 1,
+				fbdata, sizeof(*fbdata));
+	}
+
+	return 0;
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu;
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct resource *res;
+	int ret;
+
+	ipu = kzalloc(sizeof(struct ipu_soc), GFP_KERNEL);
+	if (!ipu)
+		return -ENOMEM;
+
+	spin_lock_init(&ipu->ipu_lock);
+	mutex_init(&ipu->ipu_channel_lock);
+	INIT_LIST_HEAD(&ipu->ipu_irq_handlers_list);
+
+	ipu->ipu_dev = &pdev->dev;
+
+	if (plat_data->init)
+		plat_data->init(pdev);
+
+	ipu->irq1 = platform_get_irq(pdev, 0);
+	ipu->irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || ipu->irq1 < 0 || ipu->irq2 < 0)
+		return -ENODEV;
+
+	ipu->ipu_base = res->start;
+
+	ipu->ipu_cm_reg = ioremap(ipu->ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_cm_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap1;
+	}
+
+	ipu->ipu_idmac_reg = ioremap(ipu->ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_idmac_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap2;
+	}
+
+	ipu->ipu_cpmem_reg = ioremap(ipu->ipu_base + IPU_CPMEM_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_cpmem_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap3;
+	}
+
+	ipu->ipu_clk = clk_get(&pdev->dev, "ipu");
+	if (IS_ERR(ipu->ipu_clk)) {
+		ret = PTR_ERR(ipu->ipu_clk);
+		dev_err(&pdev->dev, "clk_get failed with %d", ret);
+		goto failed_clk_get;
+	}
+
+	ipu_get(ipu);
+
+	ret = request_irq(ipu->irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", ipu->irq1, ret);
+		goto failed_request_irq1;
+	}
+
+	ret = request_irq(ipu->irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", ipu->irq2, ret);
+		goto failed_request_irq2;
+	}
+
+	platform_set_drvdata(pdev, ipu);
+
+	ipu_reset(ipu);
+
+	ret = ipu_submodules_init(pdev, ipu->ipu_base);
+	if (ret)
+		goto failed_submodules_init;
+
+	/* Set sync refresh channels as high priority */
+	ipu_idmac_write(ipu, 0x18800000, IDMAC_CHA_PRI(0));
+
+	ret = ipu_add_client_devices(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "adding client devices failed with %d\n", ret);
+		goto failed_add_clients;
+	}
+
+	ipu_put(ipu);
+
+	return 0;
+
+failed_add_clients:
+	ipu_submodules_exit(pdev, ipu->ipu_base);
+failed_submodules_init:
+	free_irq(ipu->irq2, &pdev->dev);
+failed_request_irq2:
+	free_irq(ipu->irq1, &pdev->dev);
+	ipu_put(ipu);
+failed_request_irq1:
+	clk_put(ipu->ipu_clk);
+failed_clk_get:
+	iounmap(ipu->ipu_cpmem_reg);
+failed_ioremap3:
+	iounmap(ipu->ipu_idmac_reg);
+failed_ioremap2:
+	iounmap(ipu->ipu_cm_reg);
+failed_ioremap1:
+	kfree(ipu);
+
+	return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	mfd_remove_devices(&pdev->dev);
+	ipu_submodules_exit(pdev, ipu->ipu_base);
+	free_irq(ipu->irq2, &pdev->dev);
+	free_irq(ipu->irq1, &pdev->dev);
+	iounmap(ipu->ipu_cpmem_reg);
+	iounmap(ipu->ipu_idmac_reg);
+	iounmap(ipu->ipu_cm_reg);
+
+	if (ipu->ipu_use_count != 0) {
+		dev_err(ipu->ipu_dev,
+			"unbalanced use count: %d\n", ipu->ipu_use_count);
+		clk_disable(ipu->ipu_clk);
+	}
+
+	clk_put(ipu->ipu_clk);
+
+	kfree(ipu);
+
+	return 0;
+}
+
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+		.name = "imx-ipuv3",
+	},
+	.probe = ipu_probe,
+	.remove = __devexit_p(ipu_remove),
+};
+
+static int __init ipu_gen_init(void)
+{
+	int32_t ret;
+
+	ret = platform_driver_register(&mxcipu_driver);
+	return 0;
+}
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+	platform_driver_unregister(&mxcipu_driver);
+}
+module_exit(ipu_gen_uninit);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c
new file mode 100644
index 0000000..21aadb0
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dc.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define ASYNC_SER_WAVE 6
+
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+#define DC_MAP_CONF_PTR(n)	(0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	(0x0144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+
+#define DC_WR_CH_CONF(ch)      (channel_offset[ch])
+#define DC_WR_CH_ADDR(ch)      (channel_offset[ch] + 4)
+#define DC_RL_CH(ch, evt)      (channel_offset[ch] + 8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN			(0x00D4)
+#define DC_DISP_CONF1(disp)	(0x00D8 + disp * 4)
+#define DC_DISP_CONF2(disp)	(0x00E8 + disp * 4)
+#define DC_STAT			(0x01C8)
+
+#define WROD(lf)		(0x18 | (lf << 1))
+
+#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_OFFSET		5
+#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID_OFFSET	3
+#define DC_WR_CH_CONF_PROG_DISP_ID_MASK		(3 << 3)
+
+static int channel_offset[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4};
+
+static inline struct ipu_soc *dcchannel2ipu(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu;
+	struct dc_channel *dc_base = dc_chan - dc_chan->num;
+
+	ipu = container_of(dc_base, struct ipu_soc, dc.dc_channels[0]);
+
+	return ipu;
+}
+
+static inline u32 ipu_dc_read(struct ipu_dc *dc, unsigned offset)
+{
+	return readl(dc->reg_base + offset);
+}
+
+static inline void ipu_dc_write(struct ipu_dc *dc, u32 value, unsigned offset)
+{
+	writel(value, dc->reg_base + offset);
+}
+
+static void ipu_dc_link_event(struct ipu_dc *dc, int chan, int event, int addr, int priority)
+{
+	u32 reg;
+
+	reg = ipu_dc_read(dc, DC_RL_CH(chan, event));
+	reg &= ~(0xFFFF << (16 * (event & 0x1)));
+	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+	ipu_dc_write(dc, reg, DC_RL_CH(chan, event));
+}
+
+static void ipu_dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, int map,
+			       int wave, int glue, int sync)
+{
+	u32 reg;
+	int stop = 1;
+
+	reg = sync;
+	reg |= (glue << 4);
+	reg |= (++wave << 11);
+	reg |= (++map << 15);
+	reg |= (operand << 20) & 0xFFF00000;
+	writel(reg, dc->tmpl_base + word * 8);
+
+	reg = (operand >> 12);
+	reg |= opcode << 4;
+	reg |= (stop << 9);
+	writel(reg, dc->tmpl_base + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_RGB24:
+		return 0;
+	case IPU_PIX_FMT_RGB666:
+		return 1;
+	case IPU_PIX_FMT_YUV444:
+		return 2;
+	case IPU_PIX_FMT_RGB565:
+		return 3;
+	case IPU_PIX_FMT_LVDS666:
+		return 4;
+	}
+
+	return -EINVAL;
+}
+
+#define SYNC_WAVE 0
+
+int ipu_dc_init_sync(struct dc_channel *dc_chan, int di,
+		bool interlaced, u32 pixel_fmt, u32 width)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg = 0, map;
+
+	map = ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu->ipu_dev, "IPU_DISP: No MAP\n");
+		return -EINVAL;
+	}
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	dc_chan->di = di;
+
+	if (interlaced) {
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 0, 3);
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 0, 2);
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 0, 1);
+
+		/* Init template microcode */
+		ipu_dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+	} else {
+		if (di) {
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 2, 3);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 3, 2);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 4, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		} else {
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 5, 3);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 6, 2);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 7, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		}
+	}
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NF, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NFIELD, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOF, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOFIELD, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_CHAN, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_ADDR, 0, 0);
+
+	reg = 0x2;
+	reg |= di << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	reg |= di << 2;
+	if (interlaced)
+		reg |= DC_WR_CH_CONF_FIELD_MODE;
+
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000000, DC_WR_CH_ADDR(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000084, DC_GEN);
+
+	ipu_dc_write(dc, width, DC_DISP_CONF2(di));
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+
+void ipu_dc_init_async(struct dc_channel *dc_chan, int di, bool interlaced)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg = 0;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	dc_chan->di = di;
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+	reg = 0x3;
+	reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000000, DC_WR_CH_ADDR(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000084, DC_GEN);
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_async);
+
+void ipu_dc_enable_channel(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	int di;
+	u32 reg;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	if (!dc->use_count)
+		ipu_module_enable(ipu, IPU_CONF_DC_EN);
+	dc->use_count++;
+
+	di = dc_chan->di;
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(6 - dc_chan->num));
+	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+		ipu_dc_write(dc, reg, DC_WR_CH_CONF(6 - dc_chan->num));
+	}
+
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(dc_chan->num));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	mutex_unlock(&dc->dc_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg;
+	int irq = 0, ret;
+
+	if (dc->use_count <= 0) {
+		dc->use_count = 0;
+		return;
+	}
+
+	if (dc_chan->num == 1) {
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (dc_chan->num == 5) {
+		irq = IPU_IRQ_DP_SF_END;
+	} else {
+		return;
+	}
+
+	ret = ipu_wait_for_interrupt(ipu, irq, 50);
+	if (ret)
+		return;
+
+	mutex_lock(&dc->dc_mutex);
+
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(dc_chan->num));
+	reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	dc->use_count--;
+	if (!dc->use_count)
+		ipu_module_disable(ipu, IPU_CONF_DC_EN);
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+
+struct dc_channel *ipu_dc_get(struct ipu_soc *ipu, int chan)
+{
+	struct dc_channel *dc_chan;
+
+	if (chan >= IPU_DC_CHAN_NUM)
+		return ERR_PTR(-EINVAL);
+
+	dc_chan = &ipu->dc.dc_channels[chan];
+
+	mutex_lock(&ipu->dc.dc_mutex);
+
+	if (dc_chan->inuse) {
+		dc_chan = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	dc_chan->inuse = true;
+out:
+	mutex_unlock(&ipu->dc.dc_mutex);
+
+	return dc_chan;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_get);
+
+void ipu_dc_put(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+
+	mutex_lock(&ipu->dc.dc_mutex);
+
+	dc_chan->inuse = false;
+
+	mutex_unlock(&ipu->dc.dc_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_put);
+
+static void ipu_dc_map_config(struct ipu_dc *dc, int map,
+		int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = ipu_dc_read(dc, DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xffff << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	ipu_dc_write(dc, reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = ipu_dc_read(dc, DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	ipu_dc_write(dc, reg, DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(struct ipu_dc *dc, int map)
+{
+	u32 reg = ipu_dc_read(dc, DC_MAP_CONF_PTR(map));
+	ipu_dc_write(dc, reg & ~(0xffff << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long reg_base, unsigned long template_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	int i;
+
+	ipu->dc.reg_base = ioremap(reg_base, PAGE_SIZE);
+	if (!ipu->dc.reg_base)
+		return -ENOMEM;
+
+	ipu->dc.tmpl_base = ioremap(template_base, PAGE_SIZE);
+	if (!ipu->dc.tmpl_base) {
+		iounmap(ipu->dc.reg_base);
+		return -ENOMEM;
+	}
+
+	mutex_init(&ipu->dc.dc_mutex);
+
+	for (i = 0; i < IPU_DC_CHAN_NUM; i++) {
+		ipu->dc.dc_channels[i].num = i;
+		ipu->dc.dc_channels[i].inuse = false;
+	}
+
+	/* IPU_PIX_FMT_RGB24 */
+	ipu_dc_map_clear(&ipu->dc, 0);
+	ipu_dc_map_config(&ipu->dc, 0, 0, 7, 0xff);
+	ipu_dc_map_config(&ipu->dc, 0, 1, 15, 0xff);
+	ipu_dc_map_config(&ipu->dc, 0, 2, 23, 0xff);
+
+	/* IPU_PIX_FMT_RGB666 */
+	ipu_dc_map_clear(&ipu->dc, 1);
+	ipu_dc_map_config(&ipu->dc, 1, 0, 5, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 1, 1, 11, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 1, 2, 17, 0xfc);
+
+	/* IPU_PIX_FMT_YUV444 */
+	ipu_dc_map_clear(&ipu->dc, 2);
+	ipu_dc_map_config(&ipu->dc, 2, 0, 15, 0xff);
+	ipu_dc_map_config(&ipu->dc, 2, 1, 23, 0xff);
+	ipu_dc_map_config(&ipu->dc, 2, 2, 7, 0xff);
+
+	/* IPU_PIX_FMT_RGB565 */
+	ipu_dc_map_clear(&ipu->dc, 3);
+	ipu_dc_map_config(&ipu->dc, 3, 0, 4, 0xf8);
+	ipu_dc_map_config(&ipu->dc, 3, 1, 10, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 3, 2, 15, 0xf8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	ipu_dc_map_clear(&ipu->dc, 4);
+	ipu_dc_map_config(&ipu->dc, 4, 0, 5, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 4, 1, 13, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 4, 2, 21, 0xfc);
+
+	return 0;
+}
+
+void ipu_dc_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	iounmap(ipu->dc.reg_base);
+	iounmap(ipu->dc.tmpl_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c
new file mode 100644
index 0000000..de8d0c0
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-di.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define SYNC_WAVE 0
+
+#define DC_DISP_ID_SYNC(di)	(di)
+
+struct di_sync_config {
+	int run_count;
+	int run_src;
+	int offset_count;
+	int offset_src;
+	int repeat_count;
+	int cnt_clr_src;
+	int cnt_polarity_gen_en;
+	int cnt_polarity_clr_src;
+	int cnt_polarity_trigger_src;
+	int cnt_up;
+	int cnt_down;
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = 0,
+	DI_SYNC_CLK = 1,
+	DI_SYNC_INT_HSYNC = 2,
+	DI_SYNC_HSYNC = 3,
+	DI_SYNC_VSYNC = 4,
+	DI_SYNC_DE = 6,
+};
+
+#define DI_GENERAL		0x0000
+#define DI_BS_CLKGEN0		0x0004
+#define DI_BS_CLKGEN1		0x0008
+#define DI_SW_GEN0(gen)		(0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		(0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN		0x0054
+#define DI_DW_GEN(gen)		(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	(0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF		0x015c
+#define DI_SSC			0x0160
+#define DI_POL			0x0164
+#define DI_AW0			0x0168
+#define DI_AW1			0x016c
+#define DI_SCR_CONF		0x0170
+#define DI_STAT			0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x)			((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x)			((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x)		((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x)		((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x)		((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x)		((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)	((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)		((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x)			((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x)			(x)
+#define DI_SW_GEN1_AUTO_RELOAD			(0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET		24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET		16
+
+#define DI_GEN_DI_CLK_EXT			(1 << 20)
+#define DI_GEN_POLARITY_1			(1 << 0)
+#define DI_GEN_POLARITY_2			(1 << 1)
+#define DI_GEN_POLARITY_3			(1 << 2)
+#define DI_GEN_POLARITY_4			(1 << 3)
+#define DI_GEN_POLARITY_5			(1 << 4)
+#define DI_GEN_POLARITY_6			(1 << 5)
+#define DI_GEN_POLARITY_7			(1 << 6)
+#define DI_GEN_POLARITY_8			(1 << 7)
+
+#define DI_POL_DRDY_DATA_POLARITY		(1 << 7)
+#define DI_POL_DRDY_POLARITY_15			(1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET			13
+
+#define DI0_COUNTER_RELEASE			(1 << 24)
+#define DI1_COUNTER_RELEASE			(1 << 25)
+
+static inline struct ipu_soc *di2ipu(struct ipu_di *di)
+{
+	struct ipu_soc *ipu;
+
+	if (0 == di->id)
+		ipu = container_of(di, struct ipu_soc, dis[0]);
+	else
+		ipu = container_of(di, struct ipu_soc, dis[1]);
+
+	return ipu;
+}
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+	return readl(di->reg_base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+	writel(value, di->reg_base + offset);
+}
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+				     int wave_gen,
+				     int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, int set,
+				    int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static int ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, int count)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct di_sync_config *c = &config[i];
+		int wave_gen = i + 1;
+
+		pr_debug("%s %d\n", __func__, wave_gen);
+		if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || (c->repeat_count >= 0x1000) ||
+			(c->cnt_up >= 0x400) || (c->cnt_down >= 0x400))
+			return -EINVAL;
+
+		reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+			DI_SW_GEN0_RUN_SRC(c->run_src) |
+			DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+			DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+		ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+		reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+			DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+			DI_SW_GEN1_CNT_POL_TRIGGER_SRC(c->cnt_polarity_trigger_src) |
+			DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+			DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+			DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+		if (c->repeat_count == 0) {
+			/* Enable auto reload */
+			reg |= DI_SW_GEN1_AUTO_RELOAD;
+		}
+
+		ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+		reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+		reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+		reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+		ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+	}
+	return 0;
+}
+
+static int ipu_di_sync_config_interlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width;
+	u32 reg;
+	int ret = 0;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total / 2 - 1,
+			.run_src = DI_SYNC_CLK,
+		}, {
+			.run_count = h_total - 11,
+			.run_src = DI_SYNC_CLK,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total * 2 - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = 1,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height / 2,
+			.cnt_clr_src = 4,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_HSYNC,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = 9,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = v_total / 2,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_clr_src = DI_SYNC_HSYNC,
+			.cnt_down = 4,
+		}
+	};
+
+	ret = ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+	if (ret < 0)
+		return ret;
+
+	/* set gentime select and tag sel */
+	reg = ipu_di_read(di, DI_SW_GEN1(9));
+	reg &= 0x1FFFFFFF;
+	reg |= (3 - 1) << 29 | 0x00008000;
+	ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+	ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+
+	return ret;
+}
+
+static int ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig, int div)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width + (sig->v_end_width < 2 ? 1 : 0);
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+		} , {
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+			.offset_count = div * sig->v_to_h_sync,
+			.offset_src = DI_SYNC_CLK,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_CLK,
+			.cnt_down = sig->h_sync_width * 2,
+		} , {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = sig->v_sync_width * 2,
+		} , {
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		} , {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		},
+	};
+
+	ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+	return ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, u32 pixel_clk, struct ipu_di_signal_cfg *sig)
+{
+	struct ipu_soc *ipu = di2ipu(di);
+	u32 reg;
+	u32 disp_gen, di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+	int ret = 0;
+	struct clk *di_clk;
+
+	dev_dbg(ipu->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;
+
+	mutex_lock(&di->di_mutex);
+
+	ipu_get(ipu);
+
+	/* Init clocking */
+	if (sig->ext_clk) {
+		di->external_clk = true;
+		di_clk = di->clk;
+	} else {
+		di->external_clk = false;
+		di_clk = ipu->ipu_clk;
+	}
+
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = (clk_get_rate(di_clk) * 16) / pixel_clk;
+	if (div < 0x10)	/* Min DI disp clock divider is 1 */
+		div = 0x10;
+
+	disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen &= di->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+	ipu_di_write(di, div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* Down time is half of period */
+	ipu_di_write(di, (div / 16) << 16, DI_BS_CLKGEN1);
+
+	ipu_di_data_wave_config(di, SYNC_WAVE, div / 16 - 1, div / 16 - 1);
+	ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div / 16 * 2);
+
+	div = div / 16;		/* Now divider is integer portion */
+
+	di_gen = 0;
+	if (sig->ext_clk)
+		di_gen |= DI_GEN_DI_CLK_EXT;
+
+	if (sig->interlaced) {
+		ret = ipu_di_sync_config_interlaced(di, sig);
+		if (ret < 0)
+			goto done;
+
+		/* set y_sel = 1 */
+		di_gen |= 0x10000000;
+		di_gen |= DI_GEN_POLARITY_5;
+		di_gen |= DI_GEN_POLARITY_8;
+
+		vsync_cnt = 7;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		ret = ipu_di_sync_config_noninterlaced(di, sig, div);
+		if (ret < 0)
+			goto done;
+
+		vsync_cnt = 3;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+	}
+
+	ipu_di_write(di, di_gen, DI_GENERAL);
+	ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+		     DI_SYNC_AS_GEN);
+
+	reg = ipu_di_read(di, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+	if (sig->enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig->data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+
+	ipu_di_write(di, reg, DI_POL);
+done:
+	ipu_put(ipu);
+
+	mutex_unlock(&di->di_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+	u32 reg;
+	struct ipu_soc *ipu = di2ipu(di);
+	unsigned long flags;
+
+	ipu_get(ipu);
+
+	ipu_module_enable(ipu, di->module);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+	if (di->id)
+		reg |= DI1_COUNTER_RELEASE;
+	else
+		reg |= DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	if (di->external_clk)
+		clk_enable(di->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+	u32 reg;
+	struct ipu_soc *ipu = di2ipu(di);
+	unsigned long flags;
+
+	if (di->external_clk)
+		clk_disable(di->clk);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+	if (di->id)
+		reg &= ~DI1_COUNTER_RELEASE;
+	else
+		reg &= ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	ipu_module_disable(ipu, di->module);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_disable);
+
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+{
+	struct ipu_di *di;
+
+	if (disp > 1)
+		return ERR_PTR(-EINVAL);
+
+	di = &ipu->dis[disp];
+
+	mutex_lock(&di->di_mutex);
+
+	if (!di->initialized) {
+		di = ERR_PTR(-ENOSYS);
+		goto out;
+	}
+
+	if (di->inuse) {
+		di = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	di->inuse = true;
+out:
+	mutex_unlock(&di->di_mutex);
+
+	return di;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+	mutex_lock(&di->di_mutex);
+
+	di->inuse = false;
+
+	mutex_unlock(&di->di_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_di_put);
+
+int ipu_di_init(struct platform_device *pdev, int id,
+		unsigned long reg_base, u32 module)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	char *clkid;
+
+	if (id > 1)
+		return -EINVAL;
+
+	if (id)
+		clkid = "di1";
+	else
+		clkid = "di0";
+
+	mutex_init(&ipu->dis[id].di_mutex);
+
+	ipu->dis[id].clk = clk_get(&pdev->dev, clkid);
+	ipu->dis[id].module = module;
+	ipu->dis[id].id = id;
+	ipu->dis[id].reg_base = ioremap(reg_base, PAGE_SIZE);
+	ipu->dis[id].initialized = true;
+	ipu->dis[id].inuse = false;
+	if (!ipu->dis[id].reg_base)
+		return -ENOMEM;
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+	return 0;
+}
+
+void ipu_di_exit(struct platform_device *pdev, int id)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	clk_put(ipu->dis[id].clk);
+	iounmap(ipu->dis[id].reg_base);
+	ipu->dis[id].initialized = false;
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c
new file mode 100644
index 0000000..230ddbf
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN		0x0000
+#define DMFC_WR_CHAN		0x0004
+#define DMFC_WR_CHAN_DEF	0x0008
+#define DMFC_DP_CHAN		0x000c
+#define DMFC_DP_CHAN_DEF	0x0010
+#define DMFC_GENERAL1		0x0014
+#define DMFC_GENERAL2		0x0018
+#define DMFC_IC_CTRL		0x001c
+#define DMFC_STAT		0x0020
+
+#define DMFC_WR_CHAN_1_28		0
+#define DMFC_WR_CHAN_2_41		8
+#define DMFC_WR_CHAN_1C_42		16
+#define DMFC_WR_CHAN_2C_43		24
+
+#define DMFC_DP_CHAN_5B_23		0
+#define DMFC_DP_CHAN_5F_27		8
+#define DMFC_DP_CHAN_6B_24		16
+#define DMFC_DP_CHAN_6F_29		24
+
+#define DMFC_FIFO_SIZE_64		(3 << 3)
+#define DMFC_FIFO_SIZE_128		(2 << 3)
+#define DMFC_FIFO_SIZE_256		(1 << 3)
+#define DMFC_FIFO_SIZE_512		(0 << 3)
+
+#define DMFC_SEGMENT(x)			((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_32		(0 << 6)
+#define DMFC_BURSTSIZE_16		(1 << 6)
+#define DMFC_BURSTSIZE_8		(2 << 6)
+#define DMFC_BURSTSIZE_4		(3 << 6)
+
+static struct dmfc_channel dmfcs[] = {
+	{
+		.ipu_channel	= 23,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5B_23,
+		.eot_shift	= 20,
+		.max_fifo_lines	= 3,
+	}, {
+		.ipu_channel	= 24,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6B_24,
+		.eot_shift	= 22,
+		.max_fifo_lines	= 1,
+	}, {
+		.ipu_channel	= 27,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5F_27,
+		.eot_shift	= 21,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 28,
+		.channel_reg	= DMFC_WR_CHAN,
+		.shift		= DMFC_WR_CHAN_1_28,
+		.eot_shift	= 16,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 29,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6F_29,
+		.eot_shift	= 23,
+		.max_fifo_lines	= 1,
+	},
+};
+
+#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcs)
+
+static inline struct ipu_soc *dmfcchannel2ipu(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu;
+	struct dmfc_channel *dmfc_base = dmfc - dmfc->idx;
+
+	ipu = container_of(dmfc_base, struct ipu_soc, dmfc.dmfcs[0]);
+
+	return ipu;
+}
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+
+	ipu_get(ipu);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (!ipu->dmfc.use_count)
+		ipu_module_enable(ipu, IPU_CONF_DMFC_EN);
+
+	ipu->dmfc.use_count++;
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	ipu->dmfc.use_count--;
+
+	if (!ipu->dmfc.use_count)
+		ipu_module_disable(ipu, IPU_CONF_DMFC_EN);
+
+	if (ipu->dmfc.use_count < 0)
+		ipu->dmfc.use_count = 0;
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, int segment)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	u32 val, field;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+			slots, segment, dmfc->ipu_channel);
+
+	if (!dmfc)
+		return -EINVAL;
+
+	switch (slots) {
+	case 1:
+		field = DMFC_FIFO_SIZE_64;
+		break;
+	case 2:
+		field = DMFC_FIFO_SIZE_128;
+		break;
+	case 4:
+		field = DMFC_FIFO_SIZE_256;
+		break;
+	case 8:
+		field = DMFC_FIFO_SIZE_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	field |= DMFC_SEGMENT(segment) | DMFC_BURSTSIZE_8;
+
+	val = readl(ipu->dmfc.reg_base + dmfc->channel_reg);
+
+	val &= ~(0xff << dmfc->shift);
+	val |= field << dmfc->shift;
+
+	writel(val, ipu->dmfc.reg_base + dmfc->channel_reg);
+
+	dmfc->slots = slots;
+	dmfc->segment = segment;
+	dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+	return 0;
+}
+
+static int dmfc_bandwidth_to_slots(unsigned long bandwidth,
+		unsigned long dmfc_bandwidth_per_slot)
+{
+	int slots = 1;
+
+	while (slots * dmfc_bandwidth_per_slot < bandwidth)
+		slots *= 2;
+
+	return slots;
+}
+
+static int dmfc_find_slots(struct ipu_soc *ipu, int slots)
+{
+	unsigned slotmask_need, slotmask_used = 0;
+	int i, segment = 0;
+
+	slotmask_need = (1 << slots) - 1;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		slotmask_used |= ipu->dmfc.dmfcs[i].slotmask;
+
+	while (slotmask_need <= 0xff) {
+		if (!(slotmask_used & slotmask_need))
+			return segment;
+
+		slotmask_need <<= 1;
+		segment++;
+	}
+
+	return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	int i;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: freeing %d slots starting from segment %d\n",
+			dmfc->slots, dmfc->segment);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (!dmfc->slots)
+		goto out;
+
+	dmfc->slotmask = 0;
+	dmfc->slots = 0;
+	dmfc->segment = 0;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		ipu->dmfc.dmfcs[i].slotmask = 0;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++) {
+		if (ipu->dmfc.dmfcs[i].slots > 0) {
+			ipu->dmfc.dmfcs[i].segment = dmfc_find_slots(ipu, ipu->dmfc.dmfcs[i].slots);
+			ipu->dmfc.dmfcs[i].slotmask =
+				((1 << ipu->dmfc.dmfcs[i].slots) - 1) << ipu->dmfc.dmfcs[i].segment;
+		}
+	}
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++) {
+		if (ipu->dmfc.dmfcs[i].slots > 0)
+			ipu_dmfc_setup_channel(&ipu->dmfc.dmfcs[i],
+				ipu->dmfc.dmfcs[i].slots, ipu->dmfc.dmfcs[i].segment);
+	}
+out:
+	mutex_unlock(&ipu->dmfc.mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_pixel_per_second)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	int slots = dmfc_bandwidth_to_slots(bandwidth_pixel_per_second,
+			ipu->dmfc.dmfc_bandwidth_per_slot);
+	int segment = 0, ret = 0;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+			bandwidth_pixel_per_second / 1000000, dmfc->ipu_channel);
+	ipu_get(ipu);
+
+	ipu_dmfc_free_bandwidth(dmfc);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (slots > 8) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	segment = dmfc_find_slots(ipu, slots);
+	if (segment < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ipu_dmfc_setup_channel(dmfc, slots, segment);
+
+out:
+	ipu_put(ipu);
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	u32 dmfc_gen1;
+
+	ipu_get(ipu);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	dmfc_gen1 = readl(ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	if ((dmfc->slots * 64 * 4) / width > dmfc->max_fifo_lines)
+		dmfc_gen1 |= 1 << dmfc->eot_shift;
+	else
+		dmfc_gen1 &= ~(1 << dmfc->eot_shift);
+
+	writel(dmfc_gen1, ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+{
+	int i;
+	struct ipu_dmfc *dmfc = &ipu->dmfc;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		if (dmfc->dmfcs[i].ipu_channel == ipu_channel)
+			return &dmfc->dmfcs[i];
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+	ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long reg_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	int i;
+
+	ipu->dmfc.reg_base = ioremap(reg_base, PAGE_SIZE);
+
+	if (!ipu->dmfc.reg_base)
+		return -ENOMEM;
+
+	writel(0x0, ipu->dmfc.reg_base + DMFC_WR_CHAN);
+	writel(0x0, ipu->dmfc.reg_base + DMFC_DP_CHAN);
+
+	ipu->dmfc.dmfc_num = DMFC_NUM_CHANNELS;
+	for (i = 0 ; i < ipu->dmfc.dmfc_num; i++) {
+		struct dmfc_channel *tmp = &(ipu->dmfc.dmfcs[i]);
+		memcpy(tmp, &dmfcs[i], sizeof(struct dmfc_channel));
+		tmp->idx = i;
+	}
+
+	mutex_init(&ipu->dmfc.mutex);
+
+	/*
+	 * We have a total bandwidth of clkrate * 4pixel divided
+	 * into 8 slots.
+	 */
+	ipu->dmfc.dmfc_bandwidth_per_slot = clk_get_rate(ipu->ipu_clk) / 4;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+			ipu->dmfc.dmfc_bandwidth_per_slot / 1000000);
+
+	writel(0x202020f6, ipu->dmfc.reg_base + DMFC_WR_CHAN_DEF);
+	writel(0x2020f6f6, ipu->dmfc.reg_base + DMFC_DP_CHAN_DEF);
+	writel(0x00000003, ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	return 0;
+}
+
+void ipu_dmfc_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	iounmap(ipu->dmfc.reg_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c
new file mode 100644
index 0000000..cbf6494
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dp.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF(flow)		(flow)
+#define DP_GRAPH_WIND_CTRL(flow)	(0x0004 + flow)
+#define DP_FG_POS(flow)			(0x0008 + flow)
+#define DP_CSC_A_0(flow)		(0x0044 + flow)
+#define DP_CSC_A_1(flow)		(0x0048 + flow)
+#define DP_CSC_A_2(flow)		(0x004C + flow)
+#define DP_CSC_A_3(flow)		(0x0050 + flow)
+#define DP_CSC_0(flow)			(0x0054 + flow)
+#define DP_CSC_1(flow)			(0x0058 + flow)
+
+#define DP_COM_CONF_FG_EN		(1 << 0)
+#define DP_COM_CONF_GWSEL		(1 << 1)
+#define DP_COM_CONF_GWAM		(1 << 2)
+#define DP_COM_CONF_GWCKE		(1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET	8
+#define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+/*     Y = R *  .299 + G *  .587 + B *  .114;
+       U = R * -.169 + G * -.332 + B *  .500 + 128.;
+       V = R *  .500 + G * -.419 + B * -.0813 + 128.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{ 153, 301, 58, },
+	{ -87, -170, 0x0100, },
+	{ 0x100, -215, -42, },
+	{ 0x0000, 0x0200, 0x0200, },	/* B0, B1, B2 */
+	{ 0x2, 0x2, 0x2, },	/* S0, S1, S2 */
+};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+	{ 0x095, 0x000, 0x0CC, },
+	{ 0x095, 0x3CE, 0x398, },
+	{ 0x095, 0x0FF, 0x000, },
+	{ 0x3E42, 0x010A, 0x3DD6, },	/*B0,B1,B2 */
+	{ 0x1, 0x1, 0x1, },	/*S0,S1,S2 */
+};
+
+static inline struct ipu_soc *dp2ipu(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu;
+
+	ipu = container_of(dp, struct ipu_soc, dp);
+
+	return ipu;
+}
+
+static inline u32 ipu_dp_read(struct ipu_dp *dp, unsigned offset)
+{
+	return readl(dp->reg_base + offset);
+}
+
+static inline void ipu_dp_write(struct ipu_dp *dp, u32 value, unsigned offset)
+{
+	writel(value, dp->reg_base + offset);
+}
+
+/* Please keep S0, S1 and S2 as 0x2 by using this conversion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+	int c;
+
+	c = red * rgb2ycbcr_coeff[n][0];
+	c += green * rgb2ycbcr_coeff[n][1];
+	c += blue * rgb2ycbcr_coeff[n][2];
+	c /= 16;
+	c += rgb2ycbcr_coeff[3][n] * 4;
+	c += 8;
+	c /= 16;
+	if (c < 0)
+		c = 0;
+	if (c > 255)
+		c = 255;
+	return c;
+}
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+/*
+ * Row is for BG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+	{
+		{ DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}
+};
+
+static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
+
+static int color_key_4rgb = 1;
+
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 color_key)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+	int y, u, v;
+	int red, green, blue;
+
+	mutex_lock(&dp->mutex);
+
+	color_key_4rgb = 1;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
+
+		dev_dbg(ipu->ipu_dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu->ipu_dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFF000000L;
+		ipu_dp_write(dp, reg | color_key, DP_GRAPH_WIND_CTRL(DP_SYNC));
+
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg | DP_COM_CONF_GWCKE, DP_COM_CONF(DP_SYNC));
+	} else {
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(DP_SYNC));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_color_key);
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, bool bg_chan)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	if (bg_chan)
+		reg &= ~DP_COM_CONF_GWSEL;
+	else
+		reg |= DP_COM_CONF_GWSEL;
+	ipu_dp_write(dp, reg, DP_COM_CONF(DP_SYNC));
+
+	if (enable) {
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0x00FFFFFFL;
+		ipu_dp_write(dp, reg | ((u32) alpha << 24), DP_GRAPH_WIND_CTRL(DP_SYNC));
+
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg | DP_COM_CONF_GWAM, DP_COM_CONF(DP_SYNC));
+	} else {
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(DP_SYNC));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	ipu_dp_write(dp, (x_pos << 16) | y_pos, DP_FG_POS(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+void __ipu_dp_csc_setup(struct ipu_dp *dp, int flow,
+			struct dp_csc_param_t dp_csc_param,
+			bool srm_mode_update)
+{
+	u32 reg;
+	struct ipu_soc *ipu = dp2ipu(dp);
+	const int (*coeff)[5][3];
+
+	if (dp_csc_param.mode >= 0) {
+		reg = ipu_dp_read(dp, DP_COM_CONF(flow));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		ipu_dp_write(dp, reg, DP_COM_CONF(flow));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		ipu_dp_write(dp, mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(flow));
+		ipu_dp_write(dp, mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+				(mask_b((*coeff)[3][2]) << 16) |
+				((*coeff)[4][2] << 30), DP_CSC_1(flow));
+	}
+
+	if (srm_mode_update) {
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	int in_fmt, out_fmt;
+	enum csc_type_t *csc_type;
+	u32 reg;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	if (bg)
+		csc_type = &bg_csc_type;
+	else
+		csc_type = &fg_csc_type;
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (in_fmt == RGB) {
+		if (out_fmt == RGB)
+			*csc_type = RGB2RGB;
+		else
+			*csc_type = RGB2YUV;
+	} else {
+		if (out_fmt == RGB)
+			*csc_type = YUV2RGB;
+		else
+			*csc_type = YUV2YUV;
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		u32 color_key = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFFFFFFL;
+
+		dev_dbg(ipu->ipu_dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFF000000L;
+		ipu_dp_write(dp, reg | color_key, DP_GRAPH_WIND_CTRL(DP_SYNC));
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu->ipu_dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(dp, DP_SYNC, dp_csc_array[bg_csc_type][fg_csc_type], true);
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	if (!dp->use_count)
+		ipu_module_enable(ipu, IPU_CONF_DP_EN);
+
+	dp->use_count++;
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+
+	mutex_lock(&dp->mutex);
+
+	dp->use_count--;
+
+	if (!dp->use_count)
+		ipu_module_disable(ipu, IPU_CONF_DP_EN);
+
+	if (dp->use_count < 0)
+		dp->use_count = 0;
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+
+void ipu_dp_enable_fg(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	/* Enable FG channel */
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	ipu_dp_write(dp, reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_fg);
+
+void ipu_dp_disable_fg(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg, csc;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_FG)
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+	reg &= ~DP_COM_CONF_FG_EN;
+	ipu_dp_write(dp, reg, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_fg);
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->dp.mutex);
+
+	if (ipu->dp.in_use)
+		return ERR_PTR(-EBUSY);
+
+	ipu->dp.in_use = true;
+
+	mutex_unlock(&ipu->dp.mutex);
+
+	return &ipu->dp;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+	mutex_lock(&dp->mutex);
+	dp->in_use = false;
+	mutex_unlock(&dp->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_put);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long reg_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	ipu->dp.reg_base = ioremap(reg_base, PAGE_SIZE);
+	if (!ipu->dp.reg_base)
+		return -ENOMEM;
+
+	mutex_init(&ipu->dp.mutex);
+
+	return 0;
+}
+
+void ipu_dp_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	iounmap(ipu->dp.reg_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h
new file mode 100644
index 0000000..f22bd7d
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-prv.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+
+#define MX5_IPU_CHANNEL_CSI0			 0
+#define MX5_IPU_CHANNEL_CSI1			 1
+#define MX5_IPU_CHANNEL_CSI2			 2
+#define MX5_IPU_CHANNEL_CSI3			 3
+#define MX5_IPU_CHANNEL_MEM_BG_SYNC		23
+#define MX5_IPU_CHANNEL_MEM_FG_SYNC		27
+#define MX5_IPU_CHANNEL_MEM_DC_SYNC		28
+#define MX5_IPU_CHANNEL_MEM_FG_SYNC_ALPHA	31
+#define MX5_IPU_CHANNEL_MEM_DC_ASYNC		41
+#define MX5_IPU_CHANNEL_ROT_ENC_MEM		45
+#define MX5_IPU_CHANNEL_ROT_VF_MEM		46
+#define MX5_IPU_CHANNEL_ROT_PP_MEM		47
+#define MX5_IPU_CHANNEL_ROT_ENC_MEM_OUT	48
+#define MX5_IPU_CHANNEL_ROT_VF_MEM_OUT		49
+#define MX5_IPU_CHANNEL_ROT_PP_MEM_OUT		50
+#define MX5_IPU_CHANNEL_MEM_BG_SYNC_ALPHA	51
+
+#define IPU_DISP0_BASE		0x00000000
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_DISP1_BASE		(IPU_MCU_T_DEFAULT << 25)
+#define IPU_CM_REG_BASE		0x1e000000
+#define IPU_IDMAC_REG_BASE	0x1e008000
+#define IPU_ISP_REG_BASE	0x1e010000
+#define IPU_DP_REG_BASE		0x1e018000
+#define IPU_IC_REG_BASE		0x1e020000
+#define IPU_IRT_REG_BASE	0x1e028000
+#define IPU_CSI0_REG_BASE	0x1e030000
+#define IPU_CSI1_REG_BASE	0x1e038000
+#define IPU_DI0_REG_BASE	0x1e040000
+#define IPU_DI1_REG_BASE	0x1e048000
+#define IPU_SMFC_REG_BASE	0x1e050000
+#define IPU_DC_REG_BASE		0x1e058000
+#define IPU_DMFC_REG_BASE	0x1e060000
+#define IPU_CPMEM_REG_BASE	0x1f000000
+#define IPU_LUT_REG_BASE	0x1f020000
+#define IPU_SRM_REG_BASE	0x1f040000
+#define IPU_TPM_REG_BASE	0x1f060000
+#define IPU_DC_TMPL_REG_BASE	0x1f080000
+#define IPU_ISP_TBPR_REG_BASE	0x1f0c0000
+#define IPU_VDI_REG_BASE	0x1e068000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)	(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00b8)
+#define IPU_SKIP			IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00d4)
+#define IPU_SNOOP			IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00dc)
+#define IPU_PM				IPU_CM_REG(0x00e0)
+#define IPU_GPR				IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT			IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT		IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_CTRL_IRQ(irq)	IPU_INT_CTRL(((irq) / 32))
+#define IPU_INT_STAT_IRQ(irq)	IPU_INT_STAT(((irq) / 32))
+#define IPU_INT_STAT(n)		IPU_CM_REG(0x0200 + 4 * ((n) - 1))
+
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)		IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA			IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA		IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)		IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)			IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1		IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2		IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0		IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1		IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2		IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch)		IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch)		IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+enum ipu_modules {
+	IPU_CONF_CSI0_EN		= (1 << 0),
+	IPU_CONF_CSI1_EN		= (1 << 1),
+	IPU_CONF_IC_EN			= (1 << 2),
+	IPU_CONF_ROT_EN			= (1 << 3),
+	IPU_CONF_ISP_EN			= (1 << 4),
+	IPU_CONF_DP_EN			= (1 << 5),
+	IPU_CONF_DI0_EN			= (1 << 6),
+	IPU_CONF_DI1_EN			= (1 << 7),
+	IPU_CONF_SMFC_EN		= (1 << 8),
+	IPU_CONF_DC_EN			= (1 << 9),
+	IPU_CONF_DMFC_EN		= (1 << 10),
+
+	IPU_CONF_VDI_EN			= (1 << 12),
+
+	IPU_CONF_IDMAC_DIS		= (1 << 22),
+
+	IPU_CONF_IC_DMFC_SEL		= (1 << 25),
+	IPU_CONF_IC_DMFC_SYNC		= (1 << 26),
+	IPU_CONF_VDI_DMFC_SYNC		= (1 << 27),
+
+	IPU_CONF_CSI0_DATA_SOURCE	= (1 << 28),
+	IPU_CONF_CSI1_DATA_SOURCE	= (1 << 29),
+	IPU_CONF_IC_INPUT		= (1 << 30),
+	IPU_CONF_CSI_SEL		= (1 << 31),
+};
+
+struct ipu_di {
+	int id;
+	u32 module;
+	struct clk *clk;
+	bool external_clk;
+	bool inuse;
+	bool initialized;
+	void __iomem *reg_base;
+	struct mutex di_mutex;
+};
+
+struct ipu_dc {
+#define IPU_DC_CHAN_NUM	10
+	struct dc_channel {
+		bool inuse;
+		unsigned int num;
+		unsigned int di; /* The display interface number assigned to this dc channel */
+	} dc_channels[IPU_DC_CHAN_NUM];
+	int use_count;
+	void __iomem *reg_base;
+	void __iomem *tmpl_base;
+	struct mutex dc_mutex;
+};
+
+struct dmfc_channel {
+	int		idx;
+	int		ipu_channel;
+	unsigned long	channel_reg;
+	unsigned long	shift;
+	unsigned	eot_shift;
+	unsigned	slots;
+	unsigned	max_fifo_lines;
+	unsigned	slotmask;
+	unsigned	segment;
+};
+
+struct ipu_dmfc {
+	int use_count;
+	void __iomem *reg_base;
+	unsigned long dmfc_bandwidth_per_slot;
+	struct mutex mutex;
+#define IPU_DMFC_CHAN_NUM	8
+	int dmfc_num;
+	struct dmfc_channel dmfcs[IPU_DMFC_CHAN_NUM];
+};
+
+struct ipu_dp {
+	int use_count;
+	void __iomem *reg_base;
+	struct mutex mutex;
+	bool in_use;
+};
+
+struct ipu_channel {
+	unsigned int num;
+
+	bool enabled;
+	bool busy;
+};
+
+struct ipu_soc {
+	struct device *ipu_dev;
+	struct clk *ipu_clk;
+	spinlock_t ipu_lock;
+	unsigned long ipu_base;
+	int irq1;
+	int irq2;
+
+	struct list_head ipu_irq_handlers_list;
+	int ipu_use_count;
+
+	void __iomem *ipu_cm_reg;
+	void __iomem *ipu_idmac_reg;
+	void __iomem *ipu_cpmem_reg;
+
+#define IPU_IDMA_CHAN_NUM	64
+	struct ipu_channel channels[IPU_IDMA_CHAN_NUM];
+	struct mutex ipu_channel_lock;
+
+	struct ipu_di dis[2];
+	struct ipu_dc dc;
+	struct ipu_dmfc dmfc;
+	struct ipu_dp dp;
+};
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ipu_cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ipu_cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ipu_idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ipu_idmac_reg + offset);
+}
+
+#define idmac_idma_is_set(ipu, reg, dma)(ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma))
+#define idma_mask(ch)			(1 << (ch & 0x1f))
+#define ipu_idma_is_set(ipu, reg, dma)	(ipu_cm_read(ipu, reg(dma)) & idma_mask(dma))
+
+ipu_color_space_t format_to_colorspace(u32 fmt);
+bool ipu_pixel_format_has_alpha(u32 fmt);
+
+u32 _ipu_channel_status(struct ipu_channel *channel);
+
+int _ipu_chan_is_interlaced(struct ipu_channel *channel);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+
+int ipu_di_init(struct platform_device *pdev, int id,
+		unsigned long base, u32 module);
+void ipu_di_exit(struct platform_device *pdev, int id);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base);
+void ipu_dmfc_exit(struct platform_device *pdev);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base);
+void ipu_dp_exit(struct platform_device *pdev);
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base,
+		unsigned long template_base);
+void ipu_dc_exit(struct platform_device *pdev);
+
+void ipu_get(struct ipu_soc *ipu);
+void ipu_put(struct ipu_soc *ipu);
+
+#endif				/* __IPU_PRV_H__ */
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
new file mode 100644
index 0000000..4928dba
--- /dev/null
+++ b/include/video/imx-ipu-v3.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+typedef enum {
+	/* Note the enum values correspond to BAM value */
+	IPU_ROTATE_NONE = 0,
+	IPU_ROTATE_VERT_FLIP = 1,
+	IPU_ROTATE_HORIZ_FLIP = 2,
+	IPU_ROTATE_180 = 3,
+	IPU_ROTATE_90_RIGHT = 4,
+	IPU_ROTATE_90_RIGHT_VFLIP = 5,
+	IPU_ROTATE_90_RIGHT_HFLIP = 6,
+	IPU_ROTATE_90_LEFT = 7,
+} ipu_rotate_mode_t;
+
+/*
+ * IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/* Generic or Raw Data Formats */
+#define IPU_PIX_FMT_GENERIC v4l2_fourcc('I', 'P', 'U', '0')	/* IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 v4l2_fourcc('I', 'P', 'U', '1')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 v4l2_fourcc('L', 'V', 'D', '6')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 v4l2_fourcc('L', 'V', 'D', '8')	/* IPU Generic Data */
+/* RGB Formats */
+#define IPU_PIX_FMT_RGB332  V4L2_PIX_FMT_RGB332			/*  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  V4L2_PIX_FMT_RGB555			/* 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  V4L2_PIX_FMT_RGB565			/* 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  v4l2_fourcc('R', 'G', 'B', '6')	/* 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', '6')	/* 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   V4L2_PIX_FMT_BGR24			/* 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   V4L2_PIX_FMT_RGB24			/* 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_BGR32   V4L2_PIX_FMT_BGR32			/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  v4l2_fourcc('B', 'G', 'R', 'A')	/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   V4L2_PIX_FMT_RGB32			/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  v4l2_fourcc('R', 'G', 'B', 'A')	/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  v4l2_fourcc('A', 'B', 'G', 'R')	/* 32  ABGR-8-8-8-8 */
+/* YUV Interleaved Formats */
+#define IPU_PIX_FMT_YUYV    V4L2_PIX_FMT_YUYV			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    V4L2_PIX_FMT_UYVY			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_Y41P    V4L2_PIX_FMT_Y41P			/* 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  V4L2_PIX_FMT_YUV444			/* 24 YUV 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    V4L2_PIX_FMT_NV12			/* 12  Y/CbCr 4:2:0  */
+/* YUV Planar Formats */
+#define IPU_PIX_FMT_GREY    V4L2_PIX_FMT_GREY			/* 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P V4L2_PIX_FMT_YVU410P		/* 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P V4L2_PIX_FMT_YUV410P		/* 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P v4l2_fourcc('Y', 'V', '1', '2')	/* 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P v4l2_fourcc('I', '4', '2', '0')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 v4l2_fourcc('Y', 'U', '1', '2')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P v4l2_fourcc('Y', 'V', '1', '6')	/* 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P V4L2_PIX_FMT_YUV422P		/* 16 YUV 4:2:2 */
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+	unsigned datamask_en:1;
+	unsigned ext_clk:1;
+	unsigned interlaced:1;
+	unsigned odd_field_first:1;
+	unsigned clksel_en:1;
+	unsigned clkidle_en:1;
+	unsigned data_pol:1;	/* true = inverted */
+	unsigned clk_pol:1;	/* true = rising edge */
+	unsigned enable_pol:1;
+	unsigned Hsync_pol:1;	/* true = active high */
+	unsigned Vsync_pol:1;
+
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u16 h_start_width;
+	u16 h_sync_width;
+	u16 h_end_width;
+	u16 v_start_width;
+	u16 v_sync_width;
+	u16 v_end_width;
+	u32 v_to_h_sync;
+};
+
+typedef enum {
+	RGB,
+	YCbCr,
+	YUV
+} ipu_color_space_t;
+
+#define IPU_IRQ_EOF(channel)		(channel)		/* 0 .. 63 */
+#define IPU_IRQ_NFACK(channel)		((channel) + 64)	/* 64 .. 127 */
+#define IPU_IRQ_NFB4EOF(channel)	((channel) + 128)	/* 128 .. 191 */
+#define IPU_IRQ_EOS(channel)		((channel) + 192)	/* 192 .. 255 */
+
+#define IPU_IRQ_DP_SF_START		(448 + 2)
+#define IPU_IRQ_DP_SF_END		(448 + 3)
+#define IPU_IRQ_BG_SF_END		IPU_IRQ_DP_SF_END
+#define IPU_IRQ_DC_FC_0			(448 + 8)
+#define IPU_IRQ_DC_FC_1			(448 + 9)
+#define IPU_IRQ_DC_FC_2			(448 + 10)
+#define IPU_IRQ_DC_FC_3			(448 + 11)
+#define IPU_IRQ_DC_FC_4			(448 + 12)
+#define IPU_IRQ_DC_FC_6			(448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0		(448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
+
+#define IPU_IRQ_COUNT	(15 * 32)
+
+#define DECLARE_IPU_IRQ_BITMAP(name)	DECLARE_BITMAP(name, IPU_IRQ_COUNT)
+
+struct ipu_irq_handler {
+	struct list_head	list;
+	void			(*handler)(unsigned long *, void *);
+	void			*context;
+	DECLARE_IPU_IRQ_BITMAP(ipu_irqs);
+};
+
+struct ipu_soc;
+
+int ipu_irq_add_handler(struct ipu_soc *ipu, struct ipu_irq_handler *ipuirq);
+void ipu_irq_remove_handler(struct ipu_soc *ipu, struct ipu_irq_handler *handler);
+int ipu_irq_update_handler(struct ipu_soc *ipu,
+		struct ipu_irq_handler *handler,
+		unsigned long *bitmap);
+int ipu_wait_for_interrupt(struct ipu_soc *ipu, int interrupt, int timeout_ms);
+
+struct ipu_channel;
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipu_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num);
+void ipu_idmac_put(struct ipu_channel *);
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u_offset, u32 v_offset, bool interlaced);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 bufNum, dma_addr_t phyaddr);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel);
+int ipu_idmac_disable_channel(struct ipu_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+struct dc_channel;
+struct dc_channel *ipu_dc_get(struct ipu_soc *ipu, int chan);
+void ipu_dc_put(struct dc_channel *dc_chan);
+int ipu_dc_init_sync(struct dc_channel *dc_chan, int di,
+		bool interlaced, u32 pixel_fmt, u32 width);
+void ipu_dc_init_async(struct dc_channel *dc_chan, int di, bool interlaced);
+void ipu_dc_enable_channel(struct dc_channel *dc_chan);
+void ipu_dc_disable_channel(struct dc_channel *dc_chan);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di;
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp);
+void ipu_di_put(struct ipu_di *di);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, u32 pixel_clk,
+		struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, unsigned long bandwidth_mbs);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC	0
+#define IPU_DP_FLOW_ASYNC0	1
+#define IPU_DP_FLOW_ASYNC1	2
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+void ipu_dp_enable_fg(struct ipu_dp *dp);
+void ipu_dp_disable_fg(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 colorKey);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+		bool bg_chan);
+
+#endif
-- 
1.7.1

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

* [PATCH 2/7] ARM i.MX5: Add IPU device support
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-14  9:25   ` Sascha Hauer
  2011-04-13 15:53 ` [PATCH 3/7] Add i.MX5 framebuffer driver weitway at gmail.com
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 arch/arm/mach-mx5/devices-imx51.h               |    4 +
 arch/arm/mach-mx5/devices-imx53.h               |    4 +
 arch/arm/plat-mxc/devices/Kconfig               |    4 +
 arch/arm/plat-mxc/devices/Makefile              |    1 +
 arch/arm/plat-mxc/devices/platform-imx_ipuv3.c  |   94 +++++++++++++++++++++++
 arch/arm/plat-mxc/include/mach/devices-common.h |   12 +++
 6 files changed, 119 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h
index 7fff485..1bd73b3 100644
--- a/arch/arm/mach-mx5/devices-imx51.h
+++ b/arch/arm/mach-mx5/devices-imx51.h
@@ -55,3 +55,7 @@ extern const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst;
 extern const struct imx_imx_keypad_data imx51_imx_keypad_data __initconst;
 #define imx51_add_imx_keypad(pdata)	\
 	imx_add_imx_keypad(&imx51_imx_keypad_data, pdata)
+
+extern const struct imx_ipuv3_data imx51_ipuv3_data __initconst;
+#define imx51_add_ipuv3(pdata)	\
+	imx_add_ipuv3(&imx51_ipuv3_data, pdata)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index 9251008..8049039 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -33,3 +33,7 @@ extern const struct imx_spi_imx_data imx53_ecspi_data[] __initconst;
 extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[] __initconst;
 #define imx53_add_imx2_wdt(id, pdata)	\
 	imx_add_imx2_wdt(&imx53_imx2_wdt_data[id])
+
+extern const struct imx_ipuv3_data imx53_ipuv3_data __initconst;
+#define imx53_add_ipuv3(pdata)	\
+	imx_add_ipuv3(&imx53_ipuv3_data, pdata)
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index b9ab1d5..f99317e 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -71,3 +71,7 @@ config IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
 
 config IMX_HAVE_PLATFORM_SPI_IMX
 	bool
+
+config IMX_HAVE_PLATFORM_IMX_IPUV3
+	bool
+
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index 75cd2ec..0a6be0a 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_RNGA) += platform-mxc_rnga.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_W1) += platform-mxc_w1.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX) += platform-sdhci-esdhc-imx.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_SPI_IMX) +=  platform-spi_imx.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_IPUV3) +=  platform-imx_ipuv3.o
diff --git a/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
new file mode 100644
index 0000000..fe76cf1
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Pengutronix
+ * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
+ *
+ * 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.
+ */
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+
+#define imx5_ipuv3_data_entry_single(soc, size, ipu_init)	        \
+	{                                                               \
+		.iobase = soc ## _IPU_CTRL_BASE_ADDR,                   \
+		.irq_err = soc ## _INT_IPU_ERR,                         \
+		.irq = soc ## _INT_IPU_SYN,                             \
+		.iosize = size,                                         \
+		.init = ipu_init,                                       \
+	}
+
+#ifdef CONFIG_SOC_IMX51
+int __init mx51_ipuv3_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	u32 val;
+
+	/* hard reset the IPU */
+	val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+	val |= 1 << 3;
+	writel(val, MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+
+	return ret;
+}
+
+const struct imx_ipuv3_data imx51_ipuv3_data __initconst =
+			imx5_ipuv3_data_entry_single(MX51,
+			SZ_512M, mx51_ipuv3_init);
+#endif /* ifdef CONFIG_SOC_IMX51 */
+
+#ifdef CONFIG_SOC_IMX53
+int __init mx53_ipuv3_init(struct platform_device *pdev)
+{
+	int ret = 0;
+	u32 val;
+	int i;
+
+	/* fixup ipu base address */
+	for (i = 0; i < pdev->num_resources; i++) {
+		struct resource *r = &pdev->resource[i];
+
+		if (IORESOURCE_MEM == resource_type(r))
+			r->start -= 0x18000000;
+	}
+
+	/* hard reset the IPU */
+	val = readl(MX53_IO_ADDRESS(MX53_SRC_BASE_ADDR));
+	val |= 1 << 3;
+	writel(val, MX53_IO_ADDRESS(MX53_SRC_BASE_ADDR));
+
+	return ret;
+}
+
+const struct imx_ipuv3_data imx53_ipuv3_data __initconst =
+			imx5_ipuv3_data_entry_single(MX53,
+			SZ_128M, mx53_ipuv3_init);
+#endif
+
+struct platform_device *__init imx_add_ipuv3(
+		const struct imx_ipuv3_data *data,
+		struct imx_ipuv3_platform_data *pdata)
+{
+	struct resource res[] = {
+		{
+			.start = data->iobase,
+			.end = data->iobase + data->iosize - 1,
+			.flags = IORESOURCE_MEM,
+		}, {
+			.start = data->irq_err,
+			.end = data->irq_err,
+			.flags = IORESOURCE_IRQ,
+		}, {
+			.start = data->irq,
+			.end = data->irq,
+			.flags = IORESOURCE_IRQ,
+		},
+	};
+
+	pdata->init = data->init;
+
+	return imx_add_platform_device("imx-ipuv3", -1,
+			res, ARRAY_SIZE(res), pdata, sizeof(*pdata));
+}
+
+
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 8658c9c..c65ea3a 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -264,3 +264,15 @@ struct imx_spi_imx_data {
 struct platform_device *__init imx_add_spi_imx(
 		const struct imx_spi_imx_data *data,
 		const struct spi_imx_master *pdata);
+
+#include <mach/ipu-v3.h>
+struct imx_ipuv3_data {
+	resource_size_t iobase;
+	resource_size_t iosize;
+	resource_size_t irq_err;
+	resource_size_t irq;
+	int (*init) (struct platform_device *);
+};
+struct platform_device *__init imx_add_ipuv3(
+		const struct imx_ipuv3_data *data,
+		struct imx_ipuv3_platform_data *pdata);
-- 
1.7.1

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

* [PATCH 3/7] Add i.MX5 framebuffer driver
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 2/7] ARM i.MX5: Add IPU device support weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-14  8:49   ` Sascha Hauer
  2011-04-13 15:53 ` [PATCH 4/7] ARM i.MX51 babbage: Add framebuffer support weitway at gmail.com
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

This patch adds framebuffer support to the Freescale i.MX SoCs
equipped with an IPU v3, so far these are the i.MX51/53.

This driver has been tested on the i.MX51 babbage board with
both DVI and analog VGA in different resolutions and color depths.
It has also been tested on a custom i.MX51 board using a fixed
resolution panel.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 drivers/video/Kconfig  |   11 +
 drivers/video/Makefile |    1 +
 drivers/video/mx5fb.c  |  949 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 961 insertions(+), 0 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 9698c00..fb79cd6 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2344,6 +2344,17 @@ config FB_MX3
 	  far only synchronous displays are supported. If you plan to use
 	  an LCD display with your i.MX31 system, say Y here.
 
+config FB_MX5
+	tristate "MX5 Framebuffer support"
+	depends on FB && FB_IMX_IPU_V3
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	select FB_MODE_HELPERS
+	help
+	  This is a framebuffer device for the i.MX5 LCD Controller. If you
+	  plan to use an LCD display with your i.MX5 system, say Y here.
+
 config FB_BROADSHEET
 	tristate "E-Ink Broadsheet/Epson S1D13521 controller support"
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index f6f15fd..c0588fa 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -152,6 +152,7 @@ obj-$(CONFIG_FB_BFIN_LQ035Q1)     += bfin-lq035q1-fb.o
 obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
+obj-$(CONFIG_FB_MX5)		  += mx5fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 obj-$(CONFIG_FB_MXS)		  += mxsfb.o
 obj-$(CONFIG_FB_IMX_IPU_V3)	  += imx-ipu-v3/
diff --git a/drivers/video/mx5fb.c b/drivers/video/mx5fb.c
new file mode 100644
index 0000000..85b2251
--- /dev/null
+++ b/drivers/video/mx5fb.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * Framebuffer Framebuffer Driver for SDC
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/console.h>
+#include <video/imx-ipu-v3.h>
+#include <asm/uaccess.h>
+#include <mach/ipu-v3.h>
+
+#define DRIVER_NAME "imx-ipuv3-fb"
+
+struct imx_ipu_fb_info {
+	void			*ipu;
+	int			ipu_channel_num;
+	struct ipu_channel	*ipu_ch;
+	struct dc_channel	*dc_ch;
+	int			di_no;
+	u32			ipu_di_pix_fmt;
+	u32			ipu_in_pix_fmt;
+
+	u32			pseudo_palette[16];
+
+	struct ipu_dp		*dp;
+	struct dmfc_channel	*dmfc;
+	struct ipu_di		*di;
+	struct fb_info		*slave;
+	struct fb_info		*master;
+	bool			enabled;
+
+	/* overlay specific fields */
+	bool			blank_state;
+	int			ovlxres, ovlyres;
+};
+
+static int imx_ipu_fb_set_fix(struct fb_info *info)
+{
+	struct fb_fix_screeninfo *fix = &info->fix;
+	struct fb_var_screeninfo *var = &info->var;
+
+	fix->line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	fix->type = FB_TYPE_PACKED_PIXELS;
+	fix->accel = FB_ACCEL_NONE;
+	fix->visual = FB_VISUAL_TRUECOLOR;
+	fix->xpanstep = 1;
+	fix->ypanstep = 1;
+
+	return 0;
+}
+
+static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
+{
+	int size;
+
+	size = fbi->var.yres_virtual * fbi->fix.line_length;
+
+	if (fbi->screen_base) {
+		if (fbi->fix.smem_len >= size)
+			return 0;
+
+		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+	}
+
+	fbi->screen_base = dma_alloc_writecombine(fbi->device,
+				size,
+				(dma_addr_t *)&fbi->fix.smem_start,
+				GFP_DMA);
+	if (fbi->screen_base == 0) {
+		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
+				fbi->fix.smem_len);
+		fbi->fix.smem_len = 0;
+		fbi->fix.smem_start = 0;
+		return -ENOMEM;
+	}
+
+	fbi->fix.smem_len = size;
+	fbi->screen_size = fbi->fix.smem_len;
+
+	dev_dbg(fbi->device, "allocated fb @ paddr=0x%08lx, size=%d\n",
+		fbi->fix.smem_start, fbi->fix.smem_len);
+
+	/* Clear the screen */
+	memset((char *)fbi->screen_base, 0, fbi->fix.smem_len);
+
+	return 0;
+}
+
+static void imx_ipu_fb_enable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_di_enable(mxc_fbi->di);
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dc_enable_channel(mxc_fbi->dc_ch);
+	if (mxc_fbi->dp)
+		ipu_dp_enable_channel(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+}
+
+static void imx_ipu_fb_disable(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	if (mxc_fbi->dp)
+		ipu_dp_disable_channel(mxc_fbi->dp);
+	ipu_dc_disable_channel(mxc_fbi->dc_ch);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	ipu_di_disable(mxc_fbi->di);
+
+	mxc_fbi->enabled = 0;
+}
+
+static int calc_vref(struct fb_var_screeninfo *var)
+{
+	unsigned long htotal, vtotal;
+
+	htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin;
+	vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin;
+
+	if (!htotal || !vtotal)
+		return 60;
+
+	return PICOS2KHZ(var->pixclock) * 1000 / vtotal / htotal;
+}
+
+static int calc_bandwidth(struct fb_var_screeninfo *var, unsigned int vref)
+{
+	return var->xres * var->yres * vref;
+}
+
+static int imx_ipu_fb_set_par(struct fb_info *fbi)
+{
+	int ret;
+	struct ipu_di_signal_cfg sig_cfg;
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	u32 out_pixel_fmt;
+	int interlaced = 0;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int enabled = mxc_fbi->enabled;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	if (enabled)
+		imx_ipu_fb_disable(fbi);
+
+	fbi->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+
+	ret = imx_ipu_fb_map_video_memory(fbi);
+	if (ret)
+		return ret;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	memset(&sig_cfg, 0, sizeof(sig_cfg));
+	out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt;
+
+	if (var->vmode & FB_VMODE_INTERLACED)
+		sig_cfg.interlaced = 1;
+	if (var->vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */
+		sig_cfg.odd_field_first = 1;
+	if (var->sync & FB_SYNC_EXT)
+		sig_cfg.ext_clk = 1;
+	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
+		sig_cfg.Hsync_pol = 1;
+	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
+		sig_cfg.Vsync_pol = 1;
+	if (!(var->sync & FB_SYNC_CLK_LAT_FALL))
+		sig_cfg.clk_pol = 1;
+	if (var->sync & FB_SYNC_DATA_INVERT)
+		sig_cfg.data_pol = 1;
+	if (!(var->sync & FB_SYNC_OE_LOW_ACT))
+		sig_cfg.enable_pol = 1;
+	if (var->sync & FB_SYNC_CLK_IDLE_EN)
+		sig_cfg.clkidle_en = 1;
+
+	dev_dbg(fbi->device, "pixclock = %lu.%03lu MHz\n",
+		PICOS2KHZ(var->pixclock) / 1000,
+		PICOS2KHZ(var->pixclock) % 1000);
+
+	sig_cfg.width = var->xres;
+	sig_cfg.height = var->yres;
+	sig_cfg.pixel_fmt = out_pixel_fmt;
+	sig_cfg.h_start_width = var->left_margin;
+	sig_cfg.h_sync_width = var->hsync_len;
+	sig_cfg.h_end_width = var->right_margin;
+	sig_cfg.v_start_width = var->upper_margin;
+	sig_cfg.v_sync_width = var->vsync_len;
+	sig_cfg.v_end_width = var->lower_margin;
+	sig_cfg.v_to_h_sync = 0;
+
+	if (mxc_fbi->dp) {
+		ret = ipu_dp_setup_channel(mxc_fbi->dp, mxc_fbi->ipu_in_pix_fmt,
+				out_pixel_fmt, 1);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing display processor failed with %d\n",
+				ret);
+			return ret;
+		}
+	}
+
+	ret = ipu_dc_init_sync(mxc_fbi->dc_ch, mxc_fbi->di_no, interlaced,
+			out_pixel_fmt, fbi->var.xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing display controller failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_di_init_sync_panel(mxc_fbi->di,
+				PICOS2KHZ(var->pixclock) * 1000UL,
+				&sig_cfg);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing panel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	fbi->mode = (struct fb_videomode *)fb_match_mode(var, &fbi->modelist);
+	var->xoffset = var->yoffset = 0;
+
+	if (fbi->var.vmode & FB_VMODE_INTERLACED)
+		interlaced = 1;
+
+	ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+	if (ret) {
+		dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+	if (ret) {
+		dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var)));
+	if (ret) {
+		dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+		return ret;
+	}
+
+	if (enabled)
+		imx_ipu_fb_enable(fbi);
+
+	return ret;
+}
+
+/*
+ * These are the bitfields for each
+ * display depth that we support.
+ */
+struct imxfb_rgb {
+	struct fb_bitfield	red;
+	struct fb_bitfield	green;
+	struct fb_bitfield	blue;
+	struct fb_bitfield	transp;
+};
+
+static struct imxfb_rgb def_rgb_8 = {
+	.red	= { .offset =  5, .length = 3, },
+	.green	= { .offset =  2, .length = 3, },
+	.blue	= { .offset =  0, .length = 2, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_16 = {
+	.red	= { .offset = 11, .length = 5, },
+	.green	= { .offset =  5, .length = 6, },
+	.blue	= { .offset =  0, .length = 5, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_24 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset =  0, .length = 0, },
+};
+
+static struct imxfb_rgb def_rgb_32 = {
+	.red	= { .offset = 16, .length = 8, },
+	.green	= { .offset =  8, .length = 8, },
+	.blue	= { .offset =  0, .length = 8, },
+	.transp = { .offset = 24, .length = 8, },
+};
+
+/*
+ * Check framebuffer variable parameters and adjust to valid values.
+ *
+ * @param       var      framebuffer variable parameters
+ *
+ * @param       info     framebuffer information pointer
+ */
+static int imx_ipu_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct imxfb_rgb *rgb;
+
+	/* we don't support xpan, force xres_virtual to be equal to xres */
+	var->xres_virtual = var->xres;
+
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+
+	switch (var->bits_per_pixel) {
+	case 8:
+		rgb = &def_rgb_8;
+		break;
+	case 16:
+		rgb = &def_rgb_16;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_RGB565;
+		break;
+	case 24:
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+		break;
+	case 32:
+		rgb = &def_rgb_32;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR32;
+		break;
+	default:
+		var->bits_per_pixel = 24;
+		rgb = &def_rgb_24;
+		mxc_fbi->ipu_in_pix_fmt = IPU_PIX_FMT_BGR24;
+	}
+
+	var->red    = rgb->red;
+	var->green  = rgb->green;
+	var->blue   = rgb->blue;
+	var->transp = rgb->transp;
+
+	return 0;
+}
+
+static inline unsigned int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+static int imx_ipu_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			   u_int trans, struct fb_info *fbi)
+{
+	unsigned int val;
+	int ret = 1;
+
+	/*
+	 * If greyscale is true, then we convert the RGB value
+	 * to greyscale no matter what visual we are using.
+	 */
+	if (fbi->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green +
+				      7471 * blue) >> 16;
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		/*
+		 * 16-bit True Colour.  We encode the RGB value
+		 * according to the RGB bitfield information.
+		 */
+		if (regno < 16) {
+			u32 *pal = fbi->pseudo_palette;
+
+			val = chan_to_field(red, &fbi->var.red);
+			val |= chan_to_field(green, &fbi->var.green);
+			val |= chan_to_field(blue, &fbi->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_STATIC_PSEUDOCOLOR:
+	case FB_VISUAL_PSEUDOCOLOR:
+		break;
+	}
+
+	return ret;
+}
+
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi);
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi);
+
+static int imx_ipu_fb_blank(int blank, struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+
+	dev_dbg(info->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		if (mxc_fbi->slave)
+			imx_ipu_fb_disable_overlay(mxc_fbi->slave);
+		imx_ipu_fb_disable(info);
+		break;
+	case FB_BLANK_UNBLANK:
+		imx_ipu_fb_enable(info);
+		if (mxc_fbi->slave)
+			imx_ipu_fb_enable_overlay(mxc_fbi->slave);
+		break;
+	}
+
+	return 0;
+}
+
+static int imx_ipu_fb_pan_display(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	unsigned long base;
+	int ret;
+
+	if (info->var.yoffset == var->yoffset)
+		return 0;	/* No change, do nothing */
+
+	base = var->yoffset * var->xres_virtual * var->bits_per_pixel / 8;
+	base += info->fix.smem_start;
+
+	ret = ipu_wait_for_interrupt(mxc_fbi->ipu,
+			IPU_IRQ_EOF(mxc_fbi->ipu_channel_num), 100);
+	if (ret)
+		return ret;
+
+	if (ipu_idmac_update_channel_buffer(mxc_fbi->ipu_ch, 0, base)) {
+		dev_err(info->device,
+			"Error updating SDC buf to address=0x%08lX\n", base);
+	}
+
+	info->var.yoffset = var->yoffset;
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par,
+	.fb_check_var	= imx_ipu_fb_check_var,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank,
+};
+
+/*
+ * Overlay functions
+ */
+static void imx_ipu_fb_enable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	/*
+	 * This function is called unconditionally from imx_ipu_fb_blank to
+	 * enable/disable the overlay when the background is (un)blanked. So
+	 * we decide upon blank_state whether we should actually enable the
+	 * overlay.
+	 */
+	if (!mxc_fbi->blank_state)
+		return;
+
+	if (mxc_fbi->enabled)
+		return;
+
+	ipu_dmfc_enable_channel(mxc_fbi->dmfc);
+	ipu_idmac_enable_channel(mxc_fbi->ipu_ch);
+	ipu_dp_enable_fg(mxc_fbi->dp);
+	mxc_fbi->enabled = 1;
+	ipu_dp_set_color_key(mxc_fbi->dp, 1, 0x434343);
+}
+
+static void imx_ipu_fb_disable_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	if (!mxc_fbi->enabled)
+		return;
+
+	ipu_dp_disable_fg(mxc_fbi->dp);
+	ipu_wait_for_interrupt(mxc_fbi->ipu, 451, 100);
+	ipu_idmac_disable_channel(mxc_fbi->ipu_ch);
+	ipu_dmfc_disable_channel(mxc_fbi->dmfc);
+	mxc_fbi->enabled = 0;
+}
+
+#define NONSTD_TO_XPOS(x)	(((x) >> 0)  & 0xfff)
+#define NONSTD_TO_YPOS(x)	(((x) >> 12) & 0xfff)
+#define NONSTD_TO_ALPHA(x)	(((x) >> 24) & 0xff)
+
+static int imx_ipu_fb_check_var_overlay(struct fb_var_screeninfo *var,
+		struct fb_info *info)
+{
+	struct imx_ipu_fb_info *mxc_fbi = info->par;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	static int xpos, ypos;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+
+	ret = imx_ipu_fb_check_var(var, info);
+	if (ret)
+		return ret;
+
+	if (var->xres + xpos > var_master->xres)
+		return -EINVAL;
+	if (var->yres + ypos > var_master->yres)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int imx_ipu_fb_set_par_overlay(struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct fb_var_screeninfo *var = &fbi->var;
+	struct fb_info *fbi_master = mxc_fbi->master;
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_var_screeninfo *var_master = &fbi_master->var;
+	int ret;
+	int interlaced = 0;
+	int enabled = mxc_fbi->enabled;
+	int xpos, ypos, alpha;
+	int resolution_change;
+
+	dev_dbg(fbi->device, "Reconfiguring framebuffer %dx%d-%d\n",
+		fbi->var.xres, fbi->var.yres, fbi->var.bits_per_pixel);
+
+	resolution_change = mxc_fbi->ovlxres != var->xres ||
+		mxc_fbi->ovlyres != var->yres;
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_disable_overlay(fbi);
+
+	fbi->fix.line_length = var->xres_virtual *
+				var->bits_per_pixel / 8;
+
+	xpos = NONSTD_TO_XPOS(var->nonstd);
+	ypos = NONSTD_TO_YPOS(var->nonstd);
+	alpha = NONSTD_TO_ALPHA(var->nonstd);
+
+	if (resolution_change) {
+		ret = imx_ipu_fb_map_video_memory(fbi);
+		if (ret)
+			return ret;
+	}
+
+	if (!resolution_change && enabled)
+		ipu_wait_for_interrupt(mxc_fbi_master->ipu,
+			IPU_IRQ_EOF(mxc_fbi_master->ipu_channel_num), 100);
+
+	ipu_dp_set_window_pos(mxc_fbi->dp, xpos, ypos);
+	ipu_dp_set_global_alpha(mxc_fbi->dp, 1, alpha, 1);
+
+	var->xoffset = var->yoffset = 0;
+
+	if (resolution_change) {
+		if (var->vmode & FB_VMODE_INTERLACED)
+			interlaced = 1;
+
+		ret = ipu_idmac_init_channel_buffer(mxc_fbi->ipu_ch,
+					mxc_fbi->ipu_in_pix_fmt,
+					var->xres, var->yres,
+					fbi->fix.line_length,
+					IPU_ROTATE_NONE,
+					fbi->fix.smem_start,
+					0,
+					0, 0, interlaced);
+		if (ret) {
+			dev_dbg(fbi->device, "init channel buffer failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_init_channel(mxc_fbi->dmfc, var->xres);
+		if (ret) {
+			dev_dbg(fbi->device, "initializing dmfc channel failed with %d\n",
+				ret);
+			return ret;
+		}
+
+		ret = ipu_dmfc_alloc_bandwidth(mxc_fbi->dmfc, calc_bandwidth(var, calc_vref(var_master)));
+		if (ret) {
+			dev_dbg(fbi->device, "allocating dmfc bandwidth failed with %d\n",
+				ret);
+			return ret;
+		}
+		mxc_fbi->ovlxres = var->xres;
+		mxc_fbi->ovlyres = var->yres;
+	}
+
+	if (enabled && resolution_change)
+		imx_ipu_fb_enable_overlay(fbi);
+
+	return ret;
+}
+
+static int imx_ipu_fb_blank_overlay(int blank, struct fb_info *fbi)
+{
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+
+	dev_dbg(fbi->device, "blank = %d\n", blank);
+
+	switch (blank) {
+	case FB_BLANK_POWERDOWN:
+	case FB_BLANK_VSYNC_SUSPEND:
+	case FB_BLANK_HSYNC_SUSPEND:
+	case FB_BLANK_NORMAL:
+		mxc_fbi->blank_state = 0;
+		imx_ipu_fb_disable_overlay(fbi);
+		break;
+	case FB_BLANK_UNBLANK:
+		mxc_fbi->blank_state = 1;
+		imx_ipu_fb_enable_overlay(fbi);
+		break;
+	}
+
+	return 0;
+}
+
+static struct fb_ops imx_ipu_fb_overlay_ops = {
+	.owner		= THIS_MODULE,
+	.fb_set_par	= imx_ipu_fb_set_par_overlay,
+	.fb_check_var	= imx_ipu_fb_check_var_overlay,
+	.fb_setcolreg	= imx_ipu_fb_setcolreg,
+	.fb_pan_display	= imx_ipu_fb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+	.fb_blank	= imx_ipu_fb_blank_overlay,
+};
+
+static struct fb_info *imx_ipu_fb_init_fbinfo(struct device *dev, struct fb_ops *ops)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+
+	fbi = framebuffer_alloc(sizeof(struct imx_ipu_fb_info), dev);
+	if (!fbi)
+		return NULL;
+
+	BUG_ON(fbi->par == NULL);
+	mxc_fbi = fbi->par;
+
+	fbi->var.activate = FB_ACTIVATE_NOW;
+
+	fbi->fbops = ops;
+	fbi->flags = FBINFO_FLAG_DEFAULT;
+	fbi->pseudo_palette = mxc_fbi->pseudo_palette;
+
+	fb_alloc_cmap(&fbi->cmap, 16, 0);
+
+	return fbi;
+}
+
+static int imx_ipu_fb_init_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi;
+	struct imx_ipu_fb_info *ovl_mxc_fbi;
+	int ret;
+
+	ovlfbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_overlay_ops);
+	if (!ovlfbi)
+		return -ENOMEM;
+
+	ovl_mxc_fbi = ovlfbi->par;
+	ovl_mxc_fbi->ipu_ch =
+		ipu_idmac_get(mxc_fbi_master->ipu, ipu_channel);
+	ovl_mxc_fbi->dmfc =
+		ipu_dmfc_get(mxc_fbi_master->ipu, ipu_channel);
+	ovl_mxc_fbi->di = NULL;
+	ovl_mxc_fbi->dp = mxc_fbi_master->dp;
+	ovl_mxc_fbi->master = fbi_master;
+	mxc_fbi_master->slave = ovlfbi;
+
+	ovlfbi->var.xres = 240;
+	ovlfbi->var.yres = 320;
+	ovlfbi->var.yres_virtual = ovlfbi->var.yres;
+	ovlfbi->var.xres_virtual = ovlfbi->var.xres;
+	imx_ipu_fb_check_var(&ovlfbi->var, ovlfbi);
+	imx_ipu_fb_set_fix(ovlfbi);
+
+	ret = register_framebuffer(ovlfbi);
+	if (ret) {
+		framebuffer_release(ovlfbi);
+		return ret;
+	}
+
+	ipu_dp_set_global_alpha(ovl_mxc_fbi->dp, 0, 0, 1);
+	ipu_dp_set_color_key(ovl_mxc_fbi->dp, 1, 0x434343);
+
+	imx_ipu_fb_set_par_overlay(ovlfbi);
+
+	return 0;
+}
+
+static void imx_ipu_fb_exit_overlay(struct platform_device *pdev,
+		struct fb_info *fbi_master, int ipu_channel)
+{
+	struct imx_ipu_fb_info *mxc_fbi_master = fbi_master->par;
+	struct fb_info *ovlfbi = mxc_fbi_master->slave;
+	struct imx_ipu_fb_info *ovl_mxc_fbi = ovlfbi->par;
+
+	imx_ipu_fb_blank_overlay(FB_BLANK_POWERDOWN, ovlfbi);
+
+	unregister_framebuffer(ovlfbi);
+
+	ipu_idmac_put(ovl_mxc_fbi->ipu_ch);
+	ipu_dmfc_free_bandwidth(ovl_mxc_fbi->dmfc);
+	ipu_dmfc_put(ovl_mxc_fbi->dmfc);
+
+	framebuffer_release(ovlfbi);
+}
+
+static int imx_ipu_fb_find_mode(struct fb_info *fbi)
+{
+	int ret;
+	struct fb_videomode *mode_array;
+	struct fb_modelist *modelist;
+	struct fb_var_screeninfo *var = &fbi->var;
+	int i = 0;
+
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		i++;
+
+	mode_array = kmalloc(sizeof (struct fb_modelist) * i, GFP_KERNEL);
+	if (!mode_array)
+		return -ENOMEM;
+
+	i = 0;
+	list_for_each_entry(modelist, &fbi->modelist, list)
+		mode_array[i++] = modelist->mode;
+
+	ret = fb_find_mode(&fbi->var, fbi, NULL, mode_array, i, NULL, 16);
+	if (ret == 0)
+		return -EINVAL;
+
+	dev_dbg(fbi->device, "found %dx%d-%d hs:%d:%d:%d vs:%d:%d:%d\n",
+			var->xres, var->yres, var->bits_per_pixel,
+			var->hsync_len, var->left_margin, var->right_margin,
+			var->vsync_len, var->upper_margin, var->lower_margin);
+
+	kfree(mode_array);
+
+	return 0;
+}
+
+static int __devinit imx_ipu_fb_probe(struct platform_device *pdev)
+{
+	struct fb_info *fbi;
+	struct imx_ipu_fb_info *mxc_fbi;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+	int ret = 0, i;
+
+	pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
+
+	fbi = imx_ipu_fb_init_fbinfo(&pdev->dev, &imx_ipu_fb_ops);
+	if (!fbi)
+		return -ENOMEM;
+
+	mxc_fbi = fbi->par;
+
+	mxc_fbi->ipu = plat_data->ipu;
+	mxc_fbi->ipu_channel_num = plat_data->ipu_channel_bg;
+	mxc_fbi->ipu_di_pix_fmt = plat_data->interface_pix_fmt;
+	mxc_fbi->di_no = plat_data->display;
+
+	mxc_fbi->ipu_ch = ipu_idmac_get(mxc_fbi->ipu, plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_ipu;
+	}
+
+	mxc_fbi->dmfc = ipu_dmfc_get(mxc_fbi->ipu, plat_data->ipu_channel_bg);
+	if (IS_ERR(mxc_fbi->ipu_ch)) {
+		ret = PTR_ERR(mxc_fbi->ipu_ch);
+		goto failed_request_dmfc;
+	}
+
+	mxc_fbi->dc_ch = ipu_dc_get(mxc_fbi->ipu, plat_data->dc_channel);
+	if (IS_ERR(mxc_fbi->dc_ch)) {
+		ret = PTR_ERR(mxc_fbi->dc_ch);
+		goto failed_request_dc;
+	}
+
+	if (plat_data->dp_channel >= 0) {
+		mxc_fbi->dp = ipu_dp_get(mxc_fbi->ipu);
+		if (IS_ERR(mxc_fbi->dp)) {
+			ret = PTR_ERR(mxc_fbi->ipu_ch);
+			goto failed_request_dp;
+		}
+	}
+
+	mxc_fbi->di = ipu_di_get(mxc_fbi->ipu, plat_data->display);
+	if (IS_ERR(mxc_fbi->di)) {
+		ret = PTR_ERR(mxc_fbi->di);
+		goto failed_request_di;
+	}
+
+	fbi->var.yres_virtual = fbi->var.yres;
+
+	INIT_LIST_HEAD(&fbi->modelist);
+	for (i = 0; i < plat_data->num_modes; i++)
+		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
+
+	/*if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
+		for (i = 0; i < num_fb_modes; i++)
+			fb_add_videomode(&fb_modes[i], &fbi->modelist);
+	}*/
+
+	imx_ipu_fb_find_mode(fbi);
+
+	imx_ipu_fb_check_var(&fbi->var, fbi);
+	imx_ipu_fb_set_fix(fbi);
+	ret = register_framebuffer(fbi);
+	if (ret < 0)
+		goto failed_register;
+
+	imx_ipu_fb_set_par(fbi);
+	imx_ipu_fb_blank(FB_BLANK_UNBLANK, fbi);
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_init_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	platform_set_drvdata(pdev, fbi);
+
+	return 0;
+
+failed_register:
+	ipu_di_put(mxc_fbi->di);
+failed_request_di:
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+failed_request_dp:
+	ipu_dc_put(mxc_fbi->dc_ch);
+failed_request_dc:
+	ipu_dmfc_put(mxc_fbi->dmfc);
+failed_request_dmfc:
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+failed_request_ipu:
+	fb_dealloc_cmap(&fbi->cmap);
+	framebuffer_release(fbi);
+
+	return ret;
+}
+
+static int __devexit imx_ipu_fb_remove(struct platform_device *pdev)
+{
+	struct fb_info *fbi = platform_get_drvdata(pdev);
+	struct imx_ipu_fb_info *mxc_fbi = fbi->par;
+	struct ipuv3_fb_platform_data *plat_data = pdev->dev.platform_data;
+
+	if (plat_data->ipu_channel_fg >= 0 && plat_data->flags & IMX_IPU_FB_USE_OVERLAY)
+		imx_ipu_fb_exit_overlay(pdev, fbi, plat_data->ipu_channel_fg);
+
+	imx_ipu_fb_blank(FB_BLANK_POWERDOWN, fbi);
+
+	dma_free_writecombine(fbi->device, fbi->fix.smem_len,
+			      fbi->screen_base, fbi->fix.smem_start);
+
+	if (&fbi->cmap)
+		fb_dealloc_cmap(&fbi->cmap);
+
+	unregister_framebuffer(fbi);
+
+	if (plat_data->dp_channel >= 0)
+		ipu_dp_put(mxc_fbi->dp);
+	ipu_dmfc_free_bandwidth(mxc_fbi->dmfc);
+	ipu_dmfc_put(mxc_fbi->dmfc);
+	ipu_di_put(mxc_fbi->di);
+	ipu_idmac_put(mxc_fbi->ipu_ch);
+
+	framebuffer_release(fbi);
+
+	return 0;
+}
+
+static struct platform_driver imx_ipu_fb_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+	},
+	.probe = imx_ipu_fb_probe,
+	.remove = __devexit_p(imx_ipu_fb_remove),
+};
+
+static int __init imx_ipu_fb_init(void)
+{
+	return platform_driver_register(&imx_ipu_fb_driver);
+}
+
+static void __exit imx_ipu_fb_exit(void)
+{
+	platform_driver_unregister(&imx_ipu_fb_driver);
+}
+
+module_init(imx_ipu_fb_init);
+module_exit(imx_ipu_fb_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX framebuffer driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("fb");
-- 
1.7.1

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

* [PATCH 4/7] ARM i.MX51 babbage: Add framebuffer support
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 2/7] ARM i.MX5: Add IPU device support weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 3/7] Add i.MX5 framebuffer driver weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 5/7] ARM i.MX53 loco: " weitway at gmail.com
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 arch/arm/mach-mx5/Kconfig              |    1 +
 arch/arm/mach-mx5/board-mx51_babbage.c |   74 ++++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 83ee088..175d6f1 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -43,6 +43,7 @@ config MACH_MX51_BABBAGE
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
 	select IMX_HAVE_PLATFORM_SPI_IMX
+	select IMX_HAVE_PLATFORM_IMX_IPUV3
 	help
 	  Include support for MX51 Babbage platform, also known as MX51EVK in
 	  u-boot. This includes specific configurations for the board and its
diff --git a/arch/arm/mach-mx5/board-mx51_babbage.c b/arch/arm/mach-mx5/board-mx51_babbage.c
index b2ecd19..e8418ed 100644
--- a/arch/arm/mach-mx5/board-mx51_babbage.c
+++ b/arch/arm/mach-mx5/board-mx51_babbage.c
@@ -22,11 +22,13 @@
 #include <linux/input.h>
 #include <linux/spi/flash.h>
 #include <linux/spi/spi.h>
+#include <video/imx-ipu-v3.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/iomux-mx51.h>
 #include <mach/mxc_ehci.h>
+#include <mach/ipu-v3.h>
 
 #include <asm/irq.h>
 #include <asm/setup.h>
@@ -158,6 +160,41 @@ static iomux_v3_cfg_t mx51babbage_pads[] = {
 	MX51_PAD_CSPI1_SCLK__ECSPI1_SCLK,
 	MX51_PAD_CSPI1_SS0__GPIO4_24,
 	MX51_PAD_CSPI1_SS1__GPIO4_25,
+
+	/* Display */
+	MX51_PAD_DISPB2_SER_DIN__GPIO3_5,
+	MX51_PAD_DISPB2_SER_DIO__GPIO3_6,
+	MX51_PAD_NANDF_D12__GPIO3_28,
+
+	MX51_PAD_DISP1_DAT0__DISP1_DAT0,
+	MX51_PAD_DISP1_DAT1__DISP1_DAT1,
+	MX51_PAD_DISP1_DAT2__DISP1_DAT2,
+	MX51_PAD_DISP1_DAT3__DISP1_DAT3,
+	MX51_PAD_DISP1_DAT4__DISP1_DAT4,
+	MX51_PAD_DISP1_DAT5__DISP1_DAT5,
+	MX51_PAD_DISP1_DAT6__DISP1_DAT6,
+	MX51_PAD_DISP1_DAT7__DISP1_DAT7,
+	MX51_PAD_DISP1_DAT8__DISP1_DAT8,
+	MX51_PAD_DISP1_DAT9__DISP1_DAT9,
+	MX51_PAD_DISP1_DAT10__DISP1_DAT10,
+	MX51_PAD_DISP1_DAT11__DISP1_DAT11,
+	MX51_PAD_DISP1_DAT12__DISP1_DAT12,
+	MX51_PAD_DISP1_DAT13__DISP1_DAT13,
+	MX51_PAD_DISP1_DAT14__DISP1_DAT14,
+	MX51_PAD_DISP1_DAT15__DISP1_DAT15,
+	MX51_PAD_DISP1_DAT16__DISP1_DAT16,
+	MX51_PAD_DISP1_DAT17__DISP1_DAT17,
+	MX51_PAD_DISP1_DAT18__DISP1_DAT18,
+	MX51_PAD_DISP1_DAT19__DISP1_DAT19,
+	MX51_PAD_DISP1_DAT20__DISP1_DAT20,
+	MX51_PAD_DISP1_DAT21__DISP1_DAT21,
+	MX51_PAD_DISP1_DAT22__DISP1_DAT22,
+	MX51_PAD_DISP1_DAT23__DISP1_DAT23,
+#define MX51_PAD_DI_GP4__IPU_DI2_PIN15                 IOMUX_PAD(0x758, 0x350, 4, 0x0,   0, NO_PAD_CTRL)
+	MX51_PAD_DI_GP4__IPU_DI2_PIN15,
+
+	/* I2C DVI enable */
+	MX51_PAD_CSI2_HSYNC__GPIO4_14,
 };
 
 /* Serial ports */
@@ -338,6 +375,23 @@ static const struct spi_imx_master mx51_babbage_spi_pdata __initconst = {
 	.num_chipselect = ARRAY_SIZE(mx51_babbage_spi_cs),
 };
 
+static struct ipuv3_fb_platform_data babbage_fb0_data = {
+	.interface_pix_fmt = IPU_PIX_FMT_RGB24,
+	.flags = IMX_IPU_FB_USE_MODEDB | IMX_IPU_FB_USE_OVERLAY,
+	.display = 0,
+};
+
+static struct ipuv3_fb_platform_data babbage_fb1_data = {
+	.interface_pix_fmt = IPU_PIX_FMT_RGB565,
+	.flags = IMX_IPU_FB_USE_MODEDB,
+	.display = 1,
+};
+
+static struct imx_ipuv3_platform_data ipu_data = {
+	.fb_head0_platform_data = &babbage_fb0_data,
+	.fb_head1_platform_data = &babbage_fb1_data,
+};
+
 /*
  * Board specific initialization.
  */
@@ -388,6 +442,26 @@ static void __init mx51_babbage_init(void)
 		ARRAY_SIZE(mx51_babbage_spi_board_info));
 	imx51_add_ecspi(0, &mx51_babbage_spi_pdata);
 	imx51_add_imx2_wdt(0, NULL);
+
+#define GPIO_DVI_DETECT	(2 * 32 + 28)
+#define GPIO_DVI_RESET	(2 * 32 + 5)
+#define GPIO_DVI_PWRDN	(2 * 32 + 6)
+#define GPIO_DVI_I2C	(3 * 32 + 14)
+
+	/* DVI Detect */
+	gpio_request(GPIO_DVI_DETECT, "dvi detect");
+	gpio_direction_input(GPIO_DVI_DETECT);
+	/* DVI Reset - Assert for i2c disabled mode */
+	gpio_request(GPIO_DVI_RESET, "dvi reset");
+	gpio_direction_output(GPIO_DVI_RESET, 0);
+	/* DVI Power-down */
+	gpio_request(GPIO_DVI_PWRDN, "dvi pwdn");
+	gpio_direction_output(GPIO_DVI_PWRDN, 1);
+
+	gpio_request(GPIO_DVI_I2C, "dvi i2c");
+	gpio_direction_output(GPIO_DVI_I2C, 0);
+
+	imx51_add_ipuv3(&ipu_data);
 }
 
 static void __init mx51_babbage_timer_init(void)
-- 
1.7.1

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

* [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
                   ` (2 preceding siblings ...)
  2011-04-13 15:53 ` [PATCH 4/7] ARM i.MX51 babbage: Add framebuffer support weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-14  8:57   ` Sascha Hauer
  2011-04-13 15:53 ` [PATCH 6/7] ARM i.MX53: add pwm devices support weitway at gmail.com
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 arch/arm/mach-mx5/Kconfig           |    1 +
 arch/arm/mach-mx5/board-mx53_loco.c |   24 ++++++++++++++++++++++++
 arch/arm/mach-mx5/clock-mx51-mx53.c |    3 +++
 3 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 175d6f1..5d141a7 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -166,6 +166,7 @@ config MACH_MX53_LOCO
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+	select IMX_HAVE_PLATFORM_IMX_IPUV3
 	help
 	  Include support for MX53 LOCO platform. This includes specific
 	  configurations for the board and its peripherals.
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
index 0a18f8d..a499917 100644
--- a/arch/arm/mach-mx5/board-mx53_loco.c
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -23,11 +23,13 @@
 #include <linux/fec.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <video/imx-ipu-v3.h>
 
 #include <mach/common.h>
 #include <mach/hardware.h>
 #include <mach/imx-uart.h>
 #include <mach/iomux-mx53.h>
+#include <mach/ipu-v3.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -36,6 +38,9 @@
 #include "crm_regs.h"
 #include "devices-imx53.h"
 
+#define LOCO_DISP0_PWR			IMX_GPIO_NR(3, 24)
+#define LOCO_DISP0_DET_INT		IMX_GPIO_NR(3, 31)
+#define LOCO_DISP0_RESET		IMX_GPIO_NR(5, 0)
 #define LOCO_FEC_PHY_RST		IMX_GPIO_NR(7, 6)
 
 static iomux_v3_cfg_t mx53_loco_pads[] = {
@@ -203,6 +208,23 @@ static const struct imxi2c_platform_data mx53_loco_i2c_data __initconst = {
 	.bitrate = 100000,
 };
 
+static struct ipuv3_fb_platform_data loco_fb0_data = {
+	.interface_pix_fmt = IPU_PIX_FMT_RGB565,
+	.flags = IMX_IPU_FB_USE_MODEDB | IMX_IPU_FB_USE_OVERLAY,
+	.display = 0,
+};
+
+static struct ipuv3_fb_platform_data loco_fb1_data = {
+	.interface_pix_fmt = IPU_PIX_FMT_RGB565,
+	.flags = IMX_IPU_FB_USE_MODEDB,
+	.display = 1,
+};
+
+static struct imx_ipuv3_platform_data ipu_data = {
+	.fb_head0_platform_data = &loco_fb0_data,
+	.fb_head1_platform_data = &loco_fb1_data,
+};
+
 static void __init mx53_loco_board_init(void)
 {
 	mxc_iomux_v3_setup_multiple_pads(mx53_loco_pads,
@@ -215,6 +237,8 @@ static void __init mx53_loco_board_init(void)
 	imx53_add_imx_i2c(1, &mx53_loco_i2c_data);
 	imx53_add_sdhci_esdhc_imx(0, NULL);
 	imx53_add_sdhci_esdhc_imx(2, NULL);
+
+	imx53_add_ipuv3(&ipu_data);
 }
 
 static void __init mx53_loco_timer_init(void)
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 652ace4..213ec33 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -1468,6 +1468,9 @@ static struct clk_lookup mx53_lookups[] = {
 	_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
 	_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
 	_REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
+	_REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk)
+	_REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk)
+	_REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk)
 };
 
 static void clk_tree_init(void)
-- 
1.7.1

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

* [PATCH 6/7] ARM i.MX53: add pwm devices support
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
                   ` (3 preceding siblings ...)
  2011-04-13 15:53 ` [PATCH 5/7] ARM i.MX53 loco: " weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-13 15:53 ` [PATCH 7/7] ARM: i.MX53 loco: add pwm backlight device weitway at gmail.com
  2011-04-14  9:08 ` [PATCH 1/7] Add a mfd IPUv3 driver Sascha Hauer
  6 siblings, 0 replies; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

Signed-off-by: Jason Chen <b02280@freescale.com>
---
 arch/arm/mach-mx5/clock-mx51-mx53.c          |    6 ++++--
 arch/arm/mach-mx5/devices-imx53.h            |    4 ++++
 arch/arm/plat-mxc/devices/platform-mxc_pwm.c |   13 +++++++++----
 arch/arm/plat-mxc/pwm.c                      |    3 ++-
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 213ec33..2d22031 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -1410,8 +1410,8 @@ static struct clk_lookup mx51_lookups[] = {
 	_REGISTER_CLOCK("imx-uart.2", NULL, uart3_clk)
 	_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
 	_REGISTER_CLOCK("fec.0", NULL, fec_clk)
-	_REGISTER_CLOCK("mxc_pwm.0", "pwm", pwm1_clk)
-	_REGISTER_CLOCK("mxc_pwm.1", "pwm", pwm2_clk)
+	_REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk)
+	_REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
 	_REGISTER_CLOCK("imx-i2c.0", NULL, i2c1_clk)
 	_REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk)
 	_REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk)
@@ -1468,6 +1468,8 @@ static struct clk_lookup mx53_lookups[] = {
 	_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
 	_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
 	_REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
+	_REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk)
+	_REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
 	_REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk)
 	_REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk)
 	_REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index 8049039..fd591ff 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -34,6 +34,10 @@ extern const struct imx_imx2_wdt_data imx53_imx2_wdt_data[] __initconst;
 #define imx53_add_imx2_wdt(id, pdata)	\
 	imx_add_imx2_wdt(&imx53_imx2_wdt_data[id])
 
+extern const struct imx_mxc_pwm_data imx53_mxc_pwm_data[] __initconst;
+#define imx53_add_mxc_pwm(id)	\
+	imx_add_mxc_pwm(&imx53_mxc_pwm_data[id])
+
 extern const struct imx_ipuv3_data imx53_ipuv3_data __initconst;
 #define imx53_add_ipuv3(pdata)	\
 	imx_add_ipuv3(&imx53_ipuv3_data, pdata)
diff --git a/arch/arm/plat-mxc/devices/platform-mxc_pwm.c b/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
index b0c4ae2..e610c5b 100644
--- a/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
+++ b/arch/arm/plat-mxc/devices/platform-mxc_pwm.c
@@ -42,13 +42,18 @@ const struct imx_mxc_pwm_data imx27_mxc_pwm_data __initconst =
 
 #ifdef CONFIG_SOC_IMX51
 const struct imx_mxc_pwm_data imx51_mxc_pwm_data[] __initconst = {
-#define imx51_mxc_pwm_data_entry(_id, _hwid)				\
-	imx_mxc_pwm_data_entry(MX51, _id, _hwid, SZ_16K)
-	imx51_mxc_pwm_data_entry(0, 1),
-	imx51_mxc_pwm_data_entry(1, 2),
+	imx_mxc_pwm_data_entry(MX51, 0, 1, SZ_16K),
+	imx_mxc_pwm_data_entry(MX51, 1, 2, SZ_16K),
 };
 #endif /* ifdef CONFIG_SOC_IMX51 */
 
+#ifdef CONFIG_SOC_IMX53
+const struct imx_mxc_pwm_data imx53_mxc_pwm_data[] __initconst = {
+	imx_mxc_pwm_data_entry(MX53, 0, 1, SZ_16K),
+	imx_mxc_pwm_data_entry(MX53, 1, 2, SZ_16K),
+};
+#endif /* ifdef CONFIG_SOC_IMX53 */
+
 struct platform_device *__init imx_add_mxc_pwm(
 		const struct imx_mxc_pwm_data *data)
 {
diff --git a/arch/arm/plat-mxc/pwm.c b/arch/arm/plat-mxc/pwm.c
index 7a61ef8..5230413 100644
--- a/arch/arm/plat-mxc/pwm.c
+++ b/arch/arm/plat-mxc/pwm.c
@@ -57,7 +57,8 @@ int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns)
 	if (pwm == NULL || period_ns == 0 || duty_ns > period_ns)
 		return -EINVAL;
 
-	if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()) {
+	if (cpu_is_mx27() || cpu_is_mx3() || cpu_is_mx25() || cpu_is_mx51()
+		|| cpu_is_mx53()) {
 		unsigned long long c;
 		unsigned long period_cycles, duty_cycles, prescale;
 		u32 cr;
-- 
1.7.1

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

* [PATCH 7/7] ARM: i.MX53 loco: add pwm backlight device
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
                   ` (4 preceding siblings ...)
  2011-04-13 15:53 ` [PATCH 6/7] ARM i.MX53: add pwm devices support weitway at gmail.com
@ 2011-04-13 15:53 ` weitway at gmail.com
  2011-04-14  9:08 ` [PATCH 1/7] Add a mfd IPUv3 driver Sascha Hauer
  6 siblings, 0 replies; 32+ messages in thread
From: weitway at gmail.com @ 2011-04-13 15:53 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

Signed-off-by: Jason Chen <b02280@freescale.com>
---
 arch/arm/mach-mx5/Kconfig           |    1 +
 arch/arm/mach-mx5/board-mx53_loco.c |   11 +++++++++++
 arch/arm/mach-mx5/devices-imx53.h   |    4 ++++
 3 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 5d141a7..ea95245 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -166,6 +166,7 @@ config MACH_MX53_LOCO
 	select IMX_HAVE_PLATFORM_IMX_I2C
 	select IMX_HAVE_PLATFORM_IMX_UART
 	select IMX_HAVE_PLATFORM_SDHCI_ESDHC_IMX
+	select IMX_HAVE_PLATFORM_MXC_PWM
 	select IMX_HAVE_PLATFORM_IMX_IPUV3
 	help
 	  Include support for MX53 LOCO platform. This includes specific
diff --git a/arch/arm/mach-mx5/board-mx53_loco.c b/arch/arm/mach-mx5/board-mx53_loco.c
index a499917..2c2fac6 100644
--- a/arch/arm/mach-mx5/board-mx53_loco.c
+++ b/arch/arm/mach-mx5/board-mx53_loco.c
@@ -23,6 +23,7 @@
 #include <linux/fec.h>
 #include <linux/delay.h>
 #include <linux/gpio.h>
+#include <linux/pwm_backlight.h>
 #include <video/imx-ipu-v3.h>
 
 #include <mach/common.h>
@@ -208,6 +209,13 @@ static const struct imxi2c_platform_data mx53_loco_i2c_data __initconst = {
 	.bitrate = 100000,
 };
 
+static struct platform_pwm_backlight_data loco_pwm_backlight_data = {
+	.pwm_id = 1,
+	.max_brightness = 255,
+	.dft_brightness = 128,
+	.pwm_period_ns = 50000,
+};
+
 static struct ipuv3_fb_platform_data loco_fb0_data = {
 	.interface_pix_fmt = IPU_PIX_FMT_RGB565,
 	.flags = IMX_IPU_FB_USE_MODEDB | IMX_IPU_FB_USE_OVERLAY,
@@ -238,6 +246,9 @@ static void __init mx53_loco_board_init(void)
 	imx53_add_sdhci_esdhc_imx(0, NULL);
 	imx53_add_sdhci_esdhc_imx(2, NULL);
 
+	imx53_add_mxc_pwm(1);
+	imx53_add_mxc_pwm_backlight(0, &loco_pwm_backlight_data);
+
 	imx53_add_ipuv3(&ipu_data);
 }
 
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index fd591ff..3a0982b 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -38,6 +38,10 @@ extern const struct imx_mxc_pwm_data imx53_mxc_pwm_data[] __initconst;
 #define imx53_add_mxc_pwm(id)	\
 	imx_add_mxc_pwm(&imx53_mxc_pwm_data[id])
 
+#define imx53_add_mxc_pwm_backlight(id, pdata)			\
+	platform_device_register_resndata(NULL, "pwm-backlight",\
+			id, NULL, 0, pdata, sizeof(*pdata));
+
 extern const struct imx_ipuv3_data imx53_ipuv3_data __initconst;
 #define imx53_add_ipuv3(pdata)	\
 	imx_add_ipuv3(&imx53_ipuv3_data, pdata)
-- 
1.7.1

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

* [PATCH 3/7] Add i.MX5 framebuffer driver
  2011-04-13 15:53 ` [PATCH 3/7] Add i.MX5 framebuffer driver weitway at gmail.com
@ 2011-04-14  8:49   ` Sascha Hauer
  0 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-04-14  8:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Jason,

On Wed, Apr 13, 2011 at 11:53:32PM +0800, weitway at gmail.com wrote:
> 
> +
> +static int imx_ipu_fb_map_video_memory(struct fb_info *fbi)
> +{
> +	int size;
> +
> +	size = fbi->var.yres_virtual * fbi->fix.line_length;
> +
> +	if (fbi->screen_base) {
> +		if (fbi->fix.smem_len >= size)
> +			return 0;
> +
> +		dma_free_writecombine(fbi->device, fbi->fix.smem_len,
> +			      fbi->screen_base, fbi->fix.smem_start);
> +	}
> +
> +	fbi->screen_base = dma_alloc_writecombine(fbi->device,
> +				size,
> +				(dma_addr_t *)&fbi->fix.smem_start,
> +				GFP_DMA);
> +	if (fbi->screen_base == 0) {
> +		dev_err(fbi->device, "Unable to allocate framebuffer memory (%d)\n",
> +				fbi->fix.smem_len);
> +		fbi->fix.smem_len = 0;
> +		fbi->fix.smem_start = 0;
> +		return -ENOMEM;
> +	}

On which version of the driver I posted did you base this on? At least
in the last version removed this remapping feature.

You don't know whether the framebuffer is still mapped somewhere, so
you can't reallocate the framebuffer memory without corrupting your
memory. Simple test: run fbtest on one console, switch to a higher
resolution on another console and see your board go down...

IMO the only sane solution is to allocate memory for the largest
possible resolution at probe time.


> +
> +	INIT_LIST_HEAD(&fbi->modelist);
> +	for (i = 0; i < plat_data->num_modes; i++)
> +		fb_add_videomode(&plat_data->modes[i], &fbi->modelist);
> +
> +	/*if (plat_data->flags & IMX_IPU_FB_USE_MODEDB) {
> +		for (i = 0; i < num_fb_modes; i++)
> +			fb_add_videomode(&fb_modes[i], &fbi->modelist);
> +	}*/
> +

You should remove this.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support
  2011-04-13 15:53 ` [PATCH 5/7] ARM i.MX53 loco: " weitway at gmail.com
@ 2011-04-14  8:57   ` Sascha Hauer
  2011-04-14  9:01     ` Chen Jie-B02280
  0 siblings, 1 reply; 32+ messages in thread
From: Sascha Hauer @ 2011-04-14  8:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 13, 2011 at 11:53:34PM +0800, weitway at gmail.com wrote:
> From: Jason Chen <b02280@freescale.com>
>
> Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
> ---
>  arch/arm/mach-mx5/Kconfig           |    1 +
>  arch/arm/mach-mx5/board-mx53_loco.c |   24 ++++++++++++++++++++++++
>  arch/arm/mach-mx5/clock-mx51-mx53.c |    3 +++
>  3 files changed, 28 insertions(+), 0 deletions(-)


Does the driver already work on the LOCO board? I just tested it on my
board and get no picture (neither on VGA nor on HDMI).
I got a picture on HDMI with another version of this driver and some
hacking in the clock code, but as of now this only works when a freescale
kernel is started first and rebooted into my kernel without powercycling.
There is no picture on the VGA output though and I think there is
code missing for the TV encoder.

>  }
>  
>  static void __init mx53_loco_timer_init(void)
> diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
> index 652ace4..213ec33 100644
> --- a/arch/arm/mach-mx5/clock-mx51-mx53.c
> +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
> @@ -1468,6 +1468,9 @@ static struct clk_lookup mx53_lookups[] = {
>  	_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
>  	_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
>  	_REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk)

This change shouldn't be in this patch of course.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support
  2011-04-14  8:57   ` Sascha Hauer
@ 2011-04-14  9:01     ` Chen Jie-B02280
  2011-04-14  9:12       ` Sascha Hauer
  0 siblings, 1 reply; 32+ messages in thread
From: Chen Jie-B02280 @ 2011-04-14  9:01 UTC (permalink / raw)
  To: linux-arm-kernel

Hi, Sascha,

I tested this patch on wvga lcd panel for loco board.

You can not get vga output if without tve driver support, I am planning upstream tve driver later.

And how do you test HDMI on loco board? Do you get hdmi daughter card?

Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
Shanghai Branch Office
No.192 Liangjing Rd.,
Pu Dong New District Shanghai?201203
Tel:???? 021-28937178?
Fax:???? 021-28937444
E-mail:??Jason.Chen at freescale.com


-----Original Message-----
From: Sascha Hauer [mailto:s.hauer at pengutronix.de] 
Sent: Thursday, April 14, 2011 4:57 PM
To: weitway at gmail.com
Cc: linux-arm-kernel at lists.infradead.org; u.kleine-koenig at pengutronix.de; eric.miao at linaro.org; Chen Jie-B02280; Chen Jie-B02280
Subject: Re: [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support

On Wed, Apr 13, 2011 at 11:53:34PM +0800, weitway at gmail.com wrote:
> From: Jason Chen <b02280@freescale.com>
>
> Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
> ---
>  arch/arm/mach-mx5/Kconfig           |    1 +
>  arch/arm/mach-mx5/board-mx53_loco.c |   24 ++++++++++++++++++++++++
>  arch/arm/mach-mx5/clock-mx51-mx53.c |    3 +++
>  3 files changed, 28 insertions(+), 0 deletions(-)


Does the driver already work on the LOCO board? I just tested it on my board and get no picture (neither on VGA nor on HDMI).
I got a picture on HDMI with another version of this driver and some hacking in the clock code, but as of now this only works when a freescale kernel is started first and rebooted into my kernel without powercycling.
There is no picture on the VGA output though and I think there is code missing for the TV encoder.

>  }
>  
>  static void __init mx53_loco_timer_init(void) diff --git 
> a/arch/arm/mach-mx5/clock-mx51-mx53.c 
> b/arch/arm/mach-mx5/clock-mx51-mx53.c
> index 652ace4..213ec33 100644
> --- a/arch/arm/mach-mx5/clock-mx51-mx53.c
> +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
> @@ -1468,6 +1468,9 @@ static struct clk_lookup mx53_lookups[] = {
>  	_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
>  	_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
>  	_REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", NULL, ipu_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", "di0", ipu_di0_clk)
> +	_REGISTER_CLOCK("imx-ipuv3", "di1", ipu_di1_clk)

This change shouldn't be in this patch of course.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/7] Add a mfd IPUv3 driver
  2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
                   ` (5 preceding siblings ...)
  2011-04-13 15:53 ` [PATCH 7/7] ARM: i.MX53 loco: add pwm backlight device weitway at gmail.com
@ 2011-04-14  9:08 ` Sascha Hauer
  6 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-04-14  9:08 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 13, 2011 at 11:53:30PM +0800, weitway at gmail.com wrote:
> From: Jason Chen <b02280@freescale.com>
> 
> +
> +static irqreturn_t ipu_irq_handler(int irq, void *desc)
> +{
> +	struct ipu_soc *ipu = container_of(desc, struct ipu_soc, ipu_dev);
> +	DECLARE_IPU_IRQ_BITMAP(status);
> +	struct ipu_irq_handler *handler;
> +	unsigned long flags;
> +	int i;
> +
> +	spin_lock_irqsave(&ipu->ipu_lock, flags);
> +
> +	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++) {
> +		status[i] = ipu_cm_read(ipu, IPU_INT_STAT(i + 1));
> +		ipu_cm_write(ipu, status[i], IPU_INT_STAT(i + 1));
> +	}
> +
> +	list_for_each_entry(handler, &ipu->ipu_irq_handlers_list, list) {
> +		DECLARE_IPU_IRQ_BITMAP(tmp);
> +		if (bitmap_and(tmp, status, handler->ipu_irqs, IPU_IRQ_COUNT))
> +			handler->handler(tmp, handler->context);
> +	}
> +
> +	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
> +
> +	return IRQ_HANDLED;
> +}

Arnd and Thomas have objected to the custom interrupt handling code and
prefer a standard chained interrupt handler for the IPU interrupts.


> +
> +static int ipu_add_subdevice_pdata(struct platform_device *pdev,
> +		const char *name, int id, void *pdata, size_t pdata_size)
> +{
> +	struct mfd_cell cell = {
> +		.platform_data = pdata,
> +		.data_size = pdata_size,
> +	};

These fields do not exist anymore.

> +static int __devinit ipu_probe(struct platform_device *pdev)
> +{
> +	struct ipu_soc *ipu;
> +	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
> +	struct resource *res;
> +	int ret;
> +
> +	ipu = kzalloc(sizeof(struct ipu_soc), GFP_KERNEL);
> +	if (!ipu)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&ipu->ipu_lock);
> +	mutex_init(&ipu->ipu_channel_lock);
> +	INIT_LIST_HEAD(&ipu->ipu_irq_handlers_list);
> +
> +	ipu->ipu_dev = &pdev->dev;
> +
> +	if (plat_data->init)
> +		plat_data->init(pdev);
> +
> +	ipu->irq1 = platform_get_irq(pdev, 0);
> +	ipu->irq2 = platform_get_irq(pdev, 1);
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +
> +	if (!res || ipu->irq1 < 0 || ipu->irq2 < 0)
> +		return -ENODEV;

You already allocated memory which you forget to free here.

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support
  2011-04-14  9:01     ` Chen Jie-B02280
@ 2011-04-14  9:12       ` Sascha Hauer
  2011-04-14 12:37         ` Jason Chen
  0 siblings, 1 reply; 32+ messages in thread
From: Sascha Hauer @ 2011-04-14  9:12 UTC (permalink / raw)
  To: linux-arm-kernel

Please do not top post!

On Thu, Apr 14, 2011 at 09:01:37AM +0000, Chen Jie-B02280 wrote:
> Hi, Sascha,
> 
> I tested this patch on wvga lcd panel for loco board.
> 
> You can not get vga output if without tve driver support, I am planning upstream tve driver later.
> 
> And how do you test HDMI on loco board? Do you get hdmi daughter card?

Yes, I have the hdmi daughter board. I don't have the wvga lcd panel
though. Shouldn't you register the mode for the wvga panel then?
Also, Please don't register the second head when it's not actually
working.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 2/7] ARM i.MX5: Add IPU device support
  2011-04-13 15:53 ` [PATCH 2/7] ARM i.MX5: Add IPU device support weitway at gmail.com
@ 2011-04-14  9:25   ` Sascha Hauer
  2011-04-14 12:40     ` Jason Chen
  0 siblings, 1 reply; 32+ messages in thread
From: Sascha Hauer @ 2011-04-14  9:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 13, 2011 at 11:53:31PM +0800, weitway at gmail.com wrote:
> From: Jason Chen <b02280@freescale.com>
> 
> diff --git a/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
> new file mode 100644
> index 0000000..fe76cf1
> --- /dev/null
> +++ b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
> @@ -0,0 +1,94 @@
> +/*
> + * Copyright (C) 2010 Pengutronix
> + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
> + *
> + * 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.
> + */
> +#include <mach/hardware.h>
> +#include <mach/devices-common.h>
> +
> +#define imx5_ipuv3_data_entry_single(soc, size, ipu_init)	        \
> +	{                                                               \
> +		.iobase = soc ## _IPU_CTRL_BASE_ADDR,                   \
> +		.irq_err = soc ## _INT_IPU_ERR,                         \
> +		.irq = soc ## _INT_IPU_SYN,                             \
> +		.iosize = size,                                         \
> +		.init = ipu_init,                                       \
> +	}
> +
> +#ifdef CONFIG_SOC_IMX51
> +int __init mx51_ipuv3_init(struct platform_device *pdev)
> +{
> +	int ret = 0;
> +	u32 val;
> +
> +	/* hard reset the IPU */
> +	val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
> +	val |= 1 << 3;
> +	writel(val, MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
> +
> +	return ret;
> +}
> +
> +const struct imx_ipuv3_data imx51_ipuv3_data __initconst =
> +			imx5_ipuv3_data_entry_single(MX51,
> +			SZ_512M, mx51_ipuv3_init);
> +#endif /* ifdef CONFIG_SOC_IMX51 */
> +
> +#ifdef CONFIG_SOC_IMX53
> +int __init mx53_ipuv3_init(struct platform_device *pdev)
> +{
> +	int ret = 0;
> +	u32 val;
> +	int i;
> +
> +	/* fixup ipu base address */
> +	for (i = 0; i < pdev->num_resources; i++) {
> +		struct resource *r = &pdev->resource[i];
> +
> +		if (IORESOURCE_MEM == resource_type(r))
> +			r->start -= 0x18000000;
> +	}

This is ugly. We should rather use IPU_CM_REG_BASE directly for the
resources and remove the offsets from the IPU driver.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 5/7] ARM i.MX53 loco: Add framebuffer support
  2011-04-14  9:12       ` Sascha Hauer
@ 2011-04-14 12:37         ` Jason Chen
  0 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-04-14 12:37 UTC (permalink / raw)
  To: linux-arm-kernel

2011/4/14 Sascha Hauer <s.hauer@pengutronix.de>:
> Please do not top post!
>
> On Thu, Apr 14, 2011 at 09:01:37AM +0000, Chen Jie-B02280 wrote:
>> Hi, Sascha,
>>
>> I tested this patch on wvga lcd panel for loco board.
>>
>> You can not get vga output if without tve driver support, I am planning upstream tve driver later.
>>
>> And how do you test HDMI on loco board? Do you get hdmi daughter card?
>
> Yes, I have the hdmi daughter board. I don't have the wvga lcd panel
> though. Shouldn't you register the mode for the wvga panel then?
> Also, Please don't register the second head when it's not actually
> working.
I am using VESA mode for wvga panel, and for hdmi, it also need one
driver to support.
>
> Sascha
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
>

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

* [PATCH 2/7] ARM i.MX5: Add IPU device support
  2011-04-14  9:25   ` Sascha Hauer
@ 2011-04-14 12:40     ` Jason Chen
  0 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-04-14 12:40 UTC (permalink / raw)
  To: linux-arm-kernel

2011/4/14 Sascha Hauer <s.hauer@pengutronix.de>:
> On Wed, Apr 13, 2011 at 11:53:31PM +0800, weitway at gmail.com wrote:
>> From: Jason Chen <b02280@freescale.com>
>>
>> diff --git a/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
>> new file mode 100644
>> index 0000000..fe76cf1
>> --- /dev/null
>> +++ b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
>> @@ -0,0 +1,94 @@
>> +/*
>> + * Copyright (C) 2010 Pengutronix
>> + * Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>
>> + *
>> + * 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.
>> + */
>> +#include <mach/hardware.h>
>> +#include <mach/devices-common.h>
>> +
>> +#define imx5_ipuv3_data_entry_single(soc, size, ipu_init) ? ? ? ? ? ?\
>> + ? ? { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
>> + ? ? ? ? ? ? .iobase = soc ## _IPU_CTRL_BASE_ADDR, ? ? ? ? ? ? ? ? ? \
>> + ? ? ? ? ? ? .irq_err = soc ## _INT_IPU_ERR, ? ? ? ? ? ? ? ? ? ? ? ? \
>> + ? ? ? ? ? ? .irq = soc ## _INT_IPU_SYN, ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
>> + ? ? ? ? ? ? .iosize = size, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
>> + ? ? ? ? ? ? .init = ipu_init, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? \
>> + ? ? }
>> +
>> +#ifdef CONFIG_SOC_IMX51
>> +int __init mx51_ipuv3_init(struct platform_device *pdev)
>> +{
>> + ? ? int ret = 0;
>> + ? ? u32 val;
>> +
>> + ? ? /* hard reset the IPU */
>> + ? ? val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
>> + ? ? val |= 1 << 3;
>> + ? ? writel(val, MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
>> +
>> + ? ? return ret;
>> +}
>> +
>> +const struct imx_ipuv3_data imx51_ipuv3_data __initconst =
>> + ? ? ? ? ? ? ? ? ? ? imx5_ipuv3_data_entry_single(MX51,
>> + ? ? ? ? ? ? ? ? ? ? SZ_512M, mx51_ipuv3_init);
>> +#endif /* ifdef CONFIG_SOC_IMX51 */
>> +
>> +#ifdef CONFIG_SOC_IMX53
>> +int __init mx53_ipuv3_init(struct platform_device *pdev)
>> +{
>> + ? ? int ret = 0;
>> + ? ? u32 val;
>> + ? ? int i;
>> +
>> + ? ? /* fixup ipu base address */
>> + ? ? for (i = 0; i < pdev->num_resources; i++) {
>> + ? ? ? ? ? ? struct resource *r = &pdev->resource[i];
>> +
>> + ? ? ? ? ? ? if (IORESOURCE_MEM == resource_type(r))
>> + ? ? ? ? ? ? ? ? ? ? r->start -= 0x18000000;
>> + ? ? }
>
> This is ugly. We should rather use IPU_CM_REG_BASE directly for the
> resources and remove the offsets from the IPU driver.
>
ok
> Sascha
>
>
> --
> Pengutronix e.K. ? ? ? ? ? ? ? ? ? ? ? ? ? | ? ? ? ? ? ? ? ? ? ? ? ? ? ? |
> Industrial Linux Solutions ? ? ? ? ? ? ? ? | http://www.pengutronix.de/ ?|
> Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 ? ?|
> Amtsgericht Hildesheim, HRA 2686 ? ? ? ? ? | Fax: ? +49-5121-206917-5555 |
>

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

* [PATCH 1/7] Add a mfd IPUv3 driver
  2011-04-14  2:27 Chen Jie-B02280
@ 2011-04-25 13:37 ` Jason Chen
  0 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-04-25 13:37 UTC (permalink / raw)
  To: linux-arm-kernel

    Add a mfd IPUv3 driver

    The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
    features several units for image processing, this patch adds support
    for the units needed for Framebuffer support, namely:

    - Display Controller (dc)
    - Display Interface (di)
    - Display Multi Fifo Controller (dmfc)
    - Display Processor (dp)
    - Image DMA Controller (idmac)

    This patch is based on the Freescale driver, but follows a different
    approach. The Freescale code implements logical idmac channels and
    the handling of the subunits is hidden in common idmac code pathes
    in big switch/case statements. This patch instead just provides code
    and resource management for the different subunits. The user, in this
    case the framebuffer driver, decides how the different units play
    together.

    The IPU has other units missing in this patch:

    - CMOS Sensor Interface (csi)
    - Video Deinterlacer (vdi)
    - Sensor Multi FIFO Controler (smfc)
    - Image Converter (ic)
    - Image Rotator (irt)

    So expect more files to come in this directory.

    Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
    Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
    Signed-off-by: Jason Chen <Jason.Chen@linaro.org>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Add-a-mfd-IPUv3-driver.patch.gz
Type: application/x-gzip
Size: 22782 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110425/7557b931/attachment-0001.gz>

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-04-14  2:27 Chen Jie-B02280
  2011-04-25 13:37 ` Jason Chen
  0 siblings, 1 reply; 32+ messages in thread
From: Chen Jie-B02280 @ 2011-04-14  2:27 UTC (permalink / raw)
  To: linux-arm-kernel

The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It

features several units for image processing, this patch adds support

for the units needed for Framebuffer support, namely:



- Display Controller (dc)

- Display Interface (di)

- Display Multi Fifo Controller (dmfc)

- Display Processor (dp)

- Image DMA Controller (idmac)



This patch is based on the Freescale driver, but follows a different

approach. The Freescale code implements logical idmac channels and

the handling of the subunits is hidden in common idmac code pathes

in big switch/case statements. This patch instead just provides code

and resource management for the different subunits. The user, in this

case the framebuffer driver, decides how the different units play

together.



The IPU has other units missing in this patch:



- CMOS Sensor Interface (csi)

- Video Deinterlacer (vdi)

- Sensor Multi FIFO Controler (smfc)

- Image Converter (ic)

- Image Rotator (irt)



So expect more files to come in this directory.



Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de<mailto:s.hauer@pengutronix.de>>

Signed-off-by: Jason Chen <Jason.Chen at freescale.com<mailto:Jason.Chen@freescale.com>>

Jason Chen / Chen Jie
NMG / MAD
Freescale Semiconductor (China) Ltd.
Shanghai Branch Office
No.192 Liangjing Rd.,
Pu Dong New District Shanghai 201203
Tel:     021-28937178
Fax:     021-28937444
E-mail:  Jason.Chen at freescale.com<mailto:Jason.Chen@freescale.com>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110414/7c07b565/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Add-a-mfd-IPUv3-driver.patch.gz
Type: application/x-gzip
Size: 22582 bytes
Desc: 0001-Add-a-mfd-IPUv3-driver.patch.gz
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20110414/7c07b565/attachment-0001.gz>

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-04-14  2:04 jason.chen at freescale.com
  0 siblings, 0 replies; 32+ messages in thread
From: jason.chen at freescale.com @ 2011-04-14  2:04 UTC (permalink / raw)
  To: linux-arm-kernel

From: Jason Chen <b02280@freescale.com>

The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
features several units for image processing, this patch adds support
for the units needed for Framebuffer support, namely:

- Display Controller (dc)
- Display Interface (di)
- Display Multi Fifo Controller (dmfc)
- Display Processor (dp)
- Image DMA Controller (idmac)

This patch is based on the Freescale driver, but follows a different
approach. The Freescale code implements logical idmac channels and
the handling of the subunits is hidden in common idmac code pathes
in big switch/case statements. This patch instead just provides code
and resource management for the different subunits. The user, in this
case the framebuffer driver, decides how the different units play
together.

The IPU has other units missing in this patch:

- CMOS Sensor Interface (csi)
- Video Deinterlacer (vdi)
- Sensor Multi FIFO Controler (smfc)
- Image Converter (ic)
- Image Rotator (irt)

So expect more files to come in this directory.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Jason Chen <Jason.Chen@freescale.com>
---
 arch/arm/plat-mxc/include/mach/ipu-v3.h |   52 ++
 drivers/video/Kconfig                   |    2 +
 drivers/video/Makefile                  |    1 +
 drivers/video/imx-ipu-v3/Kconfig        |   10 +
 drivers/video/imx-ipu-v3/Makefile       |    3 +
 drivers/video/imx-ipu-v3/ipu-common.c   | 1257 +++++++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dc.c       |  442 +++++++++++
 drivers/video/imx-ipu-v3/ipu-di.c       |  572 ++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dmfc.c     |  376 +++++++++
 drivers/video/imx-ipu-v3/ipu-dp.c       |  507 +++++++++++++
 drivers/video/imx-ipu-v3/ipu-prv.h      |  288 +++++++
 include/video/imx-ipu-v3.h              |  226 ++++++
 12 files changed, 3736 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h
new file mode 100644
index 0000000..184dfe5
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef __MACH_IPU_V3_H_
+#define __MACH_IPU_V3_H_
+
+/* IPU specific extensions to struct fb_videomode flag field */
+#define FB_SYNC_OE_LOW_ACT	(1 << 8)
+#define FB_SYNC_CLK_LAT_FALL	(1 << 9)
+#define FB_SYNC_DATA_INVERT	(1 << 10)
+#define FB_SYNC_CLK_IDLE_EN	(1 << 11)
+#define FB_SYNC_SHARP_MODE	(1 << 12)
+#define FB_SYNC_SWAP_RGB	(1 << 13)
+
+struct ipuv3_fb_platform_data {
+	const struct fb_videomode	*modes;
+	int				num_modes;
+	char				*mode_str;
+	u32				interface_pix_fmt;
+
+#define IMX_IPU_FB_USE_MODEDB	(1 << 0)
+#define IMX_IPU_FB_USE_OVERLAY	(1 << 1)
+	unsigned long			flags;
+
+	int				ipu_channel_bg;
+	int				ipu_channel_fg;
+	int				dc_channel;
+	int				dp_channel;
+	int				display;
+
+	void				*ipu;
+};
+
+struct imx_ipuv3_platform_data {
+	int rev;
+	int (*init) (struct platform_device *);
+	struct ipuv3_fb_platform_data	*fb_head0_platform_data;
+	struct ipuv3_fb_platform_data	*fb_head1_platform_data;
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index e0ea23f..9698c00 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
 
 source "drivers/gpu/stub/Kconfig"
 
+source "drivers/video/imx-ipu-v3/Kconfig"
+
 config VGASTATE
        tristate
        default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 9a096ae..f6f15fd 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -154,6 +154,7 @@ obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
 obj-$(CONFIG_FB_MXS)		  += mxsfb.o
+obj-$(CONFIG_FB_IMX_IPU_V3)	  += imx-ipu-v3/
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/imx-ipu-v3/Kconfig b/drivers/video/imx-ipu-v3/Kconfig
new file mode 100644
index 0000000..75aa483
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Kconfig
@@ -0,0 +1,10 @@
+
+config FB_IMX_IPU_V3
+	tristate "Support the Image Processing Unit (IPU) found on the i.MX5x"
+	depends on ARCH_MX51 || ARCH_MX53
+	select MFD_SUPPORT
+	select MFD_CORE
+	help
+	  Say yes here to support the IPU on i.MX5x. This is used by the fb
+	  driver and also by the i.MX5x camera support.
+
diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile
new file mode 100644
index 0000000..65b6153
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_FB_IMX_IPU_V3) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o
diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c
new file mode 100644
index 0000000..082a5af
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-common.c
@@ -0,0 +1,1257 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <mach/common.h>
+#include <linux/mfd/core.h>
+#include <mach/ipu-v3.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+static inline struct ipu_soc *idmachannel2ipu(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu;
+	struct ipu_channel *base = channel - channel->num;
+
+	ipu = container_of(base, struct ipu_soc, channels[0]);
+
+	return ipu;
+}
+
+struct ipu_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num)
+{
+	struct ipu_channel *channel;
+
+	dev_dbg(ipu->ipu_dev, "%s %d\n", __func__, num);
+
+	if (num > (IPU_IDMA_CHAN_NUM - 1))
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	channel = &ipu->channels[num];
+
+	if (channel->busy) {
+		channel = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	channel->busy = 1;
+	channel->num = num;
+
+out:
+	mutex_unlock(&ipu->ipu_channel_lock);
+
+	return channel;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+
+	dev_dbg(ipu->ipu_dev, "%s %d\n", __func__, channel->num);
+
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	channel->busy = 0;
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_put);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel,
+			bool doublebuffer)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	if (doublebuffer)
+		reg |= idma_mask(channel->num);
+	else
+		reg &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer);
+
+void ipu_idmac_select_buffer(struct ipu_channel *channel,
+			u32 buf_num)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	/* Mark buffer as ready. */
+	if (buf_num == 0)
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+	else
+		ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 val;
+	unsigned long flags;
+
+	ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val |= idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipu_channel *channel)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	/* Disable DMA channel(s) */
+	val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num));
+
+	/* Set channel buffers NOT to be ready */
+	ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */
+
+	if (ipu_idma_is_set(ipu, IPU_CHA_BUF0_RDY, channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF0_RDY(channel->num));
+	}
+	if (ipu_idma_is_set(ipu, IPU_CHA_BUF1_RDY, channel->num)) {
+		ipu_cm_write(ipu, idma_mask(channel->num),
+			     IPU_CHA_BUF1_RDY(channel->num));
+	}
+
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+
+	/* Reset the double buffer */
+	val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel);
+
+#define __F(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_UBO		__F(0, 46, 22)
+#define IPU_FIELD_VBO		__F(0, 68, 22)
+#define IPU_FIELD_IOX		__F(0, 90, 4)
+#define IPU_FIELD_RDRW		__F(0, 94, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SLY		__F(1, 102, 14)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_SLUV		__F(1, 128, 14)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_SX		__F(0, 46, 12)
+#define IPU_FIELD_SY		__F(0, 58, 11)
+#define IPU_FIELD_NS		__F(0, 69, 10)
+#define IPU_FIELD_SDX		__F(0, 79, 7)
+#define IPU_FIELD_SM		__F(0, 86, 10)
+#define IPU_FIELD_SCC		__F(0, 96, 1)
+#define IPU_FIELD_SCE		__F(0, 97, 1)
+#define IPU_FIELD_SDY		__F(0, 98, 7)
+#define IPU_FIELD_SDRX		__F(0, 105, 1)
+#define IPU_FIELD_SDRY		__F(0, 106, 1)
+#define IPU_FIELD_BPP		__F(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	__F(0, 110, 2)
+#define IPU_FIELD_DIM		__F(0, 112, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SL		__F(1, 102, 14)
+#define IPU_FIELD_WID0		__F(1, 116, 3)
+#define IPU_FIELD_WID1		__F(1, 119, 3)
+#define IPU_FIELD_WID2		__F(1, 122, 3)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_OFS0		__F(1, 128, 5)
+#define IPU_FIELD_OFS1		__F(1, 133, 5)
+#define IPU_FIELD_OFS2		__F(1, 138, 5)
+#define IPU_FIELD_OFS3		__F(1, 143, 5)
+#define IPU_FIELD_SXYS		__F(1, 148, 1)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	__F(1, 150, 1)
+
+struct ipu_ch_param_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+static u32 ipu_bytes_per_pixel(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/* generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YUV422P:
+		return 1;
+
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		return 2;
+
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+		return 3;
+
+	case IPU_PIX_FMT_GENERIC_32:	/* generic data */
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+		return 4;
+
+	default:
+		return 1;
+	}
+}
+
+bool ipu_pixel_format_has_alpha(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+#define ipu_ch_param_addr(cpmem_base, ch) (((struct ipu_ch_param *)cpmem_base) + (ch))
+
+static inline void ipu_ch_param_set_field(struct ipu_ch_param *base, u32 wbs, u32 v)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	base->word[word].data[i] &= ~(mask << ofs);
+	base->word[word].data[i] |= v << ofs;
+
+	if ((bit + size - 1) / 32 > i) {
+		base->word[word].data[i + 1] &= ~(v >> (mask ? (32 - ofs) : 0));
+		base->word[word].data[i + 1] |= v >> (ofs ? (32 - ofs) : 0);
+	}
+}
+
+static inline u32 ipu_ch_param_read_field(struct ipu_ch_param *base, u32 wbs)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (base->word[word].data[i] >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = base->word[word].data[i + 1];
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+
+static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
+					      int red_width, int red_offset,
+					      int green_width, int green_offset,
+					      int blue_width, int blue_offset,
+					      int alpha_width, int alpha_offset)
+{
+	/* Setup red width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID0, red_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS0, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID1, green_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS1, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID2, blue_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS2, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID3, alpha_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS3, alpha_offset);
+}
+
+static inline void ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
+{
+	struct ipu_ch_param *p = ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch);
+	dev_dbg(ipu->ipu_dev, "ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+		 p->word[0].data[3], p->word[0].data[4]);
+	dev_dbg(ipu->ipu_dev, "ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+		 p->word[1].data[3], p->word[1].data[4]);
+	dev_dbg(ipu->ipu_dev, "PFS 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_PFS));
+	dev_dbg(ipu->ipu_dev, "BPP 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_BPP));
+	dev_dbg(ipu->ipu_dev, "NPB 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_NPB));
+
+	dev_dbg(ipu->ipu_dev, "FW %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FW));
+	dev_dbg(ipu->ipu_dev, "FH %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FH));
+	dev_dbg(ipu->ipu_dev, "Stride %d\n", ipu_ch_param_read_field(p, IPU_FIELD_SL));
+
+	dev_dbg(ipu->ipu_dev, "Width0 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID0));
+	dev_dbg(ipu->ipu_dev, "Width1 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID1));
+	dev_dbg(ipu->ipu_dev, "Width2 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID2));
+	dev_dbg(ipu->ipu_dev, "Width3 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID3));
+	dev_dbg(ipu->ipu_dev, "Offset0 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS0));
+	dev_dbg(ipu->ipu_dev, "Offset1 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS1));
+	dev_dbg(ipu->ipu_dev, "Offset2 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS2));
+	dev_dbg(ipu->ipu_dev, "Offset3 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS3));
+}
+
+static inline void ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
+						u32 ch, u16 burst_pixels)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_NPB,
+			       burst_pixels - 1);
+};
+
+static inline int ipu_ch_param_get_burst_size(struct ipu_soc *ipu, u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_NPB) + 1;
+};
+
+static inline int ipu_ch_param_get_bpp(struct ipu_soc *ipu, u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_BPP);
+};
+
+static inline void ipu_ch_param_set_buffer(struct ipu_soc *ipu, u32 ch, int bufNum,
+					    dma_addr_t phyaddr)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch),
+			bufNum ? IPU_FIELD_EBA1 : IPU_FIELD_EBA0,
+			phyaddr / 8);
+};
+
+#define IPU_FIELD_ROT_HF_VF		__F(0, 119, 3)
+
+static inline void ipu_ch_param_set_rotation(struct ipu_soc *ipu,
+				u32 ch, ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ROT_HF_VF, temp_rot);
+};
+
+static inline void ipu_ch_param_set_block_mode(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_BM, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
+		u32 ch, bool option)
+{
+	if (option)
+		ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALU, 1);
+	else
+		ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALU, 0);
+};
+
+static inline void ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_CRE, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, u32 ch)
+{
+	int alp_mem_idx;
+
+	switch (ch) {
+	case 14: /* PRP graphic */
+		alp_mem_idx = 0;
+		break;
+	case 15: /* PP graphic */
+		alp_mem_idx = 1;
+		break;
+	case 23: /* DP BG SYNC graphic */
+		alp_mem_idx = 4;
+		break;
+	case 27: /* DP FG SYNC graphic */
+		alp_mem_idx = 2;
+		break;
+	default:
+		dev_err(ipu->ipu_dev, "unsupported correlated channel of local alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ALBM, alp_mem_idx);
+};
+
+static inline void ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, u32 ch)
+{
+	u32 stride;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SO, 1);
+	stride = ipu_ch_param_read_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SL) + 1;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ILO, stride / 8);
+	stride *= 2;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_SLY, stride - 1);
+};
+
+static inline void ipu_ch_param_set_high_priority(struct ipu_soc *ipu, u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_ID, 1);
+};
+
+static inline void ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, u32 ch, int alpha_width)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), IPU_FIELD_WID3,
+			alpha_width - 1);
+}
+
+static int ipu_ch_param_init(struct ipu_soc *ipu,
+			int ch,
+			u32 pixel_fmt, u32 width,
+			u32 height, u32 stride,
+			u32 u, u32 v,
+			u32 uv_stride, dma_addr_t addr0,
+			dma_addr_t addr1)
+{
+	u32 u_offset = 0;
+	u32 v_offset = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_FW, width - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_FH, height - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_SLY, stride - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA0, addr0 >> 3);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA1, addr1 >> 3);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/* Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 63);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_32:
+		/* Represents 32-bit Generic data */
+		break;
+	case IPU_PIX_FMT_RGB565:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+		break;
+	case IPU_PIX_FMT_BGR24:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+		break;
+	case IPU_PIX_FMT_ABGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_UYVY:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0xA);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0x8);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);  /* burst size */
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = (v == 0) ? stride * height : v;
+		u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+		break;
+	case IPU_PIX_FMT_NV12:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 4);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		break;
+	default:
+		dev_err(ipu->ipu_dev, "mxc ipu: unimplemented pixel format: %d\n",
+			pixel_fmt);
+		return -EINVAL;
+	}
+	/* set burst size to 16 */
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, IPU_FIELD_SLUV, uv_stride - 1);
+
+	if (u > u_offset)
+		u_offset = u;
+
+	if (v > v_offset)
+		v_offset = v;
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_UBO, u_offset / 8);
+	ipu_ch_param_set_field(&params, IPU_FIELD_VBO, v_offset / 8);
+
+	dev_dbg(ipu->ipu_dev, "initializing idma ch %d @ %p\n",
+			ch, ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch));
+	memcpy(ipu_ch_param_addr(ipu->ipu_cpmem_reg, ch), &params, sizeof(params));
+	return 0;
+}
+
+/*
+ * This function is called to initialize a buffer for a IPU channel.
+ *
+ * @param       channel         The IPU channel.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       rot_mode        Input parameter for rotation setting of buffer.
+ *                              A rotation setting other than
+ *                              IPU_ROTATE_VERT_FLIP
+ *                              should only be used for input buffers of
+ *                              rotation channels.
+ *
+ * @param       phyaddr_0       Input parameter buffer 0 physical address.
+ *
+ * @param       phyaddr_1       Input parameter buffer 1 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              double buffering mode.
+ *
+ * @param       u		private u offset for additional cropping,
+ *				zero if not used.
+ *
+ * @param       v		private v offset for additional cropping,
+ *				zero if not used.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u, u32 v, bool interlaced)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	int ret = 0;
+	u32 dma_chan = channel->num;
+
+	if (stride < width * ipu_bytes_per_pixel(pixel_fmt))
+		stride = width * ipu_bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu->ipu_dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+
+	ipu_get(ipu);
+
+	/* Build parameter memory data for DMA channel */
+	ret = ipu_ch_param_init(ipu, dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1);
+	if (ret)
+		goto out;
+
+	if (rot_mode)
+		ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
+
+	if (interlaced)
+		ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
+
+	if (idmac_idma_is_set(ipu, IDMAC_CHA_PRI, dma_chan))
+		ipu_ch_param_set_high_priority(ipu, dma_chan);
+
+	ipu_ch_param_dump(ipu, dma_chan);
+out:
+	ipu_put(ipu);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_init_channel_buffer);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 buf_num, dma_addr_t phyaddr)
+{
+	struct ipu_soc *ipu = idmachannel2ipu(channel);
+	u32 dma_chan = channel->num;
+
+	ipu_ch_param_set_buffer(ipu, dma_chan, buf_num, phyaddr);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_idmac_update_channel_buffer);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu->ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	ipu_conf |= mask;
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, lock_flags);
+
+	return 0;
+}
+
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu->ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	ipu_conf &= ~mask;
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, lock_flags);
+
+	return 0;
+}
+
+
+/*
+ * should be called with ipu_lock.
+ */
+static void ipu_irq_update_irq_mask(struct ipu_soc *ipu)
+{
+	struct ipu_irq_handler *handler;
+	int i;
+
+	DECLARE_IPU_IRQ_BITMAP(irqs);
+
+	bitmap_zero(irqs, IPU_IRQ_COUNT);
+
+	list_for_each_entry(handler, &ipu->ipu_irq_handlers_list, list)
+		bitmap_or(irqs, irqs, handler->ipu_irqs, IPU_IRQ_COUNT);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++)
+		ipu_cm_write(ipu, irqs[i], IPU_INT_CTRL(i + 1));
+}
+
+int ipu_irq_add_handler(struct ipu_soc *ipu, struct ipu_irq_handler *ipuirq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	list_add_tail(&ipuirq->list, &ipu->ipu_irq_handlers_list);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irq_add_handler);
+
+void ipu_irq_remove_handler(struct ipu_soc *ipu, struct ipu_irq_handler *handler)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	list_del(&handler->list);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+}
+EXPORT_SYMBOL_GPL(ipu_irq_remove_handler);
+
+int ipu_irq_update_handler(struct ipu_soc *ipu,
+		struct ipu_irq_handler *handler,
+		unsigned long *bitmap)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	bitmap_copy(handler->ipu_irqs, bitmap, IPU_IRQ_COUNT);
+	ipu_irq_update_irq_mask(ipu);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_irq_update_handler);
+
+static void ipu_completion_handler(unsigned long *bitmask, void *context)
+{
+	struct completion *completion = context;
+
+	complete(completion);
+}
+
+int ipu_wait_for_interrupt(struct ipu_soc *ipu, int interrupt, int timeout_ms)
+{
+	struct ipu_irq_handler handler;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long flags;
+	int ret;
+
+	bitmap_zero(handler.ipu_irqs, IPU_IRQ_COUNT);
+	bitmap_set(handler.ipu_irqs, interrupt, 1);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+	ipu_cm_write(ipu, 1 << (interrupt % 32), IPU_INT_STAT(interrupt / 32 + 1));
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	handler.handler = ipu_completion_handler;
+	handler.context = &completion;
+	ipu_irq_add_handler(ipu, &handler);
+
+	ret = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(timeout_ms));
+
+	ipu_irq_remove_handler(ipu, &handler);
+
+	return ret > 0 ? 0 : -ETIMEDOUT;
+}
+EXPORT_SYMBOL_GPL(ipu_wait_for_interrupt);
+
+static irqreturn_t ipu_irq_handler(int irq, void *desc)
+{
+	struct ipu_soc *ipu = container_of(desc, struct ipu_soc, ipu_dev);
+	DECLARE_IPU_IRQ_BITMAP(status);
+	struct ipu_irq_handler *handler;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++) {
+		status[i] = ipu_cm_read(ipu, IPU_INT_STAT(i + 1));
+		ipu_cm_write(ipu, status[i], IPU_INT_STAT(i + 1));
+	}
+
+	list_for_each_entry(handler, &ipu->ipu_irq_handlers_list, list) {
+		DECLARE_IPU_IRQ_BITMAP(tmp);
+		if (bitmap_and(tmp, status, handler->ipu_irqs, IPU_IRQ_COUNT))
+			handler->handler(tmp, handler->context);
+	}
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+ipu_color_space_t format_to_colorspace(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_LVDS666:
+	case IPU_PIX_FMT_LVDS888:
+		return RGB;
+
+	default:
+		return YCbCr;
+	}
+}
+
+static int ipu_reset(struct ipu_soc *ipu)
+{
+	int timeout = 1000;
+
+	ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST);
+
+	while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) {
+		if (!timeout--)
+			return -ETIME;
+		msleep(1);
+	}
+
+	return 0;
+}
+
+static int ipu_submodules_init(struct platform_device *pdev, unsigned long ipu_base)
+{
+	char *unit;
+	int ret;
+
+	ret = ipu_di_init(pdev, 0, ipu_base + IPU_DI0_REG_BASE,
+			IPU_CONF_DI0_EN);
+	if (ret) {
+		unit = "di0";
+		goto err_di_0;
+	}
+
+	ret = ipu_di_init(pdev, 1, ipu_base + IPU_DI1_REG_BASE,
+			IPU_CONF_DI1_EN);
+	if (ret) {
+		unit = "di1";
+		goto err_di_1;
+	}
+
+	ret = ipu_dc_init(pdev, ipu_base + IPU_DC_REG_BASE,
+			ipu_base + IPU_DC_TMPL_REG_BASE);
+	if (ret) {
+		unit = "dc_template";
+		goto err_dc;
+	}
+
+	ret = ipu_dmfc_init(pdev, ipu_base + IPU_DMFC_REG_BASE);
+	if (ret) {
+		unit = "dmfc";
+		goto err_dmfc;
+	}
+
+	ret = ipu_dp_init(pdev, ipu_base + IPU_SRM_REG_BASE);
+	if (ret) {
+		unit = "dp";
+		goto err_dp;
+	}
+
+	return 0;
+
+err_dp:
+	ipu_dmfc_exit(pdev);
+err_dmfc:
+	ipu_dc_exit(pdev);
+err_dc:
+	ipu_di_exit(pdev, 1);
+err_di_1:
+	ipu_di_exit(pdev, 0);
+err_di_0:
+	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+	return ret;
+}
+
+void ipu_get(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	ipu->ipu_use_count++;
+
+	if (ipu->ipu_use_count == 1)
+		clk_enable(ipu->ipu_clk);
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+
+void ipu_put(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->ipu_channel_lock);
+
+	ipu->ipu_use_count--;
+
+	if (ipu->ipu_use_count == 0)
+		clk_disable(ipu->ipu_clk);
+
+	if (ipu->ipu_use_count < 0) {
+		dev_err(ipu->ipu_dev, "ipu use count < 0\n");
+		ipu->ipu_use_count = 0;
+	}
+
+	mutex_unlock(&ipu->ipu_channel_lock);
+}
+
+static void ipu_submodules_exit(struct platform_device *pdev,
+		unsigned long ipu_base)
+{
+	ipu_dp_exit(pdev);
+	ipu_dmfc_exit(pdev);
+	ipu_dc_exit(pdev);
+	ipu_di_exit(pdev, 1);
+	ipu_di_exit(pdev, 0);
+}
+
+static int ipu_add_subdevice_pdata(struct platform_device *pdev,
+		const char *name, int id, void *pdata, size_t pdata_size)
+{
+	struct mfd_cell cell = {
+		.platform_data = pdata,
+		.data_size = pdata_size,
+	};
+
+	cell.name = name;
+
+	return mfd_add_devices(&pdev->dev, id, &cell, 1, NULL, 0);
+}
+
+static int ipu_add_client_devices(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipuv3_fb_platform_data *fbdata;
+
+	fbdata = plat_data->fb_head0_platform_data;
+	if (fbdata) {
+		fbdata->ipu = (void *)ipu;
+		fbdata->ipu_channel_bg =
+			MX5_IPU_CHANNEL_MEM_BG_SYNC;
+		fbdata->ipu_channel_fg =
+			MX5_IPU_CHANNEL_MEM_FG_SYNC;
+		fbdata->dc_channel = 5;
+		fbdata->dp_channel = IPU_DP_FLOW_SYNC;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 0,
+				fbdata, sizeof(*fbdata));
+	}
+
+	fbdata = plat_data->fb_head1_platform_data;
+	if (fbdata) {
+		fbdata->ipu = (void *)ipu;
+		fbdata->ipu_channel_bg =
+			MX5_IPU_CHANNEL_MEM_DC_SYNC;
+		fbdata->ipu_channel_fg = -1;
+		fbdata->dc_channel = 1;
+		fbdata->dp_channel = -1;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 1,
+				fbdata, sizeof(*fbdata));
+	}
+
+	return 0;
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu;
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct resource *res;
+	int ret;
+
+	ipu = kzalloc(sizeof(struct ipu_soc), GFP_KERNEL);
+	if (!ipu)
+		return -ENOMEM;
+
+	spin_lock_init(&ipu->ipu_lock);
+	mutex_init(&ipu->ipu_channel_lock);
+	INIT_LIST_HEAD(&ipu->ipu_irq_handlers_list);
+
+	ipu->ipu_dev = &pdev->dev;
+
+	if (plat_data->init)
+		plat_data->init(pdev);
+
+	ipu->irq1 = platform_get_irq(pdev, 0);
+	ipu->irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || ipu->irq1 < 0 || ipu->irq2 < 0)
+		return -ENODEV;
+
+	ipu->ipu_base = res->start;
+
+	ipu->ipu_cm_reg = ioremap(ipu->ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_cm_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap1;
+	}
+
+	ipu->ipu_idmac_reg = ioremap(ipu->ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_idmac_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap2;
+	}
+
+	ipu->ipu_cpmem_reg = ioremap(ipu->ipu_base + IPU_CPMEM_REG_BASE, PAGE_SIZE);
+	if (!ipu->ipu_cpmem_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap3;
+	}
+
+	ipu->ipu_clk = clk_get(&pdev->dev, "ipu");
+	if (IS_ERR(ipu->ipu_clk)) {
+		ret = PTR_ERR(ipu->ipu_clk);
+		dev_err(&pdev->dev, "clk_get failed with %d", ret);
+		goto failed_clk_get;
+	}
+
+	ipu_get(ipu);
+
+	ret = request_irq(ipu->irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", ipu->irq1, ret);
+		goto failed_request_irq1;
+	}
+
+	ret = request_irq(ipu->irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", ipu->irq2, ret);
+		goto failed_request_irq2;
+	}
+
+	platform_set_drvdata(pdev, ipu);
+
+	ipu_reset(ipu);
+
+	ret = ipu_submodules_init(pdev, ipu->ipu_base);
+	if (ret)
+		goto failed_submodules_init;
+
+	/* Set sync refresh channels as high priority */
+	ipu_idmac_write(ipu, 0x18800000, IDMAC_CHA_PRI(0));
+
+	ret = ipu_add_client_devices(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "adding client devices failed with %d\n", ret);
+		goto failed_add_clients;
+	}
+
+	ipu_put(ipu);
+
+	return 0;
+
+failed_add_clients:
+	ipu_submodules_exit(pdev, ipu->ipu_base);
+failed_submodules_init:
+	free_irq(ipu->irq2, &pdev->dev);
+failed_request_irq2:
+	free_irq(ipu->irq1, &pdev->dev);
+	ipu_put(ipu);
+failed_request_irq1:
+	clk_put(ipu->ipu_clk);
+failed_clk_get:
+	iounmap(ipu->ipu_cpmem_reg);
+failed_ioremap3:
+	iounmap(ipu->ipu_idmac_reg);
+failed_ioremap2:
+	iounmap(ipu->ipu_cm_reg);
+failed_ioremap1:
+	kfree(ipu);
+
+	return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	mfd_remove_devices(&pdev->dev);
+	ipu_submodules_exit(pdev, ipu->ipu_base);
+	free_irq(ipu->irq2, &pdev->dev);
+	free_irq(ipu->irq1, &pdev->dev);
+	iounmap(ipu->ipu_cpmem_reg);
+	iounmap(ipu->ipu_idmac_reg);
+	iounmap(ipu->ipu_cm_reg);
+
+	if (ipu->ipu_use_count != 0) {
+		dev_err(ipu->ipu_dev,
+			"unbalanced use count: %d\n", ipu->ipu_use_count);
+		clk_disable(ipu->ipu_clk);
+	}
+
+	clk_put(ipu->ipu_clk);
+
+	kfree(ipu);
+
+	return 0;
+}
+
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+		.name = "imx-ipuv3",
+	},
+	.probe = ipu_probe,
+	.remove = __devexit_p(ipu_remove),
+};
+
+static int __init ipu_gen_init(void)
+{
+	int32_t ret;
+
+	ret = platform_driver_register(&mxcipu_driver);
+	return 0;
+}
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+	platform_driver_unregister(&mxcipu_driver);
+}
+module_exit(ipu_gen_uninit);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c
new file mode 100644
index 0000000..21aadb0
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dc.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define ASYNC_SER_WAVE 6
+
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+#define DC_MAP_CONF_PTR(n)	(0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	(0x0144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+
+#define DC_WR_CH_CONF(ch)      (channel_offset[ch])
+#define DC_WR_CH_ADDR(ch)      (channel_offset[ch] + 4)
+#define DC_RL_CH(ch, evt)      (channel_offset[ch] + 8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN			(0x00D4)
+#define DC_DISP_CONF1(disp)	(0x00D8 + disp * 4)
+#define DC_DISP_CONF2(disp)	(0x00E8 + disp * 4)
+#define DC_STAT			(0x01C8)
+
+#define WROD(lf)		(0x18 | (lf << 1))
+
+#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_OFFSET		5
+#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID_OFFSET	3
+#define DC_WR_CH_CONF_PROG_DISP_ID_MASK		(3 << 3)
+
+static int channel_offset[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4};
+
+static inline struct ipu_soc *dcchannel2ipu(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu;
+	struct dc_channel *dc_base = dc_chan - dc_chan->num;
+
+	ipu = container_of(dc_base, struct ipu_soc, dc.dc_channels[0]);
+
+	return ipu;
+}
+
+static inline u32 ipu_dc_read(struct ipu_dc *dc, unsigned offset)
+{
+	return readl(dc->reg_base + offset);
+}
+
+static inline void ipu_dc_write(struct ipu_dc *dc, u32 value, unsigned offset)
+{
+	writel(value, dc->reg_base + offset);
+}
+
+static void ipu_dc_link_event(struct ipu_dc *dc, int chan, int event, int addr, int priority)
+{
+	u32 reg;
+
+	reg = ipu_dc_read(dc, DC_RL_CH(chan, event));
+	reg &= ~(0xFFFF << (16 * (event & 0x1)));
+	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+	ipu_dc_write(dc, reg, DC_RL_CH(chan, event));
+}
+
+static void ipu_dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, int map,
+			       int wave, int glue, int sync)
+{
+	u32 reg;
+	int stop = 1;
+
+	reg = sync;
+	reg |= (glue << 4);
+	reg |= (++wave << 11);
+	reg |= (++map << 15);
+	reg |= (operand << 20) & 0xFFF00000;
+	writel(reg, dc->tmpl_base + word * 8);
+
+	reg = (operand >> 12);
+	reg |= opcode << 4;
+	reg |= (stop << 9);
+	writel(reg, dc->tmpl_base + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_RGB24:
+		return 0;
+	case IPU_PIX_FMT_RGB666:
+		return 1;
+	case IPU_PIX_FMT_YUV444:
+		return 2;
+	case IPU_PIX_FMT_RGB565:
+		return 3;
+	case IPU_PIX_FMT_LVDS666:
+		return 4;
+	}
+
+	return -EINVAL;
+}
+
+#define SYNC_WAVE 0
+
+int ipu_dc_init_sync(struct dc_channel *dc_chan, int di,
+		bool interlaced, u32 pixel_fmt, u32 width)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg = 0, map;
+
+	map = ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu->ipu_dev, "IPU_DISP: No MAP\n");
+		return -EINVAL;
+	}
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	dc_chan->di = di;
+
+	if (interlaced) {
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 0, 3);
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 0, 2);
+		ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 0, 1);
+
+		/* Init template microcode */
+		ipu_dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+	} else {
+		if (di) {
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 2, 3);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 3, 2);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 4, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		} else {
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NL, 5, 3);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOL, 6, 2);
+			ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA, 7, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		}
+	}
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NF, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NFIELD, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOF, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_EOFIELD, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_CHAN, 0, 0);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_ADDR, 0, 0);
+
+	reg = 0x2;
+	reg |= di << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	reg |= di << 2;
+	if (interlaced)
+		reg |= DC_WR_CH_CONF_FIELD_MODE;
+
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000000, DC_WR_CH_ADDR(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000084, DC_GEN);
+
+	ipu_dc_write(dc, width, DC_DISP_CONF2(di));
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
+
+void ipu_dc_init_async(struct dc_channel *dc_chan, int di, bool interlaced)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg = 0;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	dc_chan->di = di;
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+	ipu_dc_link_event(dc, dc_chan->num, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+	reg = 0x3;
+	reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000000, DC_WR_CH_ADDR(dc_chan->num));
+
+	ipu_dc_write(dc, 0x00000084, DC_GEN);
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_init_async);
+
+void ipu_dc_enable_channel(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	int di;
+	u32 reg;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dc->dc_mutex);
+
+	if (!dc->use_count)
+		ipu_module_enable(ipu, IPU_CONF_DC_EN);
+	dc->use_count++;
+
+	di = dc_chan->di;
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(6 - dc_chan->num));
+	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+		ipu_dc_write(dc, reg, DC_WR_CH_CONF(6 - dc_chan->num));
+	}
+
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(dc_chan->num));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	mutex_unlock(&dc->dc_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+	struct ipu_dc *dc = &ipu->dc;
+	u32 reg;
+	int irq = 0, ret;
+
+	if (dc->use_count <= 0) {
+		dc->use_count = 0;
+		return;
+	}
+
+	if (dc_chan->num == 1) {
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (dc_chan->num == 5) {
+		irq = IPU_IRQ_DP_SF_END;
+	} else {
+		return;
+	}
+
+	ret = ipu_wait_for_interrupt(ipu, irq, 50);
+	if (ret)
+		return;
+
+	mutex_lock(&dc->dc_mutex);
+
+	reg = ipu_dc_read(dc, DC_WR_CH_CONF(dc_chan->num));
+	reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	ipu_dc_write(dc, reg, DC_WR_CH_CONF(dc_chan->num));
+
+	dc->use_count--;
+	if (!dc->use_count)
+		ipu_module_disable(ipu, IPU_CONF_DC_EN);
+
+	mutex_unlock(&dc->dc_mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
+
+struct dc_channel *ipu_dc_get(struct ipu_soc *ipu, int chan)
+{
+	struct dc_channel *dc_chan;
+
+	if (chan >= IPU_DC_CHAN_NUM)
+		return ERR_PTR(-EINVAL);
+
+	dc_chan = &ipu->dc.dc_channels[chan];
+
+	mutex_lock(&ipu->dc.dc_mutex);
+
+	if (dc_chan->inuse) {
+		dc_chan = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	dc_chan->inuse = true;
+out:
+	mutex_unlock(&ipu->dc.dc_mutex);
+
+	return dc_chan;
+}
+EXPORT_SYMBOL_GPL(ipu_dc_get);
+
+void ipu_dc_put(struct dc_channel *dc_chan)
+{
+	struct ipu_soc *ipu = dcchannel2ipu(dc_chan);
+
+	mutex_lock(&ipu->dc.dc_mutex);
+
+	dc_chan->inuse = false;
+
+	mutex_unlock(&ipu->dc.dc_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dc_put);
+
+static void ipu_dc_map_config(struct ipu_dc *dc, int map,
+		int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = ipu_dc_read(dc, DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xffff << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	ipu_dc_write(dc, reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = ipu_dc_read(dc, DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	ipu_dc_write(dc, reg, DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(struct ipu_dc *dc, int map)
+{
+	u32 reg = ipu_dc_read(dc, DC_MAP_CONF_PTR(map));
+	ipu_dc_write(dc, reg & ~(0xffff << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long reg_base, unsigned long template_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	int i;
+
+	ipu->dc.reg_base = ioremap(reg_base, PAGE_SIZE);
+	if (!ipu->dc.reg_base)
+		return -ENOMEM;
+
+	ipu->dc.tmpl_base = ioremap(template_base, PAGE_SIZE);
+	if (!ipu->dc.tmpl_base) {
+		iounmap(ipu->dc.reg_base);
+		return -ENOMEM;
+	}
+
+	mutex_init(&ipu->dc.dc_mutex);
+
+	for (i = 0; i < IPU_DC_CHAN_NUM; i++) {
+		ipu->dc.dc_channels[i].num = i;
+		ipu->dc.dc_channels[i].inuse = false;
+	}
+
+	/* IPU_PIX_FMT_RGB24 */
+	ipu_dc_map_clear(&ipu->dc, 0);
+	ipu_dc_map_config(&ipu->dc, 0, 0, 7, 0xff);
+	ipu_dc_map_config(&ipu->dc, 0, 1, 15, 0xff);
+	ipu_dc_map_config(&ipu->dc, 0, 2, 23, 0xff);
+
+	/* IPU_PIX_FMT_RGB666 */
+	ipu_dc_map_clear(&ipu->dc, 1);
+	ipu_dc_map_config(&ipu->dc, 1, 0, 5, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 1, 1, 11, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 1, 2, 17, 0xfc);
+
+	/* IPU_PIX_FMT_YUV444 */
+	ipu_dc_map_clear(&ipu->dc, 2);
+	ipu_dc_map_config(&ipu->dc, 2, 0, 15, 0xff);
+	ipu_dc_map_config(&ipu->dc, 2, 1, 23, 0xff);
+	ipu_dc_map_config(&ipu->dc, 2, 2, 7, 0xff);
+
+	/* IPU_PIX_FMT_RGB565 */
+	ipu_dc_map_clear(&ipu->dc, 3);
+	ipu_dc_map_config(&ipu->dc, 3, 0, 4, 0xf8);
+	ipu_dc_map_config(&ipu->dc, 3, 1, 10, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 3, 2, 15, 0xf8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	ipu_dc_map_clear(&ipu->dc, 4);
+	ipu_dc_map_config(&ipu->dc, 4, 0, 5, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 4, 1, 13, 0xfc);
+	ipu_dc_map_config(&ipu->dc, 4, 2, 21, 0xfc);
+
+	return 0;
+}
+
+void ipu_dc_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	iounmap(ipu->dc.reg_base);
+	iounmap(ipu->dc.tmpl_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c
new file mode 100644
index 0000000..de8d0c0
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-di.c
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define SYNC_WAVE 0
+
+#define DC_DISP_ID_SYNC(di)	(di)
+
+struct di_sync_config {
+	int run_count;
+	int run_src;
+	int offset_count;
+	int offset_src;
+	int repeat_count;
+	int cnt_clr_src;
+	int cnt_polarity_gen_en;
+	int cnt_polarity_clr_src;
+	int cnt_polarity_trigger_src;
+	int cnt_up;
+	int cnt_down;
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = 0,
+	DI_SYNC_CLK = 1,
+	DI_SYNC_INT_HSYNC = 2,
+	DI_SYNC_HSYNC = 3,
+	DI_SYNC_VSYNC = 4,
+	DI_SYNC_DE = 6,
+};
+
+#define DI_GENERAL		0x0000
+#define DI_BS_CLKGEN0		0x0004
+#define DI_BS_CLKGEN1		0x0008
+#define DI_SW_GEN0(gen)		(0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		(0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN		0x0054
+#define DI_DW_GEN(gen)		(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	(0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF		0x015c
+#define DI_SSC			0x0160
+#define DI_POL			0x0164
+#define DI_AW0			0x0168
+#define DI_AW1			0x016c
+#define DI_SCR_CONF		0x0170
+#define DI_STAT			0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x)			((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x)			((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x)		((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x)		((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x)		((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x)		((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)	((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)		((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x)			((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x)			(x)
+#define DI_SW_GEN1_AUTO_RELOAD			(0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET		24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET		16
+
+#define DI_GEN_DI_CLK_EXT			(1 << 20)
+#define DI_GEN_POLARITY_1			(1 << 0)
+#define DI_GEN_POLARITY_2			(1 << 1)
+#define DI_GEN_POLARITY_3			(1 << 2)
+#define DI_GEN_POLARITY_4			(1 << 3)
+#define DI_GEN_POLARITY_5			(1 << 4)
+#define DI_GEN_POLARITY_6			(1 << 5)
+#define DI_GEN_POLARITY_7			(1 << 6)
+#define DI_GEN_POLARITY_8			(1 << 7)
+
+#define DI_POL_DRDY_DATA_POLARITY		(1 << 7)
+#define DI_POL_DRDY_POLARITY_15			(1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET			13
+
+#define DI0_COUNTER_RELEASE			(1 << 24)
+#define DI1_COUNTER_RELEASE			(1 << 25)
+
+static inline struct ipu_soc *di2ipu(struct ipu_di *di)
+{
+	struct ipu_soc *ipu;
+
+	if (0 == di->id)
+		ipu = container_of(di, struct ipu_soc, dis[0]);
+	else
+		ipu = container_of(di, struct ipu_soc, dis[1]);
+
+	return ipu;
+}
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+	return readl(di->reg_base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+	writel(value, di->reg_base + offset);
+}
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+				     int wave_gen,
+				     int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, int set,
+				    int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static int ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, int count)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct di_sync_config *c = &config[i];
+		int wave_gen = i + 1;
+
+		pr_debug("%s %d\n", __func__, wave_gen);
+		if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || (c->repeat_count >= 0x1000) ||
+			(c->cnt_up >= 0x400) || (c->cnt_down >= 0x400))
+			return -EINVAL;
+
+		reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+			DI_SW_GEN0_RUN_SRC(c->run_src) |
+			DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+			DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+		ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+		reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+			DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+			DI_SW_GEN1_CNT_POL_TRIGGER_SRC(c->cnt_polarity_trigger_src) |
+			DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+			DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+			DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+		if (c->repeat_count == 0) {
+			/* Enable auto reload */
+			reg |= DI_SW_GEN1_AUTO_RELOAD;
+		}
+
+		ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+		reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+		reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+		reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+		ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+	}
+	return 0;
+}
+
+static int ipu_di_sync_config_interlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width;
+	u32 reg;
+	int ret = 0;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total / 2 - 1,
+			.run_src = DI_SYNC_CLK,
+		}, {
+			.run_count = h_total - 11,
+			.run_src = DI_SYNC_CLK,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total * 2 - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = 1,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height / 2,
+			.cnt_clr_src = 4,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_HSYNC,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = 9,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = v_total / 2,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_clr_src = DI_SYNC_HSYNC,
+			.cnt_down = 4,
+		}
+	};
+
+	ret = ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+	if (ret < 0)
+		return ret;
+
+	/* set gentime select and tag sel */
+	reg = ipu_di_read(di, DI_SW_GEN1(9));
+	reg &= 0x1FFFFFFF;
+	reg |= (3 - 1) << 29 | 0x00008000;
+	ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+	ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+
+	return ret;
+}
+
+static int ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig, int div)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width + (sig->v_end_width < 2 ? 1 : 0);
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+		} , {
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+			.offset_count = div * sig->v_to_h_sync,
+			.offset_src = DI_SYNC_CLK,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_CLK,
+			.cnt_down = sig->h_sync_width * 2,
+		} , {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = sig->v_sync_width * 2,
+		} , {
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		} , {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		},
+	};
+
+	ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+	return ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, u32 pixel_clk, struct ipu_di_signal_cfg *sig)
+{
+	struct ipu_soc *ipu = di2ipu(di);
+	u32 reg;
+	u32 disp_gen, di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+	int ret = 0;
+	struct clk *di_clk;
+
+	dev_dbg(ipu->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;
+
+	mutex_lock(&di->di_mutex);
+
+	ipu_get(ipu);
+
+	/* Init clocking */
+	if (sig->ext_clk) {
+		di->external_clk = true;
+		di_clk = di->clk;
+	} else {
+		di->external_clk = false;
+		di_clk = ipu->ipu_clk;
+	}
+
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = (clk_get_rate(di_clk) * 16) / pixel_clk;
+	if (div < 0x10)	/* Min DI disp clock divider is 1 */
+		div = 0x10;
+
+	disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen &= di->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+	ipu_di_write(di, div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* Down time is half of period */
+	ipu_di_write(di, (div / 16) << 16, DI_BS_CLKGEN1);
+
+	ipu_di_data_wave_config(di, SYNC_WAVE, div / 16 - 1, div / 16 - 1);
+	ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div / 16 * 2);
+
+	div = div / 16;		/* Now divider is integer portion */
+
+	di_gen = 0;
+	if (sig->ext_clk)
+		di_gen |= DI_GEN_DI_CLK_EXT;
+
+	if (sig->interlaced) {
+		ret = ipu_di_sync_config_interlaced(di, sig);
+		if (ret < 0)
+			goto done;
+
+		/* set y_sel = 1 */
+		di_gen |= 0x10000000;
+		di_gen |= DI_GEN_POLARITY_5;
+		di_gen |= DI_GEN_POLARITY_8;
+
+		vsync_cnt = 7;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		ret = ipu_di_sync_config_noninterlaced(di, sig, div);
+		if (ret < 0)
+			goto done;
+
+		vsync_cnt = 3;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+	}
+
+	ipu_di_write(di, di_gen, DI_GENERAL);
+	ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+		     DI_SYNC_AS_GEN);
+
+	reg = ipu_di_read(di, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+	if (sig->enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig->data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+
+	ipu_di_write(di, reg, DI_POL);
+done:
+	ipu_put(ipu);
+
+	mutex_unlock(&di->di_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+	u32 reg;
+	struct ipu_soc *ipu = di2ipu(di);
+	unsigned long flags;
+
+	ipu_get(ipu);
+
+	ipu_module_enable(ipu, di->module);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+	if (di->id)
+		reg |= DI1_COUNTER_RELEASE;
+	else
+		reg |= DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	if (di->external_clk)
+		clk_enable(di->clk);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+	u32 reg;
+	struct ipu_soc *ipu = di2ipu(di);
+	unsigned long flags;
+
+	if (di->external_clk)
+		clk_disable(di->clk);
+
+	spin_lock_irqsave(&ipu->ipu_lock, flags);
+
+	reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+	if (di->id)
+		reg &= ~DI1_COUNTER_RELEASE;
+	else
+		reg &= ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+
+	spin_unlock_irqrestore(&ipu->ipu_lock, flags);
+
+	ipu_module_disable(ipu, di->module);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_disable);
+
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp)
+{
+	struct ipu_di *di;
+
+	if (disp > 1)
+		return ERR_PTR(-EINVAL);
+
+	di = &ipu->dis[disp];
+
+	mutex_lock(&di->di_mutex);
+
+	if (!di->initialized) {
+		di = ERR_PTR(-ENOSYS);
+		goto out;
+	}
+
+	if (di->inuse) {
+		di = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	di->inuse = true;
+out:
+	mutex_unlock(&di->di_mutex);
+
+	return di;
+}
+EXPORT_SYMBOL_GPL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+	mutex_lock(&di->di_mutex);
+
+	di->inuse = false;
+
+	mutex_unlock(&di->di_mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_di_put);
+
+int ipu_di_init(struct platform_device *pdev, int id,
+		unsigned long reg_base, u32 module)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	char *clkid;
+
+	if (id > 1)
+		return -EINVAL;
+
+	if (id)
+		clkid = "di1";
+	else
+		clkid = "di0";
+
+	mutex_init(&ipu->dis[id].di_mutex);
+
+	ipu->dis[id].clk = clk_get(&pdev->dev, clkid);
+	ipu->dis[id].module = module;
+	ipu->dis[id].id = id;
+	ipu->dis[id].reg_base = ioremap(reg_base, PAGE_SIZE);
+	ipu->dis[id].initialized = true;
+	ipu->dis[id].inuse = false;
+	if (!ipu->dis[id].reg_base)
+		return -ENOMEM;
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+	return 0;
+}
+
+void ipu_di_exit(struct platform_device *pdev, int id)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	clk_put(ipu->dis[id].clk);
+	iounmap(ipu->dis[id].reg_base);
+	ipu->dis[id].initialized = false;
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c
new file mode 100644
index 0000000..230ddbf
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN		0x0000
+#define DMFC_WR_CHAN		0x0004
+#define DMFC_WR_CHAN_DEF	0x0008
+#define DMFC_DP_CHAN		0x000c
+#define DMFC_DP_CHAN_DEF	0x0010
+#define DMFC_GENERAL1		0x0014
+#define DMFC_GENERAL2		0x0018
+#define DMFC_IC_CTRL		0x001c
+#define DMFC_STAT		0x0020
+
+#define DMFC_WR_CHAN_1_28		0
+#define DMFC_WR_CHAN_2_41		8
+#define DMFC_WR_CHAN_1C_42		16
+#define DMFC_WR_CHAN_2C_43		24
+
+#define DMFC_DP_CHAN_5B_23		0
+#define DMFC_DP_CHAN_5F_27		8
+#define DMFC_DP_CHAN_6B_24		16
+#define DMFC_DP_CHAN_6F_29		24
+
+#define DMFC_FIFO_SIZE_64		(3 << 3)
+#define DMFC_FIFO_SIZE_128		(2 << 3)
+#define DMFC_FIFO_SIZE_256		(1 << 3)
+#define DMFC_FIFO_SIZE_512		(0 << 3)
+
+#define DMFC_SEGMENT(x)			((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_32		(0 << 6)
+#define DMFC_BURSTSIZE_16		(1 << 6)
+#define DMFC_BURSTSIZE_8		(2 << 6)
+#define DMFC_BURSTSIZE_4		(3 << 6)
+
+static struct dmfc_channel dmfcs[] = {
+	{
+		.ipu_channel	= 23,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5B_23,
+		.eot_shift	= 20,
+		.max_fifo_lines	= 3,
+	}, {
+		.ipu_channel	= 24,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6B_24,
+		.eot_shift	= 22,
+		.max_fifo_lines	= 1,
+	}, {
+		.ipu_channel	= 27,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5F_27,
+		.eot_shift	= 21,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 28,
+		.channel_reg	= DMFC_WR_CHAN,
+		.shift		= DMFC_WR_CHAN_1_28,
+		.eot_shift	= 16,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 29,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6F_29,
+		.eot_shift	= 23,
+		.max_fifo_lines	= 1,
+	},
+};
+
+#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcs)
+
+static inline struct ipu_soc *dmfcchannel2ipu(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu;
+	struct dmfc_channel *dmfc_base = dmfc - dmfc->idx;
+
+	ipu = container_of(dmfc_base, struct ipu_soc, dmfc.dmfcs[0]);
+
+	return ipu;
+}
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+
+	ipu_get(ipu);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (!ipu->dmfc.use_count)
+		ipu_module_enable(ipu, IPU_CONF_DMFC_EN);
+
+	ipu->dmfc.use_count++;
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	ipu->dmfc.use_count--;
+
+	if (!ipu->dmfc.use_count)
+		ipu_module_disable(ipu, IPU_CONF_DMFC_EN);
+
+	if (ipu->dmfc.use_count < 0)
+		ipu->dmfc.use_count = 0;
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, int segment)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	u32 val, field;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+			slots, segment, dmfc->ipu_channel);
+
+	if (!dmfc)
+		return -EINVAL;
+
+	switch (slots) {
+	case 1:
+		field = DMFC_FIFO_SIZE_64;
+		break;
+	case 2:
+		field = DMFC_FIFO_SIZE_128;
+		break;
+	case 4:
+		field = DMFC_FIFO_SIZE_256;
+		break;
+	case 8:
+		field = DMFC_FIFO_SIZE_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	field |= DMFC_SEGMENT(segment) | DMFC_BURSTSIZE_8;
+
+	val = readl(ipu->dmfc.reg_base + dmfc->channel_reg);
+
+	val &= ~(0xff << dmfc->shift);
+	val |= field << dmfc->shift;
+
+	writel(val, ipu->dmfc.reg_base + dmfc->channel_reg);
+
+	dmfc->slots = slots;
+	dmfc->segment = segment;
+	dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+	return 0;
+}
+
+static int dmfc_bandwidth_to_slots(unsigned long bandwidth,
+		unsigned long dmfc_bandwidth_per_slot)
+{
+	int slots = 1;
+
+	while (slots * dmfc_bandwidth_per_slot < bandwidth)
+		slots *= 2;
+
+	return slots;
+}
+
+static int dmfc_find_slots(struct ipu_soc *ipu, int slots)
+{
+	unsigned slotmask_need, slotmask_used = 0;
+	int i, segment = 0;
+
+	slotmask_need = (1 << slots) - 1;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		slotmask_used |= ipu->dmfc.dmfcs[i].slotmask;
+
+	while (slotmask_need <= 0xff) {
+		if (!(slotmask_used & slotmask_need))
+			return segment;
+
+		slotmask_need <<= 1;
+		segment++;
+	}
+
+	return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	int i;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: freeing %d slots starting from segment %d\n",
+			dmfc->slots, dmfc->segment);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (!dmfc->slots)
+		goto out;
+
+	dmfc->slotmask = 0;
+	dmfc->slots = 0;
+	dmfc->segment = 0;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		ipu->dmfc.dmfcs[i].slotmask = 0;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++) {
+		if (ipu->dmfc.dmfcs[i].slots > 0) {
+			ipu->dmfc.dmfcs[i].segment = dmfc_find_slots(ipu, ipu->dmfc.dmfcs[i].slots);
+			ipu->dmfc.dmfcs[i].slotmask =
+				((1 << ipu->dmfc.dmfcs[i].slots) - 1) << ipu->dmfc.dmfcs[i].segment;
+		}
+	}
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++) {
+		if (ipu->dmfc.dmfcs[i].slots > 0)
+			ipu_dmfc_setup_channel(&ipu->dmfc.dmfcs[i],
+				ipu->dmfc.dmfcs[i].slots, ipu->dmfc.dmfcs[i].segment);
+	}
+out:
+	mutex_unlock(&ipu->dmfc.mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_pixel_per_second)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	int slots = dmfc_bandwidth_to_slots(bandwidth_pixel_per_second,
+			ipu->dmfc.dmfc_bandwidth_per_slot);
+	int segment = 0, ret = 0;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+			bandwidth_pixel_per_second / 1000000, dmfc->ipu_channel);
+	ipu_get(ipu);
+
+	ipu_dmfc_free_bandwidth(dmfc);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	if (slots > 8) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	segment = dmfc_find_slots(ipu, slots);
+	if (segment < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ipu_dmfc_setup_channel(dmfc, slots, segment);
+
+out:
+	ipu_put(ipu);
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+	struct ipu_soc *ipu = dmfcchannel2ipu(dmfc);
+	u32 dmfc_gen1;
+
+	ipu_get(ipu);
+
+	mutex_lock(&ipu->dmfc.mutex);
+
+	dmfc_gen1 = readl(ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	if ((dmfc->slots * 64 * 4) / width > dmfc->max_fifo_lines)
+		dmfc_gen1 |= 1 << dmfc->eot_shift;
+	else
+		dmfc_gen1 &= ~(1 << dmfc->eot_shift);
+
+	writel(dmfc_gen1, ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	mutex_unlock(&ipu->dmfc.mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel)
+{
+	int i;
+	struct ipu_dmfc *dmfc = &ipu->dmfc;
+
+	for (i = 0; i < ipu->dmfc.dmfc_num; i++)
+		if (dmfc->dmfcs[i].ipu_channel == ipu_channel)
+			return &dmfc->dmfcs[i];
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+	ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL_GPL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long reg_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	int i;
+
+	ipu->dmfc.reg_base = ioremap(reg_base, PAGE_SIZE);
+
+	if (!ipu->dmfc.reg_base)
+		return -ENOMEM;
+
+	writel(0x0, ipu->dmfc.reg_base + DMFC_WR_CHAN);
+	writel(0x0, ipu->dmfc.reg_base + DMFC_DP_CHAN);
+
+	ipu->dmfc.dmfc_num = DMFC_NUM_CHANNELS;
+	for (i = 0 ; i < ipu->dmfc.dmfc_num; i++) {
+		struct dmfc_channel *tmp = &(ipu->dmfc.dmfcs[i]);
+		memcpy(tmp, &dmfcs[i], sizeof(struct dmfc_channel));
+		tmp->idx = i;
+	}
+
+	mutex_init(&ipu->dmfc.mutex);
+
+	/*
+	 * We have a total bandwidth of clkrate * 4pixel divided
+	 * into 8 slots.
+	 */
+	ipu->dmfc.dmfc_bandwidth_per_slot = clk_get_rate(ipu->ipu_clk) / 4;
+
+	dev_dbg(ipu->ipu_dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+			ipu->dmfc.dmfc_bandwidth_per_slot / 1000000);
+
+	writel(0x202020f6, ipu->dmfc.reg_base + DMFC_WR_CHAN_DEF);
+	writel(0x2020f6f6, ipu->dmfc.reg_base + DMFC_DP_CHAN_DEF);
+	writel(0x00000003, ipu->dmfc.reg_base + DMFC_GENERAL1);
+
+	return 0;
+}
+
+void ipu_dmfc_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	iounmap(ipu->dmfc.reg_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c
new file mode 100644
index 0000000..cbf6494
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dp.c
@@ -0,0 +1,507 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <video/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF(flow)		(flow)
+#define DP_GRAPH_WIND_CTRL(flow)	(0x0004 + flow)
+#define DP_FG_POS(flow)			(0x0008 + flow)
+#define DP_CSC_A_0(flow)		(0x0044 + flow)
+#define DP_CSC_A_1(flow)		(0x0048 + flow)
+#define DP_CSC_A_2(flow)		(0x004C + flow)
+#define DP_CSC_A_3(flow)		(0x0050 + flow)
+#define DP_CSC_0(flow)			(0x0054 + flow)
+#define DP_CSC_1(flow)			(0x0058 + flow)
+
+#define DP_COM_CONF_FG_EN		(1 << 0)
+#define DP_COM_CONF_GWSEL		(1 << 1)
+#define DP_COM_CONF_GWAM		(1 << 2)
+#define DP_COM_CONF_GWCKE		(1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET	8
+#define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+/*     Y = R *  .299 + G *  .587 + B *  .114;
+       U = R * -.169 + G * -.332 + B *  .500 + 128.;
+       V = R *  .500 + G * -.419 + B * -.0813 + 128.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{ 153, 301, 58, },
+	{ -87, -170, 0x0100, },
+	{ 0x100, -215, -42, },
+	{ 0x0000, 0x0200, 0x0200, },	/* B0, B1, B2 */
+	{ 0x2, 0x2, 0x2, },	/* S0, S1, S2 */
+};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+	{ 0x095, 0x000, 0x0CC, },
+	{ 0x095, 0x3CE, 0x398, },
+	{ 0x095, 0x0FF, 0x000, },
+	{ 0x3E42, 0x010A, 0x3DD6, },	/*B0,B1,B2 */
+	{ 0x1, 0x1, 0x1, },	/*S0,S1,S2 */
+};
+
+static inline struct ipu_soc *dp2ipu(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu;
+
+	ipu = container_of(dp, struct ipu_soc, dp);
+
+	return ipu;
+}
+
+static inline u32 ipu_dp_read(struct ipu_dp *dp, unsigned offset)
+{
+	return readl(dp->reg_base + offset);
+}
+
+static inline void ipu_dp_write(struct ipu_dp *dp, u32 value, unsigned offset)
+{
+	writel(value, dp->reg_base + offset);
+}
+
+/* Please keep S0, S1 and S2 as 0x2 by using this conversion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+	int c;
+
+	c = red * rgb2ycbcr_coeff[n][0];
+	c += green * rgb2ycbcr_coeff[n][1];
+	c += blue * rgb2ycbcr_coeff[n][2];
+	c /= 16;
+	c += rgb2ycbcr_coeff[3][n] * 4;
+	c += 8;
+	c /= 16;
+	if (c < 0)
+		c = 0;
+	if (c > 255)
+		c = 255;
+	return c;
+}
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+/*
+ * Row is for BG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+	{
+		{ DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}
+};
+
+static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
+
+static int color_key_4rgb = 1;
+
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 color_key)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+	int y, u, v;
+	int red, green, blue;
+
+	mutex_lock(&dp->mutex);
+
+	color_key_4rgb = 1;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
+
+		dev_dbg(ipu->ipu_dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu->ipu_dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFF000000L;
+		ipu_dp_write(dp, reg | color_key, DP_GRAPH_WIND_CTRL(DP_SYNC));
+
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg | DP_COM_CONF_GWCKE, DP_COM_CONF(DP_SYNC));
+	} else {
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(DP_SYNC));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_color_key);
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, bool bg_chan)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	if (bg_chan)
+		reg &= ~DP_COM_CONF_GWSEL;
+	else
+		reg |= DP_COM_CONF_GWSEL;
+	ipu_dp_write(dp, reg, DP_COM_CONF(DP_SYNC));
+
+	if (enable) {
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0x00FFFFFFL;
+		ipu_dp_write(dp, reg | ((u32) alpha << 24), DP_GRAPH_WIND_CTRL(DP_SYNC));
+
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg | DP_COM_CONF_GWAM, DP_COM_CONF(DP_SYNC));
+	} else {
+		reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(dp, reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(DP_SYNC));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	ipu_dp_write(dp, (x_pos << 16) | y_pos, DP_FG_POS(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos);
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+void __ipu_dp_csc_setup(struct ipu_dp *dp, int flow,
+			struct dp_csc_param_t dp_csc_param,
+			bool srm_mode_update)
+{
+	u32 reg;
+	struct ipu_soc *ipu = dp2ipu(dp);
+	const int (*coeff)[5][3];
+
+	if (dp_csc_param.mode >= 0) {
+		reg = ipu_dp_read(dp, DP_COM_CONF(flow));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		ipu_dp_write(dp, reg, DP_COM_CONF(flow));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		ipu_dp_write(dp, mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(flow));
+		ipu_dp_write(dp, mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(flow));
+		ipu_dp_write(dp, mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+				(mask_b((*coeff)[3][2]) << 16) |
+				((*coeff)[4][2] << 30), DP_CSC_1(flow));
+	}
+
+	if (srm_mode_update) {
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	int in_fmt, out_fmt;
+	enum csc_type_t *csc_type;
+	u32 reg;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	if (bg)
+		csc_type = &bg_csc_type;
+	else
+		csc_type = &fg_csc_type;
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (in_fmt == RGB) {
+		if (out_fmt == RGB)
+			*csc_type = RGB2RGB;
+		else
+			*csc_type = RGB2YUV;
+	} else {
+		if (out_fmt == RGB)
+			*csc_type = YUV2RGB;
+		else
+			*csc_type = YUV2YUV;
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		u32 color_key = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFFFFFFL;
+
+		dev_dbg(ipu->ipu_dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		reg = ipu_dp_read(dp, DP_GRAPH_WIND_CTRL(DP_SYNC)) & 0xFF000000L;
+		ipu_dp_write(dp, reg | color_key, DP_GRAPH_WIND_CTRL(DP_SYNC));
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu->ipu_dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(dp, DP_SYNC, dp_csc_array[bg_csc_type][fg_csc_type], true);
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	if (!dp->use_count)
+		ipu_module_enable(ipu, IPU_CONF_DP_EN);
+
+	dp->use_count++;
+
+	mutex_unlock(&dp->mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+
+	mutex_lock(&dp->mutex);
+
+	dp->use_count--;
+
+	if (!dp->use_count)
+		ipu_module_disable(ipu, IPU_CONF_DP_EN);
+
+	if (dp->use_count < 0)
+		dp->use_count = 0;
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_channel);
+
+void ipu_dp_enable_fg(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg;
+
+	mutex_lock(&dp->mutex);
+
+	/* Enable FG channel */
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	ipu_dp_write(dp, reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_enable_fg);
+
+void ipu_dp_disable_fg(struct ipu_dp *dp)
+{
+	struct ipu_soc *ipu = dp2ipu(dp);
+	u32 reg, csc;
+
+	ipu_get(ipu);
+
+	mutex_lock(&dp->mutex);
+
+	reg = ipu_dp_read(dp, DP_COM_CONF(DP_SYNC));
+	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_FG)
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+	reg &= ~DP_COM_CONF_FG_EN;
+	ipu_dp_write(dp, reg, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp->mutex);
+
+	ipu_put(ipu);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_disable_fg);
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu)
+{
+	mutex_lock(&ipu->dp.mutex);
+
+	if (ipu->dp.in_use)
+		return ERR_PTR(-EBUSY);
+
+	ipu->dp.in_use = true;
+
+	mutex_unlock(&ipu->dp.mutex);
+
+	return &ipu->dp;
+}
+EXPORT_SYMBOL_GPL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+	mutex_lock(&dp->mutex);
+	dp->in_use = false;
+	mutex_unlock(&dp->mutex);
+}
+EXPORT_SYMBOL_GPL(ipu_dp_put);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long reg_base)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	ipu->dp.reg_base = ioremap(reg_base, PAGE_SIZE);
+	if (!ipu->dp.reg_base)
+		return -ENOMEM;
+
+	mutex_init(&ipu->dp.mutex);
+
+	return 0;
+}
+
+void ipu_dp_exit(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+	iounmap(ipu->dp.reg_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h
new file mode 100644
index 0000000..f22bd7d
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-prv.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+
+#define MX5_IPU_CHANNEL_CSI0			 0
+#define MX5_IPU_CHANNEL_CSI1			 1
+#define MX5_IPU_CHANNEL_CSI2			 2
+#define MX5_IPU_CHANNEL_CSI3			 3
+#define MX5_IPU_CHANNEL_MEM_BG_SYNC		23
+#define MX5_IPU_CHANNEL_MEM_FG_SYNC		27
+#define MX5_IPU_CHANNEL_MEM_DC_SYNC		28
+#define MX5_IPU_CHANNEL_MEM_FG_SYNC_ALPHA	31
+#define MX5_IPU_CHANNEL_MEM_DC_ASYNC		41
+#define MX5_IPU_CHANNEL_ROT_ENC_MEM		45
+#define MX5_IPU_CHANNEL_ROT_VF_MEM		46
+#define MX5_IPU_CHANNEL_ROT_PP_MEM		47
+#define MX5_IPU_CHANNEL_ROT_ENC_MEM_OUT	48
+#define MX5_IPU_CHANNEL_ROT_VF_MEM_OUT		49
+#define MX5_IPU_CHANNEL_ROT_PP_MEM_OUT		50
+#define MX5_IPU_CHANNEL_MEM_BG_SYNC_ALPHA	51
+
+#define IPU_DISP0_BASE		0x00000000
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_DISP1_BASE		(IPU_MCU_T_DEFAULT << 25)
+#define IPU_CM_REG_BASE		0x1e000000
+#define IPU_IDMAC_REG_BASE	0x1e008000
+#define IPU_ISP_REG_BASE	0x1e010000
+#define IPU_DP_REG_BASE		0x1e018000
+#define IPU_IC_REG_BASE		0x1e020000
+#define IPU_IRT_REG_BASE	0x1e028000
+#define IPU_CSI0_REG_BASE	0x1e030000
+#define IPU_CSI1_REG_BASE	0x1e038000
+#define IPU_DI0_REG_BASE	0x1e040000
+#define IPU_DI1_REG_BASE	0x1e048000
+#define IPU_SMFC_REG_BASE	0x1e050000
+#define IPU_DC_REG_BASE		0x1e058000
+#define IPU_DMFC_REG_BASE	0x1e060000
+#define IPU_CPMEM_REG_BASE	0x1f000000
+#define IPU_LUT_REG_BASE	0x1f020000
+#define IPU_SRM_REG_BASE	0x1f040000
+#define IPU_TPM_REG_BASE	0x1f060000
+#define IPU_DC_TMPL_REG_BASE	0x1f080000
+#define IPU_ISP_TBPR_REG_BASE	0x1f0c0000
+#define IPU_VDI_REG_BASE	0x1e068000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)	(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00b8)
+#define IPU_SKIP			IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00d4)
+#define IPU_SNOOP			IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00dc)
+#define IPU_PM				IPU_CM_REG(0x00e0)
+#define IPU_GPR				IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT			IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT		IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_CTRL_IRQ(irq)	IPU_INT_CTRL(((irq) / 32))
+#define IPU_INT_STAT_IRQ(irq)	IPU_INT_STAT(((irq) / 32))
+#define IPU_INT_STAT(n)		IPU_CM_REG(0x0200 + 4 * ((n) - 1))
+
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)		IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA			IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA		IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)		IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)			IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1		IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2		IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0		IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1		IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2		IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch)		IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch)		IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+enum ipu_modules {
+	IPU_CONF_CSI0_EN		= (1 << 0),
+	IPU_CONF_CSI1_EN		= (1 << 1),
+	IPU_CONF_IC_EN			= (1 << 2),
+	IPU_CONF_ROT_EN			= (1 << 3),
+	IPU_CONF_ISP_EN			= (1 << 4),
+	IPU_CONF_DP_EN			= (1 << 5),
+	IPU_CONF_DI0_EN			= (1 << 6),
+	IPU_CONF_DI1_EN			= (1 << 7),
+	IPU_CONF_SMFC_EN		= (1 << 8),
+	IPU_CONF_DC_EN			= (1 << 9),
+	IPU_CONF_DMFC_EN		= (1 << 10),
+
+	IPU_CONF_VDI_EN			= (1 << 12),
+
+	IPU_CONF_IDMAC_DIS		= (1 << 22),
+
+	IPU_CONF_IC_DMFC_SEL		= (1 << 25),
+	IPU_CONF_IC_DMFC_SYNC		= (1 << 26),
+	IPU_CONF_VDI_DMFC_SYNC		= (1 << 27),
+
+	IPU_CONF_CSI0_DATA_SOURCE	= (1 << 28),
+	IPU_CONF_CSI1_DATA_SOURCE	= (1 << 29),
+	IPU_CONF_IC_INPUT		= (1 << 30),
+	IPU_CONF_CSI_SEL		= (1 << 31),
+};
+
+struct ipu_di {
+	int id;
+	u32 module;
+	struct clk *clk;
+	bool external_clk;
+	bool inuse;
+	bool initialized;
+	void __iomem *reg_base;
+	struct mutex di_mutex;
+};
+
+struct ipu_dc {
+#define IPU_DC_CHAN_NUM	10
+	struct dc_channel {
+		bool inuse;
+		unsigned int num;
+		unsigned int di; /* The display interface number assigned to this dc channel */
+	} dc_channels[IPU_DC_CHAN_NUM];
+	int use_count;
+	void __iomem *reg_base;
+	void __iomem *tmpl_base;
+	struct mutex dc_mutex;
+};
+
+struct dmfc_channel {
+	int		idx;
+	int		ipu_channel;
+	unsigned long	channel_reg;
+	unsigned long	shift;
+	unsigned	eot_shift;
+	unsigned	slots;
+	unsigned	max_fifo_lines;
+	unsigned	slotmask;
+	unsigned	segment;
+};
+
+struct ipu_dmfc {
+	int use_count;
+	void __iomem *reg_base;
+	unsigned long dmfc_bandwidth_per_slot;
+	struct mutex mutex;
+#define IPU_DMFC_CHAN_NUM	8
+	int dmfc_num;
+	struct dmfc_channel dmfcs[IPU_DMFC_CHAN_NUM];
+};
+
+struct ipu_dp {
+	int use_count;
+	void __iomem *reg_base;
+	struct mutex mutex;
+	bool in_use;
+};
+
+struct ipu_channel {
+	unsigned int num;
+
+	bool enabled;
+	bool busy;
+};
+
+struct ipu_soc {
+	struct device *ipu_dev;
+	struct clk *ipu_clk;
+	spinlock_t ipu_lock;
+	unsigned long ipu_base;
+	int irq1;
+	int irq2;
+
+	struct list_head ipu_irq_handlers_list;
+	int ipu_use_count;
+
+	void __iomem *ipu_cm_reg;
+	void __iomem *ipu_idmac_reg;
+	void __iomem *ipu_cpmem_reg;
+
+#define IPU_IDMA_CHAN_NUM	64
+	struct ipu_channel channels[IPU_IDMA_CHAN_NUM];
+	struct mutex ipu_channel_lock;
+
+	struct ipu_di dis[2];
+	struct ipu_dc dc;
+	struct ipu_dmfc dmfc;
+	struct ipu_dp dp;
+};
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ipu_cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ipu_cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ipu_idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ipu_idmac_reg + offset);
+}
+
+#define idmac_idma_is_set(ipu, reg, dma)(ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma))
+#define idma_mask(ch)			(1 << (ch & 0x1f))
+#define ipu_idma_is_set(ipu, reg, dma)	(ipu_cm_read(ipu, reg(dma)) & idma_mask(dma))
+
+ipu_color_space_t format_to_colorspace(u32 fmt);
+bool ipu_pixel_format_has_alpha(u32 fmt);
+
+u32 _ipu_channel_status(struct ipu_channel *channel);
+
+int _ipu_chan_is_interlaced(struct ipu_channel *channel);
+
+int ipu_module_enable(struct ipu_soc *ipu, u32 mask);
+int ipu_module_disable(struct ipu_soc *ipu, u32 mask);
+
+int ipu_di_init(struct platform_device *pdev, int id,
+		unsigned long base, u32 module);
+void ipu_di_exit(struct platform_device *pdev, int id);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base);
+void ipu_dmfc_exit(struct platform_device *pdev);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base);
+void ipu_dp_exit(struct platform_device *pdev);
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base,
+		unsigned long template_base);
+void ipu_dc_exit(struct platform_device *pdev);
+
+void ipu_get(struct ipu_soc *ipu);
+void ipu_put(struct ipu_soc *ipu);
+
+#endif				/* __IPU_PRV_H__ */
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
new file mode 100644
index 0000000..4928dba
--- /dev/null
+++ b/include/video/imx-ipu-v3.h
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+typedef enum {
+	/* Note the enum values correspond to BAM value */
+	IPU_ROTATE_NONE = 0,
+	IPU_ROTATE_VERT_FLIP = 1,
+	IPU_ROTATE_HORIZ_FLIP = 2,
+	IPU_ROTATE_180 = 3,
+	IPU_ROTATE_90_RIGHT = 4,
+	IPU_ROTATE_90_RIGHT_VFLIP = 5,
+	IPU_ROTATE_90_RIGHT_HFLIP = 6,
+	IPU_ROTATE_90_LEFT = 7,
+} ipu_rotate_mode_t;
+
+/*
+ * IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/* Generic or Raw Data Formats */
+#define IPU_PIX_FMT_GENERIC v4l2_fourcc('I', 'P', 'U', '0')	/* IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 v4l2_fourcc('I', 'P', 'U', '1')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 v4l2_fourcc('L', 'V', 'D', '6')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 v4l2_fourcc('L', 'V', 'D', '8')	/* IPU Generic Data */
+/* RGB Formats */
+#define IPU_PIX_FMT_RGB332  V4L2_PIX_FMT_RGB332			/*  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  V4L2_PIX_FMT_RGB555			/* 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  V4L2_PIX_FMT_RGB565			/* 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  v4l2_fourcc('R', 'G', 'B', '6')	/* 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', '6')	/* 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   V4L2_PIX_FMT_BGR24			/* 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   V4L2_PIX_FMT_RGB24			/* 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_BGR32   V4L2_PIX_FMT_BGR32			/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  v4l2_fourcc('B', 'G', 'R', 'A')	/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   V4L2_PIX_FMT_RGB32			/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  v4l2_fourcc('R', 'G', 'B', 'A')	/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  v4l2_fourcc('A', 'B', 'G', 'R')	/* 32  ABGR-8-8-8-8 */
+/* YUV Interleaved Formats */
+#define IPU_PIX_FMT_YUYV    V4L2_PIX_FMT_YUYV			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    V4L2_PIX_FMT_UYVY			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_Y41P    V4L2_PIX_FMT_Y41P			/* 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  V4L2_PIX_FMT_YUV444			/* 24 YUV 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    V4L2_PIX_FMT_NV12			/* 12  Y/CbCr 4:2:0  */
+/* YUV Planar Formats */
+#define IPU_PIX_FMT_GREY    V4L2_PIX_FMT_GREY			/* 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P V4L2_PIX_FMT_YVU410P		/* 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P V4L2_PIX_FMT_YUV410P		/* 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P v4l2_fourcc('Y', 'V', '1', '2')	/* 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P v4l2_fourcc('I', '4', '2', '0')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 v4l2_fourcc('Y', 'U', '1', '2')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P v4l2_fourcc('Y', 'V', '1', '6')	/* 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P V4L2_PIX_FMT_YUV422P		/* 16 YUV 4:2:2 */
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+	unsigned datamask_en:1;
+	unsigned ext_clk:1;
+	unsigned interlaced:1;
+	unsigned odd_field_first:1;
+	unsigned clksel_en:1;
+	unsigned clkidle_en:1;
+	unsigned data_pol:1;	/* true = inverted */
+	unsigned clk_pol:1;	/* true = rising edge */
+	unsigned enable_pol:1;
+	unsigned Hsync_pol:1;	/* true = active high */
+	unsigned Vsync_pol:1;
+
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u16 h_start_width;
+	u16 h_sync_width;
+	u16 h_end_width;
+	u16 v_start_width;
+	u16 v_sync_width;
+	u16 v_end_width;
+	u32 v_to_h_sync;
+};
+
+typedef enum {
+	RGB,
+	YCbCr,
+	YUV
+} ipu_color_space_t;
+
+#define IPU_IRQ_EOF(channel)		(channel)		/* 0 .. 63 */
+#define IPU_IRQ_NFACK(channel)		((channel) + 64)	/* 64 .. 127 */
+#define IPU_IRQ_NFB4EOF(channel)	((channel) + 128)	/* 128 .. 191 */
+#define IPU_IRQ_EOS(channel)		((channel) + 192)	/* 192 .. 255 */
+
+#define IPU_IRQ_DP_SF_START		(448 + 2)
+#define IPU_IRQ_DP_SF_END		(448 + 3)
+#define IPU_IRQ_BG_SF_END		IPU_IRQ_DP_SF_END
+#define IPU_IRQ_DC_FC_0			(448 + 8)
+#define IPU_IRQ_DC_FC_1			(448 + 9)
+#define IPU_IRQ_DC_FC_2			(448 + 10)
+#define IPU_IRQ_DC_FC_3			(448 + 11)
+#define IPU_IRQ_DC_FC_4			(448 + 12)
+#define IPU_IRQ_DC_FC_6			(448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0		(448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
+
+#define IPU_IRQ_COUNT	(15 * 32)
+
+#define DECLARE_IPU_IRQ_BITMAP(name)	DECLARE_BITMAP(name, IPU_IRQ_COUNT)
+
+struct ipu_irq_handler {
+	struct list_head	list;
+	void			(*handler)(unsigned long *, void *);
+	void			*context;
+	DECLARE_IPU_IRQ_BITMAP(ipu_irqs);
+};
+
+struct ipu_soc;
+
+int ipu_irq_add_handler(struct ipu_soc *ipu, struct ipu_irq_handler *ipuirq);
+void ipu_irq_remove_handler(struct ipu_soc *ipu, struct ipu_irq_handler *handler);
+int ipu_irq_update_handler(struct ipu_soc *ipu,
+		struct ipu_irq_handler *handler,
+		unsigned long *bitmap);
+int ipu_wait_for_interrupt(struct ipu_soc *ipu, int interrupt, int timeout_ms);
+
+struct ipu_channel;
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipu_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num);
+void ipu_idmac_put(struct ipu_channel *);
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u_offset, u32 v_offset, bool interlaced);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 bufNum, dma_addr_t phyaddr);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel);
+int ipu_idmac_disable_channel(struct ipu_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+struct dc_channel;
+struct dc_channel *ipu_dc_get(struct ipu_soc *ipu, int chan);
+void ipu_dc_put(struct dc_channel *dc_chan);
+int ipu_dc_init_sync(struct dc_channel *dc_chan, int di,
+		bool interlaced, u32 pixel_fmt, u32 width);
+void ipu_dc_init_async(struct dc_channel *dc_chan, int di, bool interlaced);
+void ipu_dc_enable_channel(struct dc_channel *dc_chan);
+void ipu_dc_disable_channel(struct dc_channel *dc_chan);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di;
+struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp);
+void ipu_di_put(struct ipu_di *di);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, u32 pixel_clk,
+		struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, unsigned long bandwidth_mbs);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC	0
+#define IPU_DP_FLOW_ASYNC0	1
+#define IPU_DP_FLOW_ASYNC1	2
+
+struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+void ipu_dp_enable_fg(struct ipu_dp *dp);
+void ipu_dp_disable_fg(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 colorKey);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+		bool bg_chan);
+
+#endif
-- 
1.7.1

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
  2011-02-16 14:10   ` Sascha Hauer
  (?)
@ 2011-02-21  5:38     ` Jason Chen
  -1 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-02-21  5:38 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, linux-kernel, linux-fbdev, Paul Mundt, Samuel Ortiz

hi, Sascha,

I have few comments for this patch.

> +#define MX51_IPU_CHANNEL_CSI0                   0
> +#define MX51_IPU_CHANNEL_CSI1                   1
> +#define MX51_IPU_CHANNEL_CSI2                   2
> +#define MX51_IPU_CHANNEL_CSI3                   3
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC           23
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC           27
> +#define MX51_IPU_CHANNEL_MEM_DC_SYNC           28
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC_ALPHA     31
> +#define MX51_IPU_CHANNEL_MEM_DC_ASYNC          41
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM           45
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM            46
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM            47
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM_OUT       48
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM_OUT                49
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM_OUT                50
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC_ALPHA     51
Had better use MX5_IPU as prefix because it's same value in MX5X.

> +
> +       ipu_idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
> +       if (!ipu_idmac_reg) {
> +               ret = -ENOMEM;
> +               goto failed_ioremap2;
> +       }
> +
> +       ret = ipu_mipi_setup();
> +       if (ret)
> +               goto failed_mipi_setup;
I dont know what's the best way to do it, but I think you had better
consider mx53 platform, so maybe this mipi_setup function and also
below ipu hw reset could be set in platform data.
> +
> +       ipu_clk = clk_get(&pdev->dev, "ipu");
> +       if (IS_ERR(ipu_clk)) {
> +               ret = PTR_ERR(ipu_clk);
> +               dev_err(&pdev->dev, "clk_get failed with %d", ret);
> +               goto failed_clk_get;
> +       }
> +
> +       ipu_get();
> +
> +       ret = request_irq(irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> +                       &pdev->dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq1, ret);
> +               goto failed_request_irq1;
> +       }
> +
> +       ret = request_irq(irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> +                       &pdev->dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq2, ret);
> +               goto failed_request_irq2;
> +       }
> +
> +       ipu_reset();

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-21  5:38     ` Jason Chen
  0 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-02-21  5:38 UTC (permalink / raw)
  To: linux-arm-kernel

hi, Sascha,

I have few comments for this patch.

> +#define MX51_IPU_CHANNEL_CSI0                   0
> +#define MX51_IPU_CHANNEL_CSI1                   1
> +#define MX51_IPU_CHANNEL_CSI2                   2
> +#define MX51_IPU_CHANNEL_CSI3                   3
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC           23
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC           27
> +#define MX51_IPU_CHANNEL_MEM_DC_SYNC           28
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC_ALPHA     31
> +#define MX51_IPU_CHANNEL_MEM_DC_ASYNC          41
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM           45
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM            46
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM            47
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM_OUT       48
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM_OUT                49
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM_OUT                50
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC_ALPHA     51
Had better use MX5_IPU as prefix because it's same value in MX5X.

> +
> +       ipu_idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
> +       if (!ipu_idmac_reg) {
> +               ret = -ENOMEM;
> +               goto failed_ioremap2;
> +       }
> +
> +       ret = ipu_mipi_setup();
> +       if (ret)
> +               goto failed_mipi_setup;
I dont know what's the best way to do it, but I think you had better
consider mx53 platform, so maybe this mipi_setup function and also
below ipu hw reset could be set in platform data.
> +
> +       ipu_clk = clk_get(&pdev->dev, "ipu");
> +       if (IS_ERR(ipu_clk)) {
> +               ret = PTR_ERR(ipu_clk);
> +               dev_err(&pdev->dev, "clk_get failed with %d", ret);
> +               goto failed_clk_get;
> +       }
> +
> +       ipu_get();
> +
> +       ret = request_irq(irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> +                       &pdev->dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq1, ret);
> +               goto failed_request_irq1;
> +       }
> +
> +       ret = request_irq(irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> +                       &pdev->dev);
> +       if (ret) {
> +               dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq2, ret);
> +               goto failed_request_irq2;
> +       }
> +
> +       ipu_reset();

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-21  5:38     ` Jason Chen
  0 siblings, 0 replies; 32+ messages in thread
From: Jason Chen @ 2011-02-21  5:38 UTC (permalink / raw)
  To: linux-arm-kernel

hi, Sascha,

I have few comments for this patch.

> +#define MX51_IPU_CHANNEL_CSI0 ? ? ? ? ? ? ? ? ? 0
> +#define MX51_IPU_CHANNEL_CSI1 ? ? ? ? ? ? ? ? ? 1
> +#define MX51_IPU_CHANNEL_CSI2 ? ? ? ? ? ? ? ? ? 2
> +#define MX51_IPU_CHANNEL_CSI3 ? ? ? ? ? ? ? ? ? 3
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC ? ? ? ? ? 23
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC ? ? ? ? ? 27
> +#define MX51_IPU_CHANNEL_MEM_DC_SYNC ? ? ? ? ? 28
> +#define MX51_IPU_CHANNEL_MEM_FG_SYNC_ALPHA ? ? 31
> +#define MX51_IPU_CHANNEL_MEM_DC_ASYNC ? ? ? ? ?41
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM ? ? ? ? ? 45
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM ? ? ? ? ? ?46
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM ? ? ? ? ? ?47
> +#define MX51_IPU_CHANNEL_ROT_ENC_MEM_OUT ? ? ? 48
> +#define MX51_IPU_CHANNEL_ROT_VF_MEM_OUT ? ? ? ? ? ? ? ?49
> +#define MX51_IPU_CHANNEL_ROT_PP_MEM_OUT ? ? ? ? ? ? ? ?50
> +#define MX51_IPU_CHANNEL_MEM_BG_SYNC_ALPHA ? ? 51
Had better use MX5_IPU as prefix because it's same value in MX5X.

> +
> + ? ? ? ipu_idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
> + ? ? ? if (!ipu_idmac_reg) {
> + ? ? ? ? ? ? ? ret = -ENOMEM;
> + ? ? ? ? ? ? ? goto failed_ioremap2;
> + ? ? ? }
> +
> + ? ? ? ret = ipu_mipi_setup();
> + ? ? ? if (ret)
> + ? ? ? ? ? ? ? goto failed_mipi_setup;
I dont know what's the best way to do it, but I think you had better
consider mx53 platform, so maybe this mipi_setup function and also
below ipu hw reset could be set in platform data.
> +
> + ? ? ? ipu_clk = clk_get(&pdev->dev, "ipu");
> + ? ? ? if (IS_ERR(ipu_clk)) {
> + ? ? ? ? ? ? ? ret = PTR_ERR(ipu_clk);
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "clk_get failed with %d", ret);
> + ? ? ? ? ? ? ? goto failed_clk_get;
> + ? ? ? }
> +
> + ? ? ? ipu_get();
> +
> + ? ? ? ret = request_irq(irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> + ? ? ? ? ? ? ? ? ? ? ? &pdev->dev);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq1, ret);
> + ? ? ? ? ? ? ? goto failed_request_irq1;
> + ? ? ? }
> +
> + ? ? ? ret = request_irq(irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
> + ? ? ? ? ? ? ? ? ? ? ? &pdev->dev);
> + ? ? ? if (ret) {
> + ? ? ? ? ? ? ? dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq2, ret);
> + ? ? ? ? ? ? ? goto failed_request_irq2;
> + ? ? ? }
> +
> + ? ? ? ipu_reset();

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
  2011-02-18  9:49       ` Sascha Hauer
  (?)
@ 2011-02-18 12:07         ` Samuel Ortiz
  -1 siblings, 0 replies; 32+ messages in thread
From: Samuel Ortiz @ 2011-02-18 12:07 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: Arnaud Patard, linux-arm-kernel, Paul Mundt, linux-kernel, linux-fbdev

Hi Sascha,

On Fri, Feb 18, 2011 at 10:49:49AM +0100, Sascha Hauer wrote:
> On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > > index 6bafb51b..ffdb37a 100644
> > > --- a/drivers/video/Kconfig
> > > +++ b/drivers/video/Kconfig
> > > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> > >  
> > >  source "drivers/gpu/stub/Kconfig"
> > >  
> > > +source "drivers/video/imx-ipu-v3/Kconfig"
> > > +
> > 
> > I don't see such a Kconfig file in this patch. Got lost while moving
> > from mfd to video ?
> 
> Oops, yes still untracked in my repository. Will add in the next series.
> 
> > 
> >  
> > >  config VGASTATE
> > >         tristate
> > >         default n
> > > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > > index 8c8fabd..f4921ab 100644
> > > --- a/drivers/video/Makefile
> > > +++ b/drivers/video/Makefile
> > > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> > >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> > >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> > >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> > 
> > Now that files are in drivers/video, do we want to keep MFD in the name ?
> 
> I asked myself the same question and had no clear answer. Probably
> better to remove the MFD.
Definitely, yes.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-18 12:07         ` Samuel Ortiz
  0 siblings, 0 replies; 32+ messages in thread
From: Samuel Ortiz @ 2011-02-18 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sascha,

On Fri, Feb 18, 2011 at 10:49:49AM +0100, Sascha Hauer wrote:
> On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > > index 6bafb51b..ffdb37a 100644
> > > --- a/drivers/video/Kconfig
> > > +++ b/drivers/video/Kconfig
> > > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> > >  
> > >  source "drivers/gpu/stub/Kconfig"
> > >  
> > > +source "drivers/video/imx-ipu-v3/Kconfig"
> > > +
> > 
> > I don't see such a Kconfig file in this patch. Got lost while moving
> > from mfd to video ?
> 
> Oops, yes still untracked in my repository. Will add in the next series.
> 
> > 
> >  
> > >  config VGASTATE
> > >         tristate
> > >         default n
> > > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > > index 8c8fabd..f4921ab 100644
> > > --- a/drivers/video/Makefile
> > > +++ b/drivers/video/Makefile
> > > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> > >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> > >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> > >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> > 
> > Now that files are in drivers/video, do we want to keep MFD in the name ?
> 
> I asked myself the same question and had no clear answer. Probably
> better to remove the MFD.
Definitely, yes.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-18 12:07         ` Samuel Ortiz
  0 siblings, 0 replies; 32+ messages in thread
From: Samuel Ortiz @ 2011-02-18 12:07 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Sascha,

On Fri, Feb 18, 2011 at 10:49:49AM +0100, Sascha Hauer wrote:
> On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > > index 6bafb51b..ffdb37a 100644
> > > --- a/drivers/video/Kconfig
> > > +++ b/drivers/video/Kconfig
> > > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> > >  
> > >  source "drivers/gpu/stub/Kconfig"
> > >  
> > > +source "drivers/video/imx-ipu-v3/Kconfig"
> > > +
> > 
> > I don't see such a Kconfig file in this patch. Got lost while moving
> > from mfd to video ?
> 
> Oops, yes still untracked in my repository. Will add in the next series.
> 
> > 
> >  
> > >  config VGASTATE
> > >         tristate
> > >         default n
> > > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > > index 8c8fabd..f4921ab 100644
> > > --- a/drivers/video/Makefile
> > > +++ b/drivers/video/Makefile
> > > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> > >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> > >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> > >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> > 
> > Now that files are in drivers/video, do we want to keep MFD in the name ?
> 
> I asked myself the same question and had no clear answer. Probably
> better to remove the MFD.
Definitely, yes.

Cheers,
Samuel.

-- 
Intel Open Source Technology Centre
http://oss.intel.com/

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
  2011-02-17 18:10     ` Arnaud Patard
  (?)
@ 2011-02-18  9:49       ` Sascha Hauer
  -1 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-02-18  9:49 UTC (permalink / raw)
  To: Arnaud Patard
  Cc: linux-arm-kernel, Paul Mundt, linux-kernel, linux-fbdev, Samuel Ortiz

On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > index 6bafb51b..ffdb37a 100644
> > --- a/drivers/video/Kconfig
> > +++ b/drivers/video/Kconfig
> > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> >  
> >  source "drivers/gpu/stub/Kconfig"
> >  
> > +source "drivers/video/imx-ipu-v3/Kconfig"
> > +
> 
> I don't see such a Kconfig file in this patch. Got lost while moving
> from mfd to video ?

Oops, yes still untracked in my repository. Will add in the next series.

> 
>  
> >  config VGASTATE
> >         tristate
> >         default n
> > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > index 8c8fabd..f4921ab 100644
> > --- a/drivers/video/Makefile
> > +++ b/drivers/video/Makefile
> > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> 
> Now that files are in drivers/video, do we want to keep MFD in the name ?

I asked myself the same question and had no clear answer. Probably
better to remove the MFD.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-18  9:49       ` Sascha Hauer
  0 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-02-18  9:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > index 6bafb51b..ffdb37a 100644
> > --- a/drivers/video/Kconfig
> > +++ b/drivers/video/Kconfig
> > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> >  
> >  source "drivers/gpu/stub/Kconfig"
> >  
> > +source "drivers/video/imx-ipu-v3/Kconfig"
> > +
> 
> I don't see such a Kconfig file in this patch. Got lost while moving
> from mfd to video ?

Oops, yes still untracked in my repository. Will add in the next series.

> 
>  
> >  config VGASTATE
> >         tristate
> >         default n
> > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > index 8c8fabd..f4921ab 100644
> > --- a/drivers/video/Makefile
> > +++ b/drivers/video/Makefile
> > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> 
> Now that files are in drivers/video, do we want to keep MFD in the name ?

I asked myself the same question and had no clear answer. Probably
better to remove the MFD.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-18  9:49       ` Sascha Hauer
  0 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-02-18  9:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Feb 17, 2011 at 07:10:24PM +0100, Arnaud Patard wrote:
> > diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> > index 6bafb51b..ffdb37a 100644
> > --- a/drivers/video/Kconfig
> > +++ b/drivers/video/Kconfig
> > @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
> >  
> >  source "drivers/gpu/stub/Kconfig"
> >  
> > +source "drivers/video/imx-ipu-v3/Kconfig"
> > +
> 
> I don't see such a Kconfig file in this patch. Got lost while moving
> from mfd to video ?

Oops, yes still untracked in my repository. Will add in the next series.

> 
>  
> >  config VGASTATE
> >         tristate
> >         default n
> > diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> > index 8c8fabd..f4921ab 100644
> > --- a/drivers/video/Makefile
> > +++ b/drivers/video/Makefile
> > @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
> >  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
> >  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
> >  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> > +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
> 
> Now that files are in drivers/video, do we want to keep MFD in the name ?

I asked myself the same question and had no clear answer. Probably
better to remove the MFD.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
  2011-02-16 14:10   ` Sascha Hauer
  (?)
@ 2011-02-17 18:10     ` Arnaud Patard
  -1 siblings, 0 replies; 32+ messages in thread
From: Arnaud Patard @ 2011-02-17 18:10 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-arm-kernel, Paul Mundt, linux-kernel, linux-fbdev, Samuel Ortiz

Sascha Hauer <s.hauer@pengutronix.de> writes:

Hi,

> The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
> features several units for image processing, this patch adds support
> for the units needed for Framebuffer support, namely:
>
> - Display Controller (dc)
> - Display Interface (di)
> - Display Multi Fifo Controller (dmfc)
> - Display Processor (dp)
> - Image DMA Controller (idmac)
>
> This patch is based on the Freescale driver, but follows a different
> approach. The Freescale code implements logical idmac channels and
> the handling of the subunits is hidden in common idmac code pathes
> in big switch/case statements. This patch instead just provides code
> and resource management for the different subunits. The user, in this
> case the framebuffer driver, decides how the different units play
> together.
>
> The IPU has other units missing in this patch:
>
> - CMOS Sensor Interface (csi)
> - Video Deinterlacer (vdi)
> - Sensor Multi FIFO Controler (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
>
> So expect more files to come in this directory.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-fbdev@vger.kernel.org
> Cc: Paul Mundt <lethal@linux-sh.org>
> Cc: Samuel Ortiz <sameo@linux.intel.com>
> ---
>  arch/arm/plat-mxc/include/mach/ipu-v3.h |   49 +++
>  drivers/video/Kconfig                   |    2 +
>  drivers/video/Makefile                  |    1 +
>  drivers/video/imx-ipu-v3/Makefile       |    3 +
>  drivers/video/imx-ipu-v3/ipu-common.c   |  708 +++++++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-cpmem.c    |  612 ++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dc.c       |  364 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-di.c       |  550 ++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dmfc.c     |  355 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dp.c       |  476 +++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-prv.h      |  216 ++++++++++
>  include/linux/mfd/imx-ipu-v3.h          |  219 ++++++++++
>  12 files changed, 3555 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-mxc/include/mach/ipu-v3.h
>  create mode 100644 drivers/video/imx-ipu-v3/Makefile
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-common.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-cpmem.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-di.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dmfc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dp.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-prv.h
>  create mode 100644 include/linux/mfd/imx-ipu-v3.h

[...]

> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 6bafb51b..ffdb37a 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
>  
>  source "drivers/gpu/stub/Kconfig"
>  
> +source "drivers/video/imx-ipu-v3/Kconfig"
> +

I don't see such a Kconfig file in this patch. Got lost while moving
from mfd to video ?

 
>  config VGASTATE
>         tristate
>         default n
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 8c8fabd..f4921ab 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
>  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
>  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/

Now that files are in drivers/video, do we want to keep MFD in the name ?

Arnaud

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

* Re: [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-17 18:10     ` Arnaud Patard
  0 siblings, 0 replies; 32+ messages in thread
From: Arnaud Patard @ 2011-02-17 18:10 UTC (permalink / raw)
  To: linux-arm-kernel

Sascha Hauer <s.hauer@pengutronix.de> writes:

Hi,

> The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
> features several units for image processing, this patch adds support
> for the units needed for Framebuffer support, namely:
>
> - Display Controller (dc)
> - Display Interface (di)
> - Display Multi Fifo Controller (dmfc)
> - Display Processor (dp)
> - Image DMA Controller (idmac)
>
> This patch is based on the Freescale driver, but follows a different
> approach. The Freescale code implements logical idmac channels and
> the handling of the subunits is hidden in common idmac code pathes
> in big switch/case statements. This patch instead just provides code
> and resource management for the different subunits. The user, in this
> case the framebuffer driver, decides how the different units play
> together.
>
> The IPU has other units missing in this patch:
>
> - CMOS Sensor Interface (csi)
> - Video Deinterlacer (vdi)
> - Sensor Multi FIFO Controler (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
>
> So expect more files to come in this directory.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-fbdev@vger.kernel.org
> Cc: Paul Mundt <lethal@linux-sh.org>
> Cc: Samuel Ortiz <sameo@linux.intel.com>
> ---
>  arch/arm/plat-mxc/include/mach/ipu-v3.h |   49 +++
>  drivers/video/Kconfig                   |    2 +
>  drivers/video/Makefile                  |    1 +
>  drivers/video/imx-ipu-v3/Makefile       |    3 +
>  drivers/video/imx-ipu-v3/ipu-common.c   |  708 +++++++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-cpmem.c    |  612 ++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dc.c       |  364 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-di.c       |  550 ++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dmfc.c     |  355 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dp.c       |  476 +++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-prv.h      |  216 ++++++++++
>  include/linux/mfd/imx-ipu-v3.h          |  219 ++++++++++
>  12 files changed, 3555 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-mxc/include/mach/ipu-v3.h
>  create mode 100644 drivers/video/imx-ipu-v3/Makefile
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-common.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-cpmem.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-di.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dmfc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dp.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-prv.h
>  create mode 100644 include/linux/mfd/imx-ipu-v3.h

[...]

> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 6bafb51b..ffdb37a 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
>  
>  source "drivers/gpu/stub/Kconfig"
>  
> +source "drivers/video/imx-ipu-v3/Kconfig"
> +

I don't see such a Kconfig file in this patch. Got lost while moving
from mfd to video ?

 
>  config VGASTATE
>         tristate
>         default n
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 8c8fabd..f4921ab 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
>  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
>  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/

Now that files are in drivers/video, do we want to keep MFD in the name ?

Arnaud

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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-17 18:10     ` Arnaud Patard
  0 siblings, 0 replies; 32+ messages in thread
From: Arnaud Patard (Rtp) @ 2011-02-17 18:10 UTC (permalink / raw)
  To: linux-arm-kernel

Sascha Hauer <s.hauer@pengutronix.de> writes:

Hi,

> The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
> features several units for image processing, this patch adds support
> for the units needed for Framebuffer support, namely:
>
> - Display Controller (dc)
> - Display Interface (di)
> - Display Multi Fifo Controller (dmfc)
> - Display Processor (dp)
> - Image DMA Controller (idmac)
>
> This patch is based on the Freescale driver, but follows a different
> approach. The Freescale code implements logical idmac channels and
> the handling of the subunits is hidden in common idmac code pathes
> in big switch/case statements. This patch instead just provides code
> and resource management for the different subunits. The user, in this
> case the framebuffer driver, decides how the different units play
> together.
>
> The IPU has other units missing in this patch:
>
> - CMOS Sensor Interface (csi)
> - Video Deinterlacer (vdi)
> - Sensor Multi FIFO Controler (smfc)
> - Image Converter (ic)
> - Image Rotator (irt)
>
> So expect more files to come in this directory.
>
> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-fbdev at vger.kernel.org
> Cc: Paul Mundt <lethal@linux-sh.org>
> Cc: Samuel Ortiz <sameo@linux.intel.com>
> ---
>  arch/arm/plat-mxc/include/mach/ipu-v3.h |   49 +++
>  drivers/video/Kconfig                   |    2 +
>  drivers/video/Makefile                  |    1 +
>  drivers/video/imx-ipu-v3/Makefile       |    3 +
>  drivers/video/imx-ipu-v3/ipu-common.c   |  708 +++++++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-cpmem.c    |  612 ++++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dc.c       |  364 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-di.c       |  550 ++++++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dmfc.c     |  355 ++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-dp.c       |  476 +++++++++++++++++++++
>  drivers/video/imx-ipu-v3/ipu-prv.h      |  216 ++++++++++
>  include/linux/mfd/imx-ipu-v3.h          |  219 ++++++++++
>  12 files changed, 3555 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/plat-mxc/include/mach/ipu-v3.h
>  create mode 100644 drivers/video/imx-ipu-v3/Makefile
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-common.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-cpmem.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-di.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dmfc.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-dp.c
>  create mode 100644 drivers/video/imx-ipu-v3/ipu-prv.h
>  create mode 100644 include/linux/mfd/imx-ipu-v3.h

[...]

> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 6bafb51b..ffdb37a 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
>  
>  source "drivers/gpu/stub/Kconfig"
>  
> +source "drivers/video/imx-ipu-v3/Kconfig"
> +

I don't see such a Kconfig file in this patch. Got lost while moving
from mfd to video ?

 
>  config VGASTATE
>         tristate
>         default n
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 8c8fabd..f4921ab 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
>  obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
>  obj-$(CONFIG_FB_MX3)		  += mx3fb.o
>  obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
> +obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/

Now that files are in drivers/video, do we want to keep MFD in the name ?

Arnaud

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

* [PATCH 1/7] Add a mfd IPUv3 driver
  2011-02-16 14:10 [PATCH v3] Add i.MX51/53 IPU framebuffer support Sascha Hauer
@ 2011-02-16 14:10   ` Sascha Hauer
  0 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-02-16 14:10 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Sascha Hauer, linux-kernel, linux-fbdev, Paul Mundt, Samuel Ortiz

The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
features several units for image processing, this patch adds support
for the units needed for Framebuffer support, namely:

- Display Controller (dc)
- Display Interface (di)
- Display Multi Fifo Controller (dmfc)
- Display Processor (dp)
- Image DMA Controller (idmac)

This patch is based on the Freescale driver, but follows a different
approach. The Freescale code implements logical idmac channels and
the handling of the subunits is hidden in common idmac code pathes
in big switch/case statements. This patch instead just provides code
and resource management for the different subunits. The user, in this
case the framebuffer driver, decides how the different units play
together.

The IPU has other units missing in this patch:

- CMOS Sensor Interface (csi)
- Video Deinterlacer (vdi)
- Sensor Multi FIFO Controler (smfc)
- Image Converter (ic)
- Image Rotator (irt)

So expect more files to come in this directory.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: linux-kernel@vger.kernel.org
Cc: linux-fbdev@vger.kernel.org
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
 arch/arm/plat-mxc/include/mach/ipu-v3.h |   49 +++
 drivers/video/Kconfig                   |    2 +
 drivers/video/Makefile                  |    1 +
 drivers/video/imx-ipu-v3/Makefile       |    3 +
 drivers/video/imx-ipu-v3/ipu-common.c   |  708 +++++++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-cpmem.c    |  612 ++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dc.c       |  364 ++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-di.c       |  550 ++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dmfc.c     |  355 ++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dp.c       |  476 +++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-prv.h      |  216 ++++++++++
 include/linux/mfd/imx-ipu-v3.h          |  219 ++++++++++
 12 files changed, 3555 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-mxc/include/mach/ipu-v3.h
 create mode 100644 drivers/video/imx-ipu-v3/Makefile
 create mode 100644 drivers/video/imx-ipu-v3/ipu-common.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-cpmem.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dc.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-di.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dmfc.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dp.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-prv.h
 create mode 100644 include/linux/mfd/imx-ipu-v3.h

diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h
new file mode 100644
index 0000000..f8900b9
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef __MACH_IPU_V3_H_
+#define __MACH_IPU_V3_H_
+
+/* IPU specific extensions to struct fb_videomode flag field */
+#define FB_SYNC_OE_LOW_ACT	(1 << 8)
+#define FB_SYNC_CLK_LAT_FALL	(1 << 9)
+#define FB_SYNC_DATA_INVERT	(1 << 10)
+#define FB_SYNC_CLK_IDLE_EN	(1 << 11)
+#define FB_SYNC_SHARP_MODE	(1 << 12)
+#define FB_SYNC_SWAP_RGB	(1 << 13)
+
+struct ipuv3_fb_platform_data {
+	const struct fb_videomode	*modes;
+	int				num_modes;
+	char				*mode_str;
+	u32				interface_pix_fmt;
+
+#define IMX_IPU_FB_USE_MODEDB	(1 << 0)
+#define IMX_IPU_FB_USE_OVERLAY	(1 << 1)
+	unsigned long			flags;
+
+	int				ipu_channel_bg;
+	int				ipu_channel_fg;
+	int				dc_channel;
+	int				dp_channel;
+	int				display;
+};
+
+struct imx_ipuv3_platform_data {
+	int rev;
+	struct ipuv3_fb_platform_data	*fb_head0_platform_data;
+	struct ipuv3_fb_platform_data	*fb_head1_platform_data;
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6bafb51b..ffdb37a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
 
 source "drivers/gpu/stub/Kconfig"
 
+source "drivers/video/imx-ipu-v3/Kconfig"
+
 config VGASTATE
        tristate
        default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8c8fabd..f4921ab 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
+obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile
new file mode 100644
index 0000000..ff70fe8
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MFD_IMX_IPU_V3) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-cpmem.o
diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c
new file mode 100644
index 0000000..d96245f
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-common.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <mach/common.h>
+#include <linux/mfd/core.h>
+#include <mach/ipu-v3.h>
+
+#include "ipu-prv.h"
+
+static struct clk *ipu_clk;
+static struct device *ipu_dev;
+
+static DEFINE_SPINLOCK(ipu_lock);
+static DEFINE_MUTEX(ipu_channel_lock);
+void __iomem *ipu_cm_reg;
+void __iomem *ipu_idmac_reg;
+
+static int ipu_use_count;
+
+static struct ipu_channel channels[64];
+
+struct ipu_channel *ipu_idmac_get(unsigned num)
+{
+	struct ipu_channel *channel;
+
+	dev_dbg(ipu_dev, "%s %d\n", __func__, num);
+
+	if (num > 63)
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&ipu_channel_lock);
+
+	channel = &channels[num];
+
+	if (channel->busy) {
+		channel = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	channel->busy = 1;
+	channel->num = num;
+
+out:
+	mutex_unlock(&ipu_channel_lock);
+
+	return channel;
+}
+EXPORT_SYMBOL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipu_channel *channel)
+{
+	dev_dbg(ipu_dev, "%s %d\n", __func__, channel->num);
+
+	mutex_lock(&ipu_channel_lock);
+
+	channel->busy = 0;
+
+	mutex_unlock(&ipu_channel_lock);
+}
+EXPORT_SYMBOL(ipu_idmac_put);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer)
+{
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	reg = ipu_cm_read(IPU_CHA_DB_MODE_SEL(channel->num));
+	if (doublebuffer)
+		reg |= idma_mask(channel->num);
+	else
+		reg &= ~idma_mask(channel->num);
+	ipu_cm_write(reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_idmac_set_double_buffer);
+
+int ipu_module_enable(u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(IPU_CONF);
+	ipu_conf |= mask;
+	ipu_cm_write(ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu_lock, lock_flags);
+
+	return 0;
+}
+
+int ipu_module_disable(u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(IPU_CONF);
+	ipu_conf &= ~mask;
+	ipu_cm_write(ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu_lock, lock_flags);
+
+	return 0;
+}
+
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num)
+{
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	/* Mark buffer as ready. */
+	if (buf_num == 0)
+		ipu_cm_write(idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+	else
+		ipu_cm_write(idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel)
+{
+	u32 val;
+	unsigned long flags;
+
+	ipu_get();
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	val = ipu_idmac_read(IDMAC_CHA_EN(channel->num));
+	val |= idma_mask(channel->num);
+	ipu_idmac_write(val, IDMAC_CHA_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipu_channel *channel)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	/* Disable DMA channel(s) */
+	val = ipu_idmac_read(IDMAC_CHA_EN(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_idmac_write(val, IDMAC_CHA_EN(channel->num));
+
+	/* Set channel buffers NOT to be ready */
+	ipu_cm_write(0xf0000000, IPU_GPR); /* write one to clear */
+
+	if (ipu_idma_is_set(IPU_CHA_BUF0_RDY, channel->num)) {
+		ipu_cm_write(idma_mask(channel->num),
+			     IPU_CHA_BUF0_RDY(channel->num));
+	}
+	if (ipu_idma_is_set(IPU_CHA_BUF1_RDY, channel->num)) {
+		ipu_cm_write(idma_mask(channel->num),
+			     IPU_CHA_BUF1_RDY(channel->num));
+	}
+
+	ipu_cm_write(0x0, IPU_GPR); /* write one to set */
+
+	/* Reset the double buffer */
+	val = ipu_cm_read(IPU_CHA_DB_MODE_SEL(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_cm_write(val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_disable_channel);
+
+static LIST_HEAD(ipu_irq_handlers);
+
+static void ipu_irq_update_irq_mask(void)
+{
+	struct ipu_irq_handler *handler;
+	int i;
+
+	DECLARE_IPU_IRQ_BITMAP(irqs);
+
+	bitmap_zero(irqs, IPU_IRQ_COUNT);
+
+	list_for_each_entry(handler, &ipu_irq_handlers, list)
+		bitmap_or(irqs, irqs, handler->ipu_irqs, IPU_IRQ_COUNT);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++)
+		ipu_cm_write(irqs[i], IPU_INT_CTRL(i + 1));
+}
+
+int ipu_irq_add_handler(struct ipu_irq_handler *ipuirq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	list_add_tail(&ipuirq->list, &ipu_irq_handlers);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_irq_add_handler);
+
+void ipu_irq_remove_handler(struct ipu_irq_handler *handler)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	list_del(&handler->list);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_irq_remove_handler);
+
+int ipu_irq_update_handler(struct ipu_irq_handler *handler,
+		unsigned long *bitmap)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	bitmap_copy(handler->ipu_irqs, bitmap, IPU_IRQ_COUNT);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_irq_update_handler);
+
+static void ipu_completion_handler(unsigned long *bitmask, void *context)
+{
+	struct completion *completion = context;
+
+	complete(completion);
+}
+
+int ipu_wait_for_interrupt(int interrupt, int timeout_ms)
+{
+	struct ipu_irq_handler handler;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	int ret;
+
+	bitmap_zero(handler.ipu_irqs, IPU_IRQ_COUNT);
+	bitmap_set(handler.ipu_irqs, interrupt, 1);
+
+	ipu_cm_write(1 << (interrupt % 32), IPU_INT_STAT(interrupt / 32 + 1));
+
+	handler.handler = ipu_completion_handler;
+	handler.context = &completion;
+	ipu_irq_add_handler(&handler);
+
+	ret = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(timeout_ms));
+
+	ipu_irq_remove_handler(&handler);
+
+	if (ret > 0)
+		ret = 0;
+	else
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_wait_for_interrupt);
+
+static irqreturn_t ipu_irq_handler(int irq, void *desc)
+{
+	DECLARE_IPU_IRQ_BITMAP(status);
+	struct ipu_irq_handler *handler;
+	int i;
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++) {
+		status[i] = ipu_cm_read(IPU_INT_STAT(i + 1));
+		ipu_cm_write(status[i], IPU_INT_STAT(i + 1));
+	}
+
+	list_for_each_entry(handler, &ipu_irq_handlers, list) {
+		DECLARE_IPU_IRQ_BITMAP(tmp);
+		if (bitmap_and(tmp, status, handler->ipu_irqs, IPU_IRQ_COUNT))
+			handler->handler(tmp, handler->context);
+	}
+
+	return IRQ_HANDLED;
+}
+
+ipu_color_space_t format_to_colorspace(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_LVDS666:
+	case IPU_PIX_FMT_LVDS888:
+		return RGB;
+
+	default:
+		return YCbCr;
+	}
+}
+
+static int ipu_reset(void)
+{
+	int timeout = 10000;
+	u32 val;
+
+	/* hard reset the IPU */
+	val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+	val |= 1 << 3;
+	writel(val, MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+
+	ipu_cm_write(0x807FFFFF, IPU_MEM_RST);
+
+	while (ipu_cm_read(IPU_MEM_RST) & 0x80000000) {
+		if (!timeout--)
+			return -ETIME;
+		udelay(100);
+	}
+
+	return 0;
+}
+
+/*
+ * The MIPI HSC unit has been removed from the i.MX51 Reference Manual by
+ * the Freescale marketing division. However this did not remove the
+ * hardware from the chip which still needs to be configured...
+ */
+static int __devinit ipu_mipi_setup(void)
+{
+	struct clk *hsc_clk;
+	void __iomem *hsc_addr;
+	int ret = 0;
+
+	hsc_addr = ioremap(MX51_MIPI_HSC_BASE_ADDR, PAGE_SIZE);
+	if (!hsc_addr)
+		return -ENOMEM;
+
+	hsc_clk = clk_get_sys(NULL, "mipi_hsp");
+	if (IS_ERR(hsc_clk)) {
+		ret = PTR_ERR(hsc_clk);
+		goto unmap;
+	}
+	clk_enable(hsc_clk);
+
+	/* setup MIPI module to legacy mode */
+	__raw_writel(0xF00, hsc_addr);
+
+	/* CSI mode: reserved; DI control mode: legacy (from Freescale BSP) */
+	__raw_writel(__raw_readl(hsc_addr + 0x800) | 0x30ff,
+		hsc_addr + 0x800);
+
+	clk_disable(hsc_clk);
+	clk_put(hsc_clk);
+unmap:
+	iounmap(hsc_addr);
+
+	return ret;
+}
+
+static int ipu_submodules_init(struct platform_device *pdev,
+		unsigned long ipu_base, struct clk *ipu_clk)
+{
+	char *unit;
+	int ret;
+
+	ret = ipu_di_init(pdev, 0, ipu_base + IPU_DI0_REG_BASE,
+			IPU_CONF_DI0_EN, ipu_clk);
+	if (ret) {
+		unit = "di0";
+		goto err_di_0;
+	}
+
+	ret = ipu_di_init(pdev, 1, ipu_base + IPU_DI1_REG_BASE,
+			IPU_CONF_DI1_EN, ipu_clk);
+	if (ret) {
+		unit = "di1";
+		goto err_di_1;
+	}
+
+	ret = ipu_dc_init(pdev, ipu_base + IPU_DC_REG_BASE,
+			ipu_base + IPU_DC_TMPL_REG_BASE);
+	if (ret) {
+		unit = "dc_template";
+		goto err_dc;
+	}
+
+	ret = ipu_dmfc_init(pdev, ipu_base + IPU_DMFC_REG_BASE, ipu_clk);
+	if (ret) {
+		unit = "dmfc";
+		goto err_dmfc;
+	}
+
+	ret = ipu_dp_init(pdev, ipu_base + IPU_SRM_REG_BASE);
+	if (ret) {
+		unit = "dp";
+		goto err_dp;
+	}
+
+	ret = ipu_cpmem_init(pdev, ipu_base + IPU_CPMEM_REG_BASE);
+	if (ret) {
+		unit = "cpmem";
+		goto err_cpmem;
+	}
+
+	return 0;
+
+err_cpmem:
+	ipu_dp_exit(pdev);
+err_dp:
+	ipu_dmfc_exit(pdev);
+err_dmfc:
+	ipu_dc_exit(pdev);
+err_dc:
+	ipu_di_exit(pdev, 1);
+err_di_1:
+	ipu_di_exit(pdev, 0);
+err_di_0:
+	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+	return ret;
+}
+
+void ipu_get(void)
+{
+	mutex_lock(&ipu_channel_lock);
+
+	ipu_use_count++;
+
+	if (ipu_use_count == 1)
+		clk_enable(ipu_clk);
+
+	mutex_unlock(&ipu_channel_lock);
+}
+
+void ipu_put(void)
+{
+	mutex_lock(&ipu_channel_lock);
+
+	ipu_use_count--;
+
+	if (ipu_use_count == 0)
+		clk_disable(ipu_clk);
+
+	if (ipu_use_count < 0) {
+		dev_err(ipu_dev, "ipu use count < 0\n");
+		ipu_use_count = 0;
+	}
+
+	mutex_unlock(&ipu_channel_lock);
+}
+
+static void ipu_submodules_exit(struct platform_device *pdev,
+		unsigned long ipu_base)
+{
+	ipu_cpmem_exit(pdev);
+	ipu_dp_exit(pdev);
+	ipu_dmfc_exit(pdev);
+	ipu_dc_exit(pdev);
+	ipu_di_exit(pdev, 1);
+	ipu_di_exit(pdev, 0);
+}
+
+static int ipu_add_subdevice_pdata(struct platform_device *pdev,
+		const char *name, int id, void *pdata, size_t pdata_size)
+{
+	struct mfd_cell cell = {
+		.platform_data = pdata,
+		.data_size = pdata_size,
+	};
+
+	cell.name = name;
+
+	return mfd_add_devices(&pdev->dev, id, &cell, 1, NULL, 0);
+}
+
+static int ipu_add_client_devices(struct platform_device *pdev)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipuv3_fb_platform_data *fbdata;
+
+	fbdata = plat_data->fb_head0_platform_data;
+	if (fbdata) {
+		fbdata->ipu_channel_bg =
+			MX51_IPU_CHANNEL_MEM_BG_SYNC;
+		fbdata->ipu_channel_fg =
+			MX51_IPU_CHANNEL_MEM_FG_SYNC;
+		fbdata->dc_channel = 5;
+		fbdata->dp_channel = IPU_DP_FLOW_SYNC;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 0,
+				fbdata, sizeof(*fbdata));
+	}
+
+	fbdata = plat_data->fb_head1_platform_data;
+	if (fbdata) {
+		fbdata->ipu_channel_bg =
+			MX51_IPU_CHANNEL_MEM_DC_SYNC;
+		fbdata->ipu_channel_fg = -1;
+		fbdata->dc_channel = 1;
+		fbdata->dp_channel = -1;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 1,
+				fbdata, sizeof(*fbdata));
+	}
+
+	return 0;
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned long ipu_base;
+	int ret, irq1, irq2;
+
+	/* There can be only one */
+	if (ipu_dev)
+		return -EBUSY;
+
+	spin_lock_init(&ipu_lock);
+
+	ipu_dev = &pdev->dev;
+
+	irq1 = platform_get_irq(pdev, 0);
+	irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || irq1 < 0 || irq2 < 0)
+		return -ENODEV;
+
+	ipu_base = res->start;
+
+	ipu_cm_reg = ioremap(ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+	if (!ipu_cm_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap1;
+	}
+
+	ipu_idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+	if (!ipu_idmac_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap2;
+	}
+
+	ret = ipu_mipi_setup();
+	if (ret)
+		goto failed_mipi_setup;
+
+	ipu_clk = clk_get(&pdev->dev, "ipu");
+	if (IS_ERR(ipu_clk)) {
+		ret = PTR_ERR(ipu_clk);
+		dev_err(&pdev->dev, "clk_get failed with %d", ret);
+		goto failed_clk_get;
+	}
+
+	ipu_get();
+
+	ret = request_irq(irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq1, ret);
+		goto failed_request_irq1;
+	}
+
+	ret = request_irq(irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq2, ret);
+		goto failed_request_irq2;
+	}
+
+	ipu_reset();
+
+	ret = ipu_submodules_init(pdev, ipu_base, ipu_clk);
+	if (ret)
+		goto failed_submodules_init;
+
+	/* Set sync refresh channels as high priority */
+	ipu_idmac_write(0x18800000, IDMAC_CHA_PRI(0));
+
+	ret = ipu_add_client_devices(pdev);
+        if (ret) {
+                dev_err(&pdev->dev, "adding client devices failed with %d\n", ret);
+		goto failed_add_clients;
+        }
+
+	ipu_put();
+
+	return 0;
+
+failed_add_clients:
+	ipu_submodules_exit(pdev, ipu_base);
+failed_submodules_init:
+	free_irq(irq2, &pdev->dev);
+failed_request_irq2:
+	free_irq(irq1, &pdev->dev);
+	ipu_put();
+failed_request_irq1:
+	clk_put(ipu_clk);
+failed_clk_get:
+failed_mipi_setup:
+	iounmap(ipu_idmac_reg);
+failed_ioremap2:
+	iounmap(ipu_cm_reg);
+failed_ioremap1:
+
+	return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned long ipu_base;
+	int irq1, irq2;
+
+	irq1 = platform_get_irq(pdev, 0);
+	irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ipu_base = res->start;
+
+	mfd_remove_devices(&pdev->dev);
+	ipu_submodules_exit(pdev, ipu_base);
+	free_irq(irq2, &pdev->dev);
+	free_irq(irq1, &pdev->dev);
+	iounmap(ipu_idmac_reg);
+	iounmap(ipu_cm_reg);
+
+	if (ipu_use_count != 0) {
+		dev_err(ipu_dev, "unbalanced use count: %d\n", ipu_use_count);
+		clk_disable(ipu_clk);
+	}
+
+	clk_put(ipu_clk);
+	ipu_dev = NULL;
+
+	return 0;
+}
+
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+		.name = "imx-ipuv3",
+	},
+	.probe = ipu_probe,
+	.remove = __devexit_p(ipu_remove),
+};
+
+static int __init ipu_gen_init(void)
+{
+	int32_t ret;
+
+	ret = platform_driver_register(&mxcipu_driver);
+	return 0;
+}
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+	platform_driver_unregister(&mxcipu_driver);
+}
+module_exit(ipu_gen_uninit);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imx-ipu-v3/ipu-cpmem.c b/drivers/video/imx-ipu-v3/ipu-cpmem.c
new file mode 100644
index 0000000..faff5ee
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-cpmem.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/types.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+
+#include "ipu-prv.h"
+
+#define __F(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_UBO		__F(0, 46, 22)
+#define IPU_FIELD_VBO		__F(0, 68, 22)
+#define IPU_FIELD_IOX		__F(0, 90, 4)
+#define IPU_FIELD_RDRW		__F(0, 94, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SLY		__F(1, 102, 14)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_SLUV		__F(1, 128, 14)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_SX		__F(0, 46, 12)
+#define IPU_FIELD_SY		__F(0, 58, 11)
+#define IPU_FIELD_NS		__F(0, 69, 10)
+#define IPU_FIELD_SDX		__F(0, 79, 7)
+#define IPU_FIELD_SM		__F(0, 86, 10)
+#define IPU_FIELD_SCC		__F(0, 96, 1)
+#define IPU_FIELD_SCE		__F(0, 97, 1)
+#define IPU_FIELD_SDY		__F(0, 98, 7)
+#define IPU_FIELD_SDRX		__F(0, 105, 1)
+#define IPU_FIELD_SDRY		__F(0, 106, 1)
+#define IPU_FIELD_BPP		__F(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	__F(0, 110, 2)
+#define IPU_FIELD_DIM		__F(0, 112, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SL		__F(1, 102, 14)
+#define IPU_FIELD_WID0		__F(1, 116, 3)
+#define IPU_FIELD_WID1		__F(1, 119, 3)
+#define IPU_FIELD_WID2		__F(1, 122, 3)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_OFS0		__F(1, 128, 5)
+#define IPU_FIELD_OFS1		__F(1, 133, 5)
+#define IPU_FIELD_OFS2		__F(1, 138, 5)
+#define IPU_FIELD_OFS3		__F(1, 143, 5)
+#define IPU_FIELD_SXYS		__F(1, 148, 1)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	__F(1, 150, 1)
+
+static u32 *ipu_cpmem_base;
+static struct device *ipu_dev;
+
+struct ipu_ch_param_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+static u32 ipu_bytes_per_pixel(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/* generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YUV422P:
+		return 1;
+
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		return 2;
+
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+		return 3;
+
+	case IPU_PIX_FMT_GENERIC_32:	/* generic data */
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+		return 4;
+
+	default:
+		return 1;
+	}
+}
+
+bool ipu_pixel_format_has_alpha(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+#define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch))
+
+static inline void ipu_ch_param_set_field(struct ipu_ch_param *base, u32 wbs, u32 v)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	base->word[word].data[i] &= ~(mask << ofs);
+	base->word[word].data[i] |= v << ofs;
+
+	if ((bit + size - 1) / 32 > i) {
+		base->word[word].data[i + 1] &= ~(v >> (mask ? (32 - ofs) : 0));
+		base->word[word].data[i + 1] |= v >> (ofs ? (32 - ofs) : 0);
+	}
+}
+
+static inline u32 ipu_ch_param_read_field(struct ipu_ch_param *base, u32 wbs)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (base->word[word].data[i] >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = base->word[word].data[i + 1];
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+
+static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
+					      int red_width, int red_offset,
+					      int green_width, int green_offset,
+					      int blue_width, int blue_offset,
+					      int alpha_width, int alpha_offset)
+{
+	/* Setup red width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID0, red_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS0, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID1, green_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS1, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID2, blue_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS2, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID3, alpha_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS3, alpha_offset);
+}
+
+static inline void ipu_ch_param_dump(int ch)
+{
+	struct ipu_ch_param *p = ipu_ch_param_addr(ch);
+	pr_debug("ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+		 p->word[0].data[3], p->word[0].data[4]);
+	pr_debug("ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+		 p->word[1].data[3], p->word[1].data[4]);
+	pr_debug("PFS 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_PFS));
+	pr_debug("BPP 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_BPP));
+	pr_debug("NPB 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_NPB));
+
+	pr_debug("FW %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FW));
+	pr_debug("FH %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FH));
+	pr_debug("Stride %d\n", ipu_ch_param_read_field(p, IPU_FIELD_SL));
+
+	pr_debug("Width0 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID0));
+	pr_debug("Width1 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID1));
+	pr_debug("Width2 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID2));
+	pr_debug("Width3 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID3));
+	pr_debug("Offset0 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS0));
+	pr_debug("Offset1 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS1));
+	pr_debug("Offset2 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS2));
+	pr_debug("Offset3 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS3));
+}
+
+static inline void ipu_ch_param_set_burst_size(u32 ch,
+						u16 burst_pixels)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_NPB,
+			       burst_pixels - 1);
+};
+
+static inline int ipu_ch_param_get_burst_size(u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_NPB) + 1;
+};
+
+static inline int ipu_ch_param_get_bpp(u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_BPP);
+};
+
+static inline void ipu_ch_param_set_buffer(u32 ch, int bufNum,
+					    dma_addr_t phyaddr)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch),
+			bufNum ? IPU_FIELD_EBA1 : IPU_FIELD_EBA0,
+			phyaddr / 8);
+};
+
+#define IPU_FIELD_ROT_HF_VF		__F(0, 119, 3)
+
+static inline void ipu_ch_param_set_rotation(u32 ch,
+					      ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ROT_HF_VF, temp_rot);
+};
+
+static inline void ipu_ch_param_set_block_mode(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_BM, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_use_separate_channel(u32 ch,
+		bool option)
+{
+	if (option)
+		ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALU, 1);
+	else
+		ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALU, 0);
+};
+
+static inline void ipu_ch_param_set_alpha_condition_read(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_CRE, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_buffer_memory(u32 ch)
+{
+	int alp_mem_idx;
+
+	switch (ch) {
+	case 14: /* PRP graphic */
+		alp_mem_idx = 0;
+		break;
+	case 15: /* PP graphic */
+		alp_mem_idx = 1;
+		break;
+	case 23: /* DP BG SYNC graphic */
+		alp_mem_idx = 4;
+		break;
+	case 27: /* DP FG SYNC graphic */
+		alp_mem_idx = 2;
+		break;
+	default:
+		dev_err(ipu_dev, "unsupported correlated channel of local alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALBM, alp_mem_idx);
+};
+
+static inline void ipu_ch_param_set_interlaced_scan(u32 ch)
+{
+	u32 stride;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_SO, 1);
+	stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_SL) + 1;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ILO, stride / 8);
+	stride *= 2;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_SLY, stride - 1);
+};
+
+static inline void ipu_ch_param_set_high_priority(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ID, 1);
+};
+
+static inline void ipu_ch_params_set_alpha_width(u32 ch, int alpha_width)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_WID3,
+			alpha_width - 1);
+}
+
+static int ipu_ch_param_init(int ch,
+			u32 pixel_fmt, u32 width,
+			u32 height, u32 stride,
+			u32 u, u32 v,
+			u32 uv_stride, dma_addr_t addr0,
+			dma_addr_t addr1)
+{
+	u32 u_offset = 0;
+	u32 v_offset = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_FW, width - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_FH, height - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_SLY, stride - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA0, addr0 >> 3);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA1, addr1 >> 3);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/* Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 63);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_32:
+		/* Represents 32-bit Generic data */
+		break;
+	case IPU_PIX_FMT_RGB565:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+		break;
+	case IPU_PIX_FMT_BGR24:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+		break;
+	case IPU_PIX_FMT_ABGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_UYVY:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0xA);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0x8);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);  /* burst size */
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = (v == 0) ? stride * height : v;
+		u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+		break;
+	case IPU_PIX_FMT_NV12:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 4);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		break;
+	default:
+		dev_err(ipu_dev, "mxc ipu: unimplemented pixel format: %d\n",
+			pixel_fmt);
+		return -EINVAL;
+	}
+	/* set burst size to 16 */
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, IPU_FIELD_SLUV, uv_stride - 1);
+
+	if (u > u_offset)
+		u_offset = u;
+
+	if (v > v_offset)
+		v_offset = v;
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_UBO, u_offset / 8);
+	ipu_ch_param_set_field(&params, IPU_FIELD_VBO, v_offset / 8);
+
+	pr_debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch));
+	memcpy(ipu_ch_param_addr(ch), &params, sizeof(params));
+	return 0;
+}
+
+/*
+ * This function is called to initialize a buffer for a IPU channel.
+ *
+ * @param       channel         The IPU channel.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       rot_mode        Input parameter for rotation setting of buffer.
+ *                              A rotation setting other than
+ *                              IPU_ROTATE_VERT_FLIP
+ *                              should only be used for input buffers of
+ *                              rotation channels.
+ *
+ * @param       phyaddr_0       Input parameter buffer 0 physical address.
+ *
+ * @param       phyaddr_1       Input parameter buffer 1 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              double buffering mode.
+ *
+ * @param       u		private u offset for additional cropping,
+ *				zero if not used.
+ *
+ * @param       v		private v offset for additional cropping,
+ *				zero if not used.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u, u32 v, bool interlaced)
+{
+	int ret = 0;
+	u32 dma_chan = channel->num;
+
+	if (stride < width * ipu_bytes_per_pixel(pixel_fmt))
+		stride = width * ipu_bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu_dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+
+	ipu_get();
+
+	/* Build parameter memory data for DMA channel */
+	ret = ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1);
+	if (ret)
+		goto out;
+
+	if (rot_mode)
+		ipu_ch_param_set_rotation(dma_chan, rot_mode);
+
+	if (interlaced)
+		ipu_ch_param_set_interlaced_scan(dma_chan);
+
+	if (idmac_idma_is_set(IDMAC_CHA_PRI, dma_chan))
+		ipu_ch_param_set_high_priority(dma_chan);
+
+	ipu_ch_param_dump(dma_chan);
+out:
+	ipu_put();
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_idmac_init_channel_buffer);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 buf_num, dma_addr_t phyaddr)
+{
+	u32 dma_chan = channel->num;
+
+	ipu_ch_param_set_buffer(dma_chan, buf_num, phyaddr);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_update_channel_buffer);
+
+int ipu_cpmem_init(struct platform_device *pdev, unsigned long base)
+{
+	ipu_cpmem_base = ioremap(base, PAGE_SIZE);
+	if (!ipu_cpmem_base)
+		return -ENOMEM;
+	ipu_dev = &pdev->dev;
+	return 0;
+}
+
+void ipu_cpmem_exit(struct platform_device *pdev)
+{
+	iounmap(ipu_cpmem_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c
new file mode 100644
index 0000000..b8c601e
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dc.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define ASYNC_SER_WAVE 6
+
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+#define DC_MAP_CONF_PTR(n)	(ipu_dc_reg + 0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	(ipu_dc_reg + 0x0144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+
+#define DC_WR_CH_CONF(ch)	(ipu_dc_reg + dc_channels[ch].channel_offset)
+#define DC_WR_CH_ADDR(ch)	(ipu_dc_reg + dc_channels[ch].channel_offset + 4)
+#define DC_RL_CH(ch, evt)	(ipu_dc_reg + dc_channels[ch].channel_offset + 8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN			(ipu_dc_reg + 0x00D4)
+#define DC_DISP_CONF1(disp)	(ipu_dc_reg + 0x00D8 + disp * 4)
+#define DC_DISP_CONF2(disp)	(ipu_dc_reg + 0x00E8 + disp * 4)
+#define DC_STAT			(ipu_dc_reg + 0x01C8)
+
+#define WROD(lf)		(0x18 | (lf << 1))
+
+#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_OFFSET		5
+#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID_OFFSET	3
+#define DC_WR_CH_CONF_PROG_DISP_ID_MASK		(3 << 3)
+
+static void __iomem *ipu_dc_reg;
+static void __iomem *ipu_dc_tmpl_reg;
+static struct device *ipu_dev;
+
+struct ipu_dc {
+	unsigned int di; /* The display interface number assigned to this dc channel */
+	unsigned int channel_offset;
+};
+
+static struct ipu_dc dc_channels[10];
+
+static void ipu_dc_link_event(int chan, int event, int addr, int priority)
+{
+	u32 reg;
+
+	reg = __raw_readl(DC_RL_CH(chan, event));
+	reg &= ~(0xFFFF << (16 * (event & 0x1)));
+	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+	__raw_writel(reg, DC_RL_CH(chan, event));
+}
+
+static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
+			       int wave, int glue, int sync)
+{
+	u32 reg;
+	int stop = 1;
+
+	reg = sync;
+	reg |= (glue << 4);
+	reg |= (++wave << 11);
+	reg |= (++map << 15);
+	reg |= (operand << 20) & 0xFFF00000;
+	__raw_writel(reg, ipu_dc_tmpl_reg + word * 8);
+
+	reg = (operand >> 12);
+	reg |= opcode << 4;
+	reg |= (stop << 9);
+	__raw_writel(reg, ipu_dc_tmpl_reg + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_RGB24:
+		return 0;
+	case IPU_PIX_FMT_RGB666:
+		return 1;
+	case IPU_PIX_FMT_YUV444:
+		return 2;
+	case IPU_PIX_FMT_RGB565:
+		return 3;
+	case IPU_PIX_FMT_LVDS666:
+		return 4;
+	}
+
+	return -EINVAL;
+}
+
+#define SYNC_WAVE 0
+
+int ipu_dc_init_sync(int dc_chan, int di, bool interlaced, u32 pixel_fmt, u32 width)
+{
+	u32 reg = 0, map;
+
+	dc_channels[dc_chan].di = di;
+
+	map = ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu_dev, "IPU_DISP: No MAP\n");
+		return -EINVAL;
+	}
+
+	ipu_get();
+
+	if (interlaced) {
+		ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3);
+		ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2);
+		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1);
+
+		/* Init template microcode */
+		ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+	} else {
+		if (di) {
+			ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
+			ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
+			ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		} else {
+			ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
+			ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
+			ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		}
+	}
+	ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+	reg = 0x2;
+	reg |= di << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	reg |= di << 2;
+	if (interlaced)
+		reg |= DC_WR_CH_CONF_FIELD_MODE;
+
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+	__raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	__raw_writel(0x00000084, DC_GEN);
+
+	__raw_writel(width, DC_DISP_CONF2(di));
+
+	ipu_module_enable(IPU_CONF_DC_EN);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dc_init_sync);
+
+void ipu_dc_init_async(int dc_chan, int di, bool interlaced)
+{
+	u32 reg = 0;
+	dc_channels[dc_chan].di = di;
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+	reg = 0x3;
+	reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+	__raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	__raw_writel(0x00000084, DC_GEN);
+
+	ipu_module_enable(IPU_CONF_DC_EN);
+}
+EXPORT_SYMBOL(ipu_dc_init_async);
+
+void ipu_dc_enable_channel(u32 dc_chan)
+{
+	int di;
+	u32 reg;
+
+	di = dc_channels[dc_chan].di;
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));
+	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+		__raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
+	}
+
+	reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+}
+EXPORT_SYMBOL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(u32 dc_chan)
+{
+	u32 reg;
+	int irq = 0, ret, timeout = 50;
+
+	if (dc_chan == 1) {
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (dc_chan == 5) {
+		irq = IPU_IRQ_DP_SF_END;
+	} else {
+		return;
+	}
+
+	ret = ipu_wait_for_interrupt(irq, 50);
+	if (ret)
+		return;
+
+	/* Wait for DC triple buffer to empty */
+	if (dc_channels[dc_chan].di == 0)
+		while ((__raw_readl(DC_STAT) & 0x00000002)
+			!= 0x00000002) {
+			msleep(2);
+			timeout -= 2;
+			if (timeout <= 0)
+				break;
+		}
+	else if (dc_channels[dc_chan].di == 1)
+		while ((__raw_readl(DC_STAT) & 0x00000020)
+			!= 0x00000020) {
+			msleep(2);
+			timeout -= 2;
+			if (timeout <= 0)
+				break;
+	}
+
+	reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+	reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+}
+EXPORT_SYMBOL(ipu_dc_disable_channel);
+
+static void ipu_dc_map_config(int map, int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = __raw_readl(DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xffff << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	__raw_writel(reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = __raw_readl(DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	__raw_writel(reg, DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(int map)
+{
+	u32 reg = __raw_readl(DC_MAP_CONF_PTR(map));
+	__raw_writel(reg & ~(0xffff << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base, unsigned long template_base)
+{
+	static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4};
+	int i;
+
+	ipu_dc_reg = ioremap(base, PAGE_SIZE);
+	if (!ipu_dc_reg)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	ipu_dc_tmpl_reg = ioremap(template_base, PAGE_SIZE);
+	if (!ipu_dc_tmpl_reg) {
+		iounmap(ipu_dc_reg);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < 10; i++)
+		dc_channels[i].channel_offset = channel_offsets[i];
+
+	/* IPU_PIX_FMT_RGB24 */
+	ipu_dc_map_clear(0);
+	ipu_dc_map_config(0, 0, 7, 0xff);
+	ipu_dc_map_config(0, 1, 15, 0xff);
+	ipu_dc_map_config(0, 2, 23, 0xff);
+
+	/* IPU_PIX_FMT_RGB666 */
+	ipu_dc_map_clear(1);
+	ipu_dc_map_config(1, 0, 5, 0xfc);
+	ipu_dc_map_config(1, 1, 11, 0xfc);
+	ipu_dc_map_config(1, 2, 17, 0xfc);
+
+	/* IPU_PIX_FMT_YUV444 */
+	ipu_dc_map_clear(2);
+	ipu_dc_map_config(2, 0, 15, 0xff);
+	ipu_dc_map_config(2, 1, 23, 0xff);
+	ipu_dc_map_config(2, 2, 7, 0xff);
+
+	/* IPU_PIX_FMT_RGB565 */
+	ipu_dc_map_clear(3);
+	ipu_dc_map_config(3, 0, 4, 0xf8);
+	ipu_dc_map_config(3, 1, 10, 0xfc);
+	ipu_dc_map_config(3, 2, 15, 0xf8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	ipu_dc_map_clear(4);
+	ipu_dc_map_config(4, 0, 5, 0xfc);
+	ipu_dc_map_config(4, 1, 13, 0xfc);
+	ipu_dc_map_config(4, 2, 21, 0xfc);
+
+	return 0;
+}
+
+void ipu_dc_exit(struct platform_device *pdev)
+{
+	iounmap(ipu_dc_reg);
+	iounmap(ipu_dc_tmpl_reg);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c
new file mode 100644
index 0000000..62e3d01
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-di.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/platform_device.h>
+
+#include "ipu-prv.h"
+
+#define SYNC_WAVE 0
+
+#define DC_DISP_ID_SYNC(di)	(di)
+
+struct ipu_di {
+	void __iomem *base;
+	int id;
+	u32 module;
+	struct clk *clk;
+	struct clk *ipu_clk;
+	bool external_clk;
+	bool inuse;
+	bool initialized;
+};
+
+static struct ipu_di dis[2];
+
+static DEFINE_MUTEX(di_mutex);
+static struct device *ipu_dev;
+
+struct di_sync_config {
+	int run_count;
+	int run_src;
+	int offset_count;
+	int offset_src;
+	int repeat_count;
+	int cnt_clr_src;
+	int cnt_polarity_gen_en;
+	int cnt_polarity_clr_src;
+	int cnt_polarity_trigger_src;
+	int cnt_up;
+	int cnt_down;
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = 0,
+	DI_SYNC_CLK = 1,
+	DI_SYNC_INT_HSYNC = 2,
+	DI_SYNC_HSYNC = 3,
+	DI_SYNC_VSYNC = 4,
+	DI_SYNC_DE = 6,
+};
+
+#define DI_GENERAL		0x0000
+#define DI_BS_CLKGEN0		0x0004
+#define DI_BS_CLKGEN1		0x0008
+#define DI_SW_GEN0(gen)		(0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		(0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN		0x0054
+#define DI_DW_GEN(gen)		(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	(0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF		0x015c
+#define DI_SSC			0x0160
+#define DI_POL			0x0164
+#define DI_AW0			0x0168
+#define DI_AW1			0x016c
+#define DI_SCR_CONF		0x0170
+#define DI_STAT			0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x)			((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x)			((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x)		((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x)		((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x)		((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x)		((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)	((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)		((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x)			((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x)			(x)
+#define DI_SW_GEN1_AUTO_RELOAD			(0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET		24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET		16
+
+#define DI_GEN_DI_CLK_EXT			(1 << 20)
+#define DI_GEN_POLARITY_1			(1 << 0)
+#define DI_GEN_POLARITY_2			(1 << 1)
+#define DI_GEN_POLARITY_3			(1 << 2)
+#define DI_GEN_POLARITY_4			(1 << 3)
+#define DI_GEN_POLARITY_5			(1 << 4)
+#define DI_GEN_POLARITY_6			(1 << 5)
+#define DI_GEN_POLARITY_7			(1 << 6)
+#define DI_GEN_POLARITY_8			(1 << 7)
+
+#define DI_POL_DRDY_DATA_POLARITY		(1 << 7)
+#define DI_POL_DRDY_POLARITY_15			(1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET			13
+
+#define DI0_COUNTER_RELEASE			(1 << 24)
+#define DI1_COUNTER_RELEASE			(1 << 25)
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+	return __raw_readl(di->base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+	__raw_writel(value, di->base + offset);
+}
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+				     int wave_gen,
+				     int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, int set,
+				    int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, int count)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct di_sync_config *c = &config[i];
+		int wave_gen = i + 1;
+
+		pr_debug("%s %d\n", __func__, wave_gen);
+		if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || (c->repeat_count >= 0x1000) ||
+			(c->cnt_up >= 0x400) || (c->cnt_down >= 0x400)) {
+			dev_err(ipu_dev, "DI%d counters out of range.\n", di->id);
+			return;
+		}
+
+		reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+			DI_SW_GEN0_RUN_SRC(c->run_src) |
+			DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+			DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+		ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+		reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+			DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+			DI_SW_GEN1_CNT_POL_TRIGGER_SRC(c->cnt_polarity_trigger_src) |
+			DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+			DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+			DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+		if (c->repeat_count == 0) {
+			/* Enable auto reload */
+			reg |= DI_SW_GEN1_AUTO_RELOAD;
+		}
+
+		ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+		reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+		reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+		reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+		ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+	}
+}
+
+static void ipu_di_sync_config_interlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width;
+	u32 reg;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total / 2 - 1,
+			.run_src = DI_SYNC_CLK,
+		}, {
+			.run_count = h_total - 11,
+			.run_src = DI_SYNC_CLK,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total * 2 - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = 1,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height / 2,
+			.cnt_clr_src = 4,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_HSYNC,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = 9,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = v_total / 2,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_clr_src = DI_SYNC_HSYNC,
+			.cnt_down = 4,
+		}
+	};
+
+	ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+
+	/* set gentime select and tag sel */
+	reg = ipu_di_read(di, DI_SW_GEN1(9));
+	reg &= 0x1FFFFFFF;
+	reg |= (3 - 1) << 29 | 0x00008000;
+	ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+	ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+}
+
+static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig, int div)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width + (sig->v_end_width < 2 ? 1 : 0);
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+		} , {
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+			.offset_count = div * sig->v_to_h_sync,
+			.offset_src = DI_SYNC_CLK,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_CLK,
+			.cnt_down = sig->h_sync_width * 2,
+		} , {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = sig->v_sync_width * 2,
+		} , {
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		} , {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		},
+	};
+
+	ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+	ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, u32 pixel_clk, struct ipu_di_signal_cfg *sig)
+{
+	u32 reg;
+	u32 disp_gen, di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+	struct clk *di_clk;
+
+	dev_dbg(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;
+
+	mutex_lock(&di_mutex);
+	ipu_get();
+
+	/* Init clocking */
+	if (sig->ext_clk) {
+		di->external_clk = true;
+		di_clk = di->clk;
+	} else {
+		di->external_clk = false;
+		di_clk = di->ipu_clk;
+	}
+
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = (clk_get_rate(di_clk) * 16) / pixel_clk;
+	if (div < 0x10)	/* Min DI disp clock divider is 1 */
+		div = 0x10;
+
+	disp_gen = ipu_cm_read(IPU_DISP_GEN);
+	disp_gen &= di->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(disp_gen, IPU_DISP_GEN);
+
+	ipu_di_write(di, div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* Down time is half of period */
+	ipu_di_write(di, (div / 16) << 16, DI_BS_CLKGEN1);
+
+	ipu_di_data_wave_config(di, SYNC_WAVE, div / 16 - 1, div / 16 - 1);
+	ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div / 16 * 2);
+
+	div = div / 16;		/* Now divider is integer portion */
+
+	di_gen = 0;
+	if (sig->ext_clk)
+		di_gen |= DI_GEN_DI_CLK_EXT;
+
+	if (sig->interlaced) {
+		ipu_di_sync_config_interlaced(di, sig);
+
+		/* set y_sel = 1 */
+		di_gen |= 0x10000000;
+		di_gen |= DI_GEN_POLARITY_5;
+		di_gen |= DI_GEN_POLARITY_8;
+
+		vsync_cnt = 7;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		ipu_di_sync_config_noninterlaced(di, sig, div);
+
+		vsync_cnt = 3;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+	}
+
+	ipu_di_write(di, di_gen, DI_GENERAL);
+	ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+		     DI_SYNC_AS_GEN);
+
+	reg = ipu_di_read(di, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+	if (sig->enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig->data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+
+	ipu_di_write(di, reg, DI_POL);
+
+	ipu_put();
+	mutex_unlock(&di_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+	u32 reg;
+
+	ipu_get();
+	reg = ipu_cm_read(IPU_DISP_GEN);
+	if (di->id)
+		reg |= DI1_COUNTER_RELEASE;
+	else
+		reg |= DI0_COUNTER_RELEASE;
+	ipu_cm_write(reg, IPU_DISP_GEN);
+
+	if (di->external_clk)
+		clk_enable(di->clk);
+
+	ipu_module_enable(di->module);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+	u32 reg;
+
+	ipu_module_disable(di->module);
+	ipu_put();
+
+	if (di->external_clk)
+		clk_disable(di->clk);
+
+	reg = ipu_cm_read(IPU_DISP_GEN);
+	if (di->id)
+		reg &= ~DI1_COUNTER_RELEASE;
+	else
+		reg &= ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(reg, IPU_DISP_GEN);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_disable);
+
+static DEFINE_MUTEX(ipu_di_lock);
+
+struct ipu_di *ipu_di_get(int disp)
+{
+	struct ipu_di *di;
+
+	if (disp > 1)
+		return ERR_PTR(-EINVAL);
+
+	di = &dis[disp];
+
+	mutex_lock(&ipu_di_lock);
+
+	if (!di->initialized) {
+		di = ERR_PTR(-ENOSYS);
+		goto out;
+	}
+
+	if (di->inuse) {
+		di = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	di->inuse = true;
+out:
+	mutex_unlock(&ipu_di_lock);
+
+	return di;
+}
+EXPORT_SYMBOL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+	mutex_lock(&ipu_di_lock);
+
+	di->inuse = false;
+
+	mutex_unlock(&ipu_di_lock);
+}
+EXPORT_SYMBOL(ipu_di_put);
+
+int ipu_di_init(struct platform_device *pdev, int id, unsigned long base,
+		u32 module, struct clk *ipu_clk)
+{
+	char *clkid;
+
+	if (id > 1)
+		return -EINVAL;
+
+	if (id)
+		clkid = "di1";
+	else
+		clkid = "di0";
+
+	ipu_dev = &pdev->dev;
+
+	dis[id].clk = clk_get(&pdev->dev, clkid);
+	dis[id].module = module;
+	dis[id].id = id;
+	dis[id].ipu_clk = ipu_clk;
+	dis[id].base = ioremap(base, PAGE_SIZE);
+	dis[id].initialized = true;
+	dis[id].inuse = false;
+	if (!dis[id].base)
+		return -ENOMEM;
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+	return 0;
+}
+
+void ipu_di_exit(struct platform_device *pdev, int id)
+{
+	clk_put(dis[id].clk);
+	iounmap(dis[id].base);
+	dis[id].initialized = false;
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c
new file mode 100644
index 0000000..3d47a76
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN		0x0000
+#define DMFC_WR_CHAN		0x0004
+#define DMFC_WR_CHAN_DEF	0x0008
+#define DMFC_DP_CHAN		0x000c
+#define DMFC_DP_CHAN_DEF	0x0010
+#define DMFC_GENERAL1		0x0014
+#define DMFC_GENERAL2		0x0018
+#define DMFC_IC_CTRL		0x001c
+#define DMFC_STAT		0x0020
+
+#define DMFC_WR_CHAN_1_28		0
+#define DMFC_WR_CHAN_2_41		8
+#define DMFC_WR_CHAN_1C_42		16
+#define DMFC_WR_CHAN_2C_43		24
+
+#define DMFC_DP_CHAN_5B_23		0
+#define DMFC_DP_CHAN_5F_27		8
+#define DMFC_DP_CHAN_6B_24		16
+#define DMFC_DP_CHAN_6F_29		24
+
+#define DMFC_FIFO_SIZE_64		(3 << 3)
+#define DMFC_FIFO_SIZE_128		(2 << 3)
+#define DMFC_FIFO_SIZE_256		(1 << 3)
+#define DMFC_FIFO_SIZE_512		(0 << 3)
+
+#define DMFC_SEGMENT(x)			((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_32		(0 << 6)
+#define DMFC_BURSTSIZE_16		(1 << 6)
+#define DMFC_BURSTSIZE_8		(2 << 6)
+#define DMFC_BURSTSIZE_4		(3 << 6)
+
+static struct device *ipu_dev;
+
+struct dmfc_channel {
+	int		ipu_channel;
+	unsigned long	channel_reg;
+	unsigned long	shift;
+	unsigned	eot_shift;
+	unsigned	slots;
+	unsigned	max_fifo_lines;
+	unsigned	slotmask;
+	unsigned	segment;
+};
+
+static struct dmfc_channel dmfcs[] = {
+	{
+		.ipu_channel	= 23,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5B_23,
+		.eot_shift	= 20,
+		.max_fifo_lines	= 3,
+	}, {
+		.ipu_channel	= 24,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6B_24,
+		.eot_shift	= 22,
+		.max_fifo_lines	= 1,
+	}, {
+		.ipu_channel	= 27,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5F_27,
+		.eot_shift	= 21,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 28,
+		.channel_reg	= DMFC_WR_CHAN,
+		.shift		= DMFC_WR_CHAN_1_28,
+		.eot_shift	= 16,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 29,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6F_29,
+		.eot_shift	= 23,
+		.max_fifo_lines	= 1,
+	},
+};
+
+#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcs)
+
+static int dmfc_use_count;
+static void __iomem *dmfc_regs;
+static unsigned long dmfc_bandwidth_per_slot;
+static DEFINE_MUTEX(dmfc_mutex);
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+	mutex_lock(&dmfc_mutex);
+	ipu_get();
+
+	if (!dmfc_use_count)
+		ipu_module_enable(IPU_CONF_DMFC_EN);
+
+	dmfc_use_count++;
+
+	mutex_unlock(&dmfc_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+	mutex_lock(&dmfc_mutex);
+
+	dmfc_use_count--;
+
+	if (!dmfc_use_count)
+		ipu_module_disable(IPU_CONF_DMFC_EN);
+
+	if (dmfc_use_count < 0)
+		dmfc_use_count = 0;
+
+	ipu_put();
+	mutex_unlock(&dmfc_mutex);
+}
+EXPORT_SYMBOL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, int segment)
+{
+	u32 val, field;
+
+	dev_dbg(ipu_dev, "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+			slots, segment, dmfc->ipu_channel);
+
+	if (!dmfc)
+		return -EINVAL;
+
+	switch (slots) {
+	case 1:
+		field = DMFC_FIFO_SIZE_64;
+		break;
+	case 2:
+		field = DMFC_FIFO_SIZE_128;
+		break;
+	case 4:
+		field = DMFC_FIFO_SIZE_256;
+		break;
+	case 8:
+		field = DMFC_FIFO_SIZE_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	field |= DMFC_SEGMENT(segment) | DMFC_BURSTSIZE_8;
+
+	val = readl(dmfc_regs + dmfc->channel_reg);
+
+	val &= ~(0xff << dmfc->shift);
+	val |= field << dmfc->shift;
+
+	writel(val, dmfc_regs + dmfc->channel_reg);
+
+	dmfc->slots = slots;
+	dmfc->segment = segment;
+	dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+	return 0;
+}
+
+static int dmfc_bandwidth_to_slots(unsigned long bandwidth)
+{
+	int slots = 1;
+
+	while (slots * dmfc_bandwidth_per_slot < bandwidth)
+		slots *= 2;
+
+	return slots;
+}
+
+static int dmfc_find_slots(int slots)
+{
+	unsigned slotmask_need, slotmask_used = 0;
+	int i, segment = 0;
+
+	slotmask_need = (1 << slots) - 1;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		slotmask_used |= dmfcs[i].slotmask;
+
+	while (slotmask_need <= 0xff) {
+		if (!(slotmask_used & slotmask_need))
+			return segment;
+
+		slotmask_need <<= 1;
+		segment++;
+	}
+
+	return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+	int i;
+
+	dev_dbg(ipu_dev, "dmfc: freeing %d slots starting from segment %d\n",
+			dmfc->slots, dmfc->segment);
+
+	mutex_lock(&dmfc_mutex);
+
+	if (!dmfc->slots)
+		goto out;
+
+	dmfc->slotmask = 0;
+	dmfc->slots = 0;
+	dmfc->segment = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++)
+		dmfcs[i].slotmask = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++) {
+		if (dmfcs[i].slots > 0) {
+			dmfcs[i].segment = dmfc_find_slots(dmfcs[i].slots);
+			dmfcs[i].slotmask = ((1 << dmfcs[i].slots) - 1) << dmfcs[i].segment;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++) {
+		if (dmfcs[i].slots > 0)
+			ipu_dmfc_setup_channel(&dmfcs[i], dmfcs[i].slots, dmfcs[i].segment);
+	}
+out:
+	mutex_unlock(&dmfc_mutex);
+}
+EXPORT_SYMBOL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_pixel_per_second)
+{
+	int slots = dmfc_bandwidth_to_slots(bandwidth_pixel_per_second);
+	int segment = 0, ret = 0;
+
+	dev_dbg(ipu_dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+			bandwidth_pixel_per_second / 1000000, dmfc->ipu_channel);
+
+	ipu_dmfc_free_bandwidth(dmfc);
+
+	ipu_get();
+	mutex_lock(&dmfc_mutex);
+
+	if (slots > 8) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	segment = dmfc_find_slots(slots);
+	if (segment < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ipu_dmfc_setup_channel(dmfc, slots, segment);
+
+out:
+	ipu_put();
+	mutex_unlock(&dmfc_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+	u32 dmfc_gen1;
+
+	ipu_get();
+
+	dmfc_gen1 = readl(dmfc_regs + DMFC_GENERAL1);
+
+	if ((dmfc->slots * 64 * 4) / width > dmfc->max_fifo_lines)
+		dmfc_gen1 |= 1 << dmfc->eot_shift;
+	else
+		dmfc_gen1 &= ~(1 << dmfc->eot_shift);
+
+	writel(dmfc_gen1, dmfc_regs + DMFC_GENERAL1);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(int ipu_channel)
+{
+	int i;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		if (dmfcs[i].ipu_channel == ipu_channel)
+			return &dmfcs[i];
+	return NULL;
+}
+EXPORT_SYMBOL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+	ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base,
+		struct clk *ipu_clk)
+{
+	dmfc_regs = ioremap(base, PAGE_SIZE);
+
+	if (!dmfc_regs)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	writel(0x0, dmfc_regs + DMFC_WR_CHAN);
+	writel(0x0, dmfc_regs + DMFC_DP_CHAN);
+
+	/*
+	 * We have a total bandwidth of clkrate * 4pixel divided
+	 * into 8 slots.
+	 */
+	dmfc_bandwidth_per_slot = clk_get_rate(ipu_clk) / 4;
+
+	dev_dbg(ipu_dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+			dmfc_bandwidth_per_slot / 1000000);
+
+	writel(0x202020f6, dmfc_regs + DMFC_WR_CHAN_DEF);
+	writel(0x2020f6f6, dmfc_regs + DMFC_DP_CHAN_DEF);
+	writel(0x00000003, dmfc_regs + DMFC_GENERAL1);
+
+	return 0;
+}
+
+void ipu_dmfc_exit(struct platform_device *pdev)
+{
+	iounmap(dmfc_regs);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c
new file mode 100644
index 0000000..57a7fec
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dp.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/err.h>
+
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF(flow)		(ipu_dp_base + flow)
+#define DP_GRAPH_WIND_CTRL(flow)	(ipu_dp_base + 0x0004 + flow)
+#define DP_FG_POS(flow)			(ipu_dp_base + 0x0008 + flow)
+#define DP_CSC_A_0(flow)		(ipu_dp_base + 0x0044 + flow)
+#define DP_CSC_A_1(flow)		(ipu_dp_base + 0x0048 + flow)
+#define DP_CSC_A_2(flow)		(ipu_dp_base + 0x004C + flow)
+#define DP_CSC_A_3(flow)		(ipu_dp_base + 0x0050 + flow)
+#define DP_CSC_0(flow)			(ipu_dp_base + 0x0054 + flow)
+#define DP_CSC_1(flow)			(ipu_dp_base + 0x0058 + flow)
+
+#define DP_COM_CONF_FG_EN		(1 << 0)
+#define DP_COM_CONF_GWSEL		(1 << 1)
+#define DP_COM_CONF_GWAM		(1 << 2)
+#define DP_COM_CONF_GWCKE		(1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET	8
+#define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
+
+struct ipu_dp {
+	u32 flow;
+	bool in_use;
+};
+
+static struct ipu_dp ipu_dp[3];
+static struct device *ipu_dev;
+
+static u32 ipu_flows[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+static void __iomem *ipu_dp_base;
+static int dp_use_count;
+static DEFINE_MUTEX(dp_mutex);
+
+/*     Y = R *  .299 + G *  .587 + B *  .114;
+       U = R * -.169 + G * -.332 + B *  .500 + 128.;
+       V = R *  .500 + G * -.419 + B * -.0813 + 128.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{ 153, 301, 58, },
+	{ -87, -170, 0x0100, },
+	{ 0x100, -215, -42, },
+	{ 0x0000, 0x0200, 0x0200, },	/* B0, B1, B2 */
+	{ 0x2, 0x2, 0x2, },	/* S0, S1, S2 */
+};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+	{ 0x095, 0x000, 0x0CC, },
+	{ 0x095, 0x3CE, 0x398, },
+	{ 0x095, 0x0FF, 0x000, },
+	{ 0x3E42, 0x010A, 0x3DD6, },	/*B0,B1,B2 */
+	{ 0x1, 0x1, 0x1, },	/*S0,S1,S2 */
+};
+
+/* Please keep S0, S1 and S2 as 0x2 by using this conversion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+	int c;
+
+	c = red * rgb2ycbcr_coeff[n][0];
+	c += green * rgb2ycbcr_coeff[n][1];
+	c += blue * rgb2ycbcr_coeff[n][2];
+	c /= 16;
+	c += rgb2ycbcr_coeff[3][n] * 4;
+	c += 8;
+	c /= 16;
+	if (c < 0)
+		c = 0;
+	if (c > 255)
+		c = 255;
+	return c;
+}
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+/*
+ * Row is for BG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+	{
+		{ DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}
+};
+
+static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
+
+static int color_key_4rgb = 1;
+
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 color_key)
+{
+	u32 reg;
+	int y, u, v;
+	int red, green, blue;
+
+	mutex_lock(&dp_mutex);
+
+	color_key_4rgb = 1;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
+
+		dev_dbg(ipu_dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu_dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFF000000L;
+		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp->flow));
+
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF(dp->flow));
+	} else {
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(dp->flow));
+	}
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_color_key);
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, bool bg_chan)
+{
+	u32 reg;
+
+	mutex_lock(&dp_mutex);
+
+	reg = __raw_readl(DP_COM_CONF(dp->flow));
+	if (bg_chan)
+		reg &= ~DP_COM_CONF_GWSEL;
+	else
+		reg |= DP_COM_CONF_GWSEL;
+	__raw_writel(reg, DP_COM_CONF(dp->flow));
+
+	if (enable) {
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0x00FFFFFFL;
+		__raw_writel(reg | ((u32) alpha << 24),
+			     DP_GRAPH_WIND_CTRL(dp->flow));
+
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF(dp->flow));
+	} else {
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(dp->flow));
+	}
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+	u32 reg;
+
+	mutex_lock(&dp_mutex);
+
+	__raw_writel((x_pos << 16) | y_pos, DP_FG_POS(dp->flow));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_window_pos);
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+void __ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param,
+			bool srm_mode_update)
+{
+	u32 reg;
+	const int (*coeff)[5][3];
+
+	if (dp_csc_param.mode >= 0) {
+		reg = __raw_readl(DP_COM_CONF(dp));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		__raw_writel(reg, DP_COM_CONF(dp));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		__raw_writel(mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
+		__raw_writel(mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
+		__raw_writel(mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
+		__raw_writel(mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
+		__raw_writel(mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(dp));
+		__raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+				(mask_b((*coeff)[3][2]) << 16) |
+				((*coeff)[4][2] << 30), DP_CSC_1(dp));
+	}
+
+	if (srm_mode_update) {
+		reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(reg, IPU_SRM_PRI2);
+	}
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg)
+{
+	int in_fmt, out_fmt;
+	enum csc_type_t *csc_type;
+	u32 reg;
+
+	ipu_get();
+
+	if (bg)
+		csc_type = &bg_csc_type;
+	else
+		csc_type = &fg_csc_type;
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (in_fmt == RGB) {
+		if (out_fmt == RGB)
+			*csc_type = RGB2RGB;
+		else
+			*csc_type = RGB2YUV;
+	} else {
+		if (out_fmt == RGB)
+			*csc_type = YUV2RGB;
+		else
+			*csc_type = YUV2YUV;
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = __raw_readl(DP_COM_CONF(dp->flow));
+	if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		u32 color_key = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFFFFFFL;
+
+		dev_dbg(ipu_dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFF000000L;
+		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp->flow));
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu_dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(dp->flow, dp_csc_array[bg_csc_type][fg_csc_type], true);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	mutex_lock(&dp_mutex);
+	ipu_get();
+
+	if (!dp_use_count)
+		ipu_module_enable(IPU_CONF_DP_EN);
+
+	dp_use_count++;
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+	mutex_lock(&dp_mutex);
+
+	dp_use_count--;
+
+	if (!dp_use_count)
+		ipu_module_disable(IPU_CONF_DP_EN);
+
+	if (dp_use_count < 0)
+		dp_use_count = 0;
+
+	ipu_put();
+	mutex_unlock(&dp_mutex);
+}
+EXPORT_SYMBOL(ipu_dp_disable_channel);
+
+void ipu_dp_enable_fg(struct ipu_dp *dp)
+{
+	u32 reg;
+
+	/* Enable FG channel */
+	reg = __raw_readl(DP_COM_CONF(DP_SYNC));
+	__raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+}
+EXPORT_SYMBOL(ipu_dp_enable_fg);
+
+void ipu_dp_disable_fg(struct ipu_dp *dp)
+{
+	u32 reg, csc;
+
+	ipu_get();
+
+	reg = __raw_readl(DP_COM_CONF(DP_SYNC));
+	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_FG)
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+	reg &= ~DP_COM_CONF_FG_EN;
+	__raw_writel(reg, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	ipu_put();
+}
+EXPORT_SYMBOL(ipu_dp_disable_fg);
+
+struct ipu_dp *ipu_dp_get(unsigned int flow)
+{
+	struct ipu_dp *dp;
+
+	if (flow > 2)
+		return ERR_PTR(-EINVAL);
+
+	dp = &ipu_dp[flow];
+
+	if (dp->in_use)
+		return ERR_PTR(-EBUSY);
+
+	dp->in_use = true;
+	dp->flow = ipu_flows[flow];
+
+	return dp;
+}
+EXPORT_SYMBOL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+	dp->in_use = false;
+}
+EXPORT_SYMBOL(ipu_dp_put);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base)
+{
+	ipu_dp_base = ioremap(base, PAGE_SIZE);
+	if (!ipu_dp_base)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	return 0;
+}
+
+void ipu_dp_exit(struct platform_device *pdev)
+{
+	 iounmap(ipu_dp_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h
new file mode 100644
index 0000000..339b554
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-prv.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+
+#define MX51_IPU_CHANNEL_CSI0			 0
+#define MX51_IPU_CHANNEL_CSI1			 1
+#define MX51_IPU_CHANNEL_CSI2			 2
+#define MX51_IPU_CHANNEL_CSI3			 3
+#define MX51_IPU_CHANNEL_MEM_BG_SYNC		23
+#define MX51_IPU_CHANNEL_MEM_FG_SYNC		27
+#define MX51_IPU_CHANNEL_MEM_DC_SYNC		28
+#define MX51_IPU_CHANNEL_MEM_FG_SYNC_ALPHA	31
+#define MX51_IPU_CHANNEL_MEM_DC_ASYNC		41
+#define MX51_IPU_CHANNEL_ROT_ENC_MEM		45
+#define MX51_IPU_CHANNEL_ROT_VF_MEM		46
+#define MX51_IPU_CHANNEL_ROT_PP_MEM		47
+#define MX51_IPU_CHANNEL_ROT_ENC_MEM_OUT	48
+#define MX51_IPU_CHANNEL_ROT_VF_MEM_OUT		49
+#define MX51_IPU_CHANNEL_ROT_PP_MEM_OUT		50
+#define MX51_IPU_CHANNEL_MEM_BG_SYNC_ALPHA	51
+
+#define IPU_DISP0_BASE		0x00000000
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_DISP1_BASE		(IPU_MCU_T_DEFAULT << 25)
+#define IPU_CM_REG_BASE		0x1e000000
+#define IPU_IDMAC_REG_BASE	0x1e008000
+#define IPU_ISP_REG_BASE	0x1e010000
+#define IPU_DP_REG_BASE		0x1e018000
+#define IPU_IC_REG_BASE		0x1e020000
+#define IPU_IRT_REG_BASE	0x1e028000
+#define IPU_CSI0_REG_BASE	0x1e030000
+#define IPU_CSI1_REG_BASE	0x1e038000
+#define IPU_DI0_REG_BASE	0x1e040000
+#define IPU_DI1_REG_BASE	0x1e048000
+#define IPU_SMFC_REG_BASE	0x1e050000
+#define IPU_DC_REG_BASE		0x1e058000
+#define IPU_DMFC_REG_BASE	0x1e060000
+#define IPU_CPMEM_REG_BASE	0x1f000000
+#define IPU_LUT_REG_BASE	0x1f020000
+#define IPU_SRM_REG_BASE	0x1f040000
+#define IPU_TPM_REG_BASE	0x1f060000
+#define IPU_DC_TMPL_REG_BASE	0x1f080000
+#define IPU_ISP_TBPR_REG_BASE	0x1f0c0000
+#define IPU_VDI_REG_BASE	0x1e068000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)	(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00b8)
+#define IPU_SKIP			IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00d4)
+#define IPU_SNOOP			IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00dc)
+#define IPU_PM				IPU_CM_REG(0x00e0)
+#define IPU_GPR				IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT			IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT		IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_CTRL_IRQ(irq)	IPU_INT_CTRL(((irq) / 32))
+#define IPU_INT_STAT_IRQ(irq)	IPU_INT_STAT(((irq) / 32))
+#define IPU_INT_STAT(n)		IPU_CM_REG(0x0200 + 4 * ((n) - 1))
+
+extern void __iomem *ipu_cm_reg;
+
+static inline u32 ipu_cm_read(unsigned offset)
+{
+	return __raw_readl(ipu_cm_reg + offset);
+}
+
+static inline void ipu_cm_write(u32 value, unsigned offset)
+{
+	__raw_writel(value, ipu_cm_reg + offset);
+}
+
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)		IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA			IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA		IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)		IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)			IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1		IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2		IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0		IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1		IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2		IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch)		IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch)		IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+extern void __iomem *ipu_idmac_reg;
+
+static inline u32 ipu_idmac_read(unsigned offset)
+{
+	return __raw_readl(ipu_idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(u32 value, unsigned offset)
+{
+	__raw_writel(value, ipu_idmac_reg + offset);
+}
+
+#define idmac_idma_is_set(reg, dma)	(ipu_idmac_read(reg(dma)) & idma_mask(dma))
+#define idma_mask(ch)			(1 << (ch & 0x1f))
+#define ipu_idma_is_set(reg, dma)	(ipu_cm_read(reg(dma)) & idma_mask(dma))
+
+enum ipu_modules {
+	IPU_CONF_CSI0_EN		= (1 << 0),
+	IPU_CONF_CSI1_EN		= (1 << 1),
+	IPU_CONF_IC_EN			= (1 << 2),
+	IPU_CONF_ROT_EN			= (1 << 3),
+	IPU_CONF_ISP_EN			= (1 << 4),
+	IPU_CONF_DP_EN			= (1 << 5),
+	IPU_CONF_DI0_EN			= (1 << 6),
+	IPU_CONF_DI1_EN			= (1 << 7),
+	IPU_CONF_SMFC_EN		= (1 << 8),
+	IPU_CONF_DC_EN			= (1 << 9),
+	IPU_CONF_DMFC_EN		= (1 << 10),
+
+	IPU_CONF_VDI_EN			= (1 << 12),
+
+	IPU_CONF_IDMAC_DIS		= (1 << 22),
+
+	IPU_CONF_IC_DMFC_SEL		= (1 << 25),
+	IPU_CONF_IC_DMFC_SYNC		= (1 << 26),
+	IPU_CONF_VDI_DMFC_SYNC		= (1 << 27),
+
+	IPU_CONF_CSI0_DATA_SOURCE	= (1 << 28),
+	IPU_CONF_CSI1_DATA_SOURCE	= (1 << 29),
+	IPU_CONF_IC_INPUT		= (1 << 30),
+	IPU_CONF_CSI_SEL		= (1 << 31),
+};
+
+struct ipu_channel {
+	unsigned int num;
+
+	bool enabled;
+	bool busy;
+};
+
+ipu_color_space_t format_to_colorspace(u32 fmt);
+bool ipu_pixel_format_has_alpha(u32 fmt);
+
+u32 _ipu_channel_status(struct ipu_channel *channel);
+
+int _ipu_chan_is_interlaced(struct ipu_channel *channel);
+
+int ipu_module_enable(u32 mask);
+int ipu_module_disable(u32 mask);
+
+int ipu_di_init(struct platform_device *pdev, int id, unsigned long base,
+		u32 module, struct clk *ipu_clk);
+void ipu_di_exit(struct platform_device *pdev, int id);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base,
+		struct clk *ipu_clk);
+void ipu_dmfc_exit(struct platform_device *pdev);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base);
+void ipu_dp_exit(struct platform_device *pdev);
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base,
+		unsigned long template_base);
+void ipu_dc_exit(struct platform_device *pdev);
+
+int ipu_cpmem_init(struct platform_device *pdev, unsigned long base);
+void ipu_cpmem_exit(struct platform_device *pdev);
+
+void ipu_get(void);
+void ipu_put(void);
+
+#endif				/* __IPU_PRV_H__ */
diff --git a/include/linux/mfd/imx-ipu-v3.h b/include/linux/mfd/imx-ipu-v3.h
new file mode 100644
index 0000000..7243360
--- /dev/null
+++ b/include/linux/mfd/imx-ipu-v3.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+typedef enum {
+	/* Note the enum values correspond to BAM value */
+	IPU_ROTATE_NONE = 0,
+	IPU_ROTATE_VERT_FLIP = 1,
+	IPU_ROTATE_HORIZ_FLIP = 2,
+	IPU_ROTATE_180 = 3,
+	IPU_ROTATE_90_RIGHT = 4,
+	IPU_ROTATE_90_RIGHT_VFLIP = 5,
+	IPU_ROTATE_90_RIGHT_HFLIP = 6,
+	IPU_ROTATE_90_LEFT = 7,
+} ipu_rotate_mode_t;
+
+/*
+ * IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/* Generic or Raw Data Formats */
+#define IPU_PIX_FMT_GENERIC v4l2_fourcc('I', 'P', 'U', '0')	/* IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 v4l2_fourcc('I', 'P', 'U', '1')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 v4l2_fourcc('L', 'V', 'D', '6')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 v4l2_fourcc('L', 'V', 'D', '8')	/* IPU Generic Data */
+/* RGB Formats */
+#define IPU_PIX_FMT_RGB332  V4L2_PIX_FMT_RGB332			/*  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  V4L2_PIX_FMT_RGB555			/* 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  V4L2_PIX_FMT_RGB565			/* 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  v4l2_fourcc('R', 'G', 'B', '6')	/* 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', '6')	/* 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   V4L2_PIX_FMT_BGR24			/* 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   V4L2_PIX_FMT_RGB24			/* 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_BGR32   V4L2_PIX_FMT_BGR32			/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  v4l2_fourcc('B', 'G', 'R', 'A')	/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   V4L2_PIX_FMT_RGB32			/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  v4l2_fourcc('R', 'G', 'B', 'A')	/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  v4l2_fourcc('A', 'B', 'G', 'R')	/* 32  ABGR-8-8-8-8 */
+/* YUV Interleaved Formats */
+#define IPU_PIX_FMT_YUYV    V4L2_PIX_FMT_YUYV			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    V4L2_PIX_FMT_UYVY			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_Y41P    V4L2_PIX_FMT_Y41P			/* 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  V4L2_PIX_FMT_YUV444			/* 24 YUV 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    V4L2_PIX_FMT_NV12			/* 12  Y/CbCr 4:2:0  */
+/* YUV Planar Formats */
+#define IPU_PIX_FMT_GREY    V4L2_PIX_FMT_GREY			/* 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P V4L2_PIX_FMT_YVU410P		/* 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P V4L2_PIX_FMT_YUV410P		/* 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P v4l2_fourcc('Y', 'V', '1', '2')	/* 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P v4l2_fourcc('I', '4', '2', '0')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 v4l2_fourcc('Y', 'U', '1', '2')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P v4l2_fourcc('Y', 'V', '1', '6')	/* 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P V4L2_PIX_FMT_YUV422P		/* 16 YUV 4:2:2 */
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+	unsigned datamask_en:1;
+	unsigned ext_clk:1;
+	unsigned interlaced:1;
+	unsigned odd_field_first:1;
+	unsigned clksel_en:1;
+	unsigned clkidle_en:1;
+	unsigned data_pol:1;	/* true = inverted */
+	unsigned clk_pol:1;	/* true = rising edge */
+	unsigned enable_pol:1;
+	unsigned Hsync_pol:1;	/* true = active high */
+	unsigned Vsync_pol:1;
+
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u16 h_start_width;
+	u16 h_sync_width;
+	u16 h_end_width;
+	u16 v_start_width;
+	u16 v_sync_width;
+	u16 v_end_width;
+	u32 v_to_h_sync;
+};
+
+typedef enum {
+	RGB,
+	YCbCr,
+	YUV
+} ipu_color_space_t;
+
+#define IPU_IRQ_EOF(channel)		(channel)		/* 0 .. 63 */
+#define IPU_IRQ_NFACK(channel)		((channel) + 64)	/* 64 .. 127 */
+#define IPU_IRQ_NFB4EOF(channel)	((channel) + 128)	/* 128 .. 191 */
+#define IPU_IRQ_EOS(channel)		((channel) + 192)	/* 192 .. 255 */
+
+#define IPU_IRQ_DP_SF_START		(448 + 2)
+#define IPU_IRQ_DP_SF_END		(448 + 3)
+#define IPU_IRQ_BG_SF_END		IPU_IRQ_DP_SF_END,
+#define IPU_IRQ_DC_FC_0			(448 + 8)
+#define IPU_IRQ_DC_FC_1			(448 + 9)
+#define IPU_IRQ_DC_FC_2			(448 + 10)
+#define IPU_IRQ_DC_FC_3			(448 + 11)
+#define IPU_IRQ_DC_FC_4			(448 + 12)
+#define IPU_IRQ_DC_FC_6			(448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0		(448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
+
+#define IPU_IRQ_COUNT	(15 * 32)
+
+#define DECLARE_IPU_IRQ_BITMAP(name)	DECLARE_BITMAP(name, IPU_IRQ_COUNT)
+
+struct ipu_irq_handler {
+	struct list_head	list;
+	void			(*handler)(unsigned long *, void *);
+	void			*context;
+	DECLARE_IPU_IRQ_BITMAP(ipu_irqs);
+};
+
+int ipu_irq_add_handler(struct ipu_irq_handler *ipuirq);
+void ipu_irq_remove_handler(struct ipu_irq_handler *handler);
+int ipu_irq_update_handler(struct ipu_irq_handler *handler,
+		unsigned long *bitmap);
+int ipu_wait_for_interrupt(int interrupt, int timeout_ms);
+
+struct ipu_channel;
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipu_channel *ipu_idmac_get(unsigned channel);
+void ipu_idmac_put(struct ipu_channel *);
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u_offset, u32 v_offset, bool interlaced);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 bufNum, dma_addr_t phyaddr);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel);
+int ipu_idmac_disable_channel(struct ipu_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+int ipu_dc_init_sync(int dc_chan, int di, bool interlaced, u32 pixel_fmt, u32 width);
+void ipu_dc_init_async(int dc_chan, int di, bool interlaced);
+void ipu_dc_enable_channel(u32 dc_chan);
+void ipu_dc_disable_channel(u32 dc_chan);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di;
+struct ipu_di *ipu_di_get(int disp);
+void ipu_di_put(struct ipu_di *);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, u32 pixel_clk,
+		struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, unsigned long bandwidth_mbs);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(int ipu_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC	0
+#define IPU_DP_FLOW_ASYNC0	1
+#define IPU_DP_FLOW_ASYNC1	2
+
+struct ipu_dp *ipu_dp_get(unsigned int flow);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+void ipu_dp_enable_fg(struct ipu_dp *dp);
+void ipu_dp_disable_fg(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 colorKey);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+		bool bg_chan);
+
+#endif
-- 
1.7.2.3


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

* [PATCH 1/7] Add a mfd IPUv3 driver
@ 2011-02-16 14:10   ` Sascha Hauer
  0 siblings, 0 replies; 32+ messages in thread
From: Sascha Hauer @ 2011-02-16 14:10 UTC (permalink / raw)
  To: linux-arm-kernel

The IPU is the Image Processing Unit found on i.MX51/53 SoCs. It
features several units for image processing, this patch adds support
for the units needed for Framebuffer support, namely:

- Display Controller (dc)
- Display Interface (di)
- Display Multi Fifo Controller (dmfc)
- Display Processor (dp)
- Image DMA Controller (idmac)

This patch is based on the Freescale driver, but follows a different
approach. The Freescale code implements logical idmac channels and
the handling of the subunits is hidden in common idmac code pathes
in big switch/case statements. This patch instead just provides code
and resource management for the different subunits. The user, in this
case the framebuffer driver, decides how the different units play
together.

The IPU has other units missing in this patch:

- CMOS Sensor Interface (csi)
- Video Deinterlacer (vdi)
- Sensor Multi FIFO Controler (smfc)
- Image Converter (ic)
- Image Rotator (irt)

So expect more files to come in this directory.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Cc: linux-kernel at vger.kernel.org
Cc: linux-fbdev at vger.kernel.org
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Samuel Ortiz <sameo@linux.intel.com>
---
 arch/arm/plat-mxc/include/mach/ipu-v3.h |   49 +++
 drivers/video/Kconfig                   |    2 +
 drivers/video/Makefile                  |    1 +
 drivers/video/imx-ipu-v3/Makefile       |    3 +
 drivers/video/imx-ipu-v3/ipu-common.c   |  708 +++++++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-cpmem.c    |  612 ++++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dc.c       |  364 ++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-di.c       |  550 ++++++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dmfc.c     |  355 ++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-dp.c       |  476 +++++++++++++++++++++
 drivers/video/imx-ipu-v3/ipu-prv.h      |  216 ++++++++++
 include/linux/mfd/imx-ipu-v3.h          |  219 ++++++++++
 12 files changed, 3555 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-mxc/include/mach/ipu-v3.h
 create mode 100644 drivers/video/imx-ipu-v3/Makefile
 create mode 100644 drivers/video/imx-ipu-v3/ipu-common.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-cpmem.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dc.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-di.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dmfc.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-dp.c
 create mode 100644 drivers/video/imx-ipu-v3/ipu-prv.h
 create mode 100644 include/linux/mfd/imx-ipu-v3.h

diff --git a/arch/arm/plat-mxc/include/mach/ipu-v3.h b/arch/arm/plat-mxc/include/mach/ipu-v3.h
new file mode 100644
index 0000000..f8900b9
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ *
+ * 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.
+ */
+
+#ifndef __MACH_IPU_V3_H_
+#define __MACH_IPU_V3_H_
+
+/* IPU specific extensions to struct fb_videomode flag field */
+#define FB_SYNC_OE_LOW_ACT	(1 << 8)
+#define FB_SYNC_CLK_LAT_FALL	(1 << 9)
+#define FB_SYNC_DATA_INVERT	(1 << 10)
+#define FB_SYNC_CLK_IDLE_EN	(1 << 11)
+#define FB_SYNC_SHARP_MODE	(1 << 12)
+#define FB_SYNC_SWAP_RGB	(1 << 13)
+
+struct ipuv3_fb_platform_data {
+	const struct fb_videomode	*modes;
+	int				num_modes;
+	char				*mode_str;
+	u32				interface_pix_fmt;
+
+#define IMX_IPU_FB_USE_MODEDB	(1 << 0)
+#define IMX_IPU_FB_USE_OVERLAY	(1 << 1)
+	unsigned long			flags;
+
+	int				ipu_channel_bg;
+	int				ipu_channel_fg;
+	int				dc_channel;
+	int				dp_channel;
+	int				display;
+};
+
+struct imx_ipuv3_platform_data {
+	int rev;
+	struct ipuv3_fb_platform_data	*fb_head0_platform_data;
+	struct ipuv3_fb_platform_data	*fb_head1_platform_data;
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 6bafb51b..ffdb37a 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -26,6 +26,8 @@ source "drivers/gpu/drm/Kconfig"
 
 source "drivers/gpu/stub/Kconfig"
 
+source "drivers/video/imx-ipu-v3/Kconfig"
+
 config VGASTATE
        tristate
        default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 8c8fabd..f4921ab 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -153,6 +153,7 @@ obj-$(CONFIG_FB_BFIN_T350MCQB)	  += bfin-t350mcqb-fb.o
 obj-$(CONFIG_FB_BFIN_7393)        += bfin_adv7393fb.o
 obj-$(CONFIG_FB_MX3)		  += mx3fb.o
 obj-$(CONFIG_FB_DA8XX)		  += da8xx-fb.o
+obj-$(CONFIG_MFD_IMX_IPU_V3)	  += imx-ipu-v3/
 
 # the test framebuffer is last
 obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
diff --git a/drivers/video/imx-ipu-v3/Makefile b/drivers/video/imx-ipu-v3/Makefile
new file mode 100644
index 0000000..ff70fe8
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MFD_IMX_IPU_V3) += imx-ipu-v3.o
+
+imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o ipu-cpmem.o
diff --git a/drivers/video/imx-ipu-v3/ipu-common.c b/drivers/video/imx-ipu-v3/ipu-common.c
new file mode 100644
index 0000000..d96245f
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-common.c
@@ -0,0 +1,708 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/clk.h>
+#include <linux/list.h>
+#include <mach/common.h>
+#include <linux/mfd/core.h>
+#include <mach/ipu-v3.h>
+
+#include "ipu-prv.h"
+
+static struct clk *ipu_clk;
+static struct device *ipu_dev;
+
+static DEFINE_SPINLOCK(ipu_lock);
+static DEFINE_MUTEX(ipu_channel_lock);
+void __iomem *ipu_cm_reg;
+void __iomem *ipu_idmac_reg;
+
+static int ipu_use_count;
+
+static struct ipu_channel channels[64];
+
+struct ipu_channel *ipu_idmac_get(unsigned num)
+{
+	struct ipu_channel *channel;
+
+	dev_dbg(ipu_dev, "%s %d\n", __func__, num);
+
+	if (num > 63)
+		return ERR_PTR(-ENODEV);
+
+	mutex_lock(&ipu_channel_lock);
+
+	channel = &channels[num];
+
+	if (channel->busy) {
+		channel = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	channel->busy = 1;
+	channel->num = num;
+
+out:
+	mutex_unlock(&ipu_channel_lock);
+
+	return channel;
+}
+EXPORT_SYMBOL(ipu_idmac_get);
+
+void ipu_idmac_put(struct ipu_channel *channel)
+{
+	dev_dbg(ipu_dev, "%s %d\n", __func__, channel->num);
+
+	mutex_lock(&ipu_channel_lock);
+
+	channel->busy = 0;
+
+	mutex_unlock(&ipu_channel_lock);
+}
+EXPORT_SYMBOL(ipu_idmac_put);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer)
+{
+	unsigned long flags;
+	u32 reg;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	reg = ipu_cm_read(IPU_CHA_DB_MODE_SEL(channel->num));
+	if (doublebuffer)
+		reg |= idma_mask(channel->num);
+	else
+		reg &= ~idma_mask(channel->num);
+	ipu_cm_write(reg, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_idmac_set_double_buffer);
+
+int ipu_module_enable(u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(IPU_CONF);
+	ipu_conf |= mask;
+	ipu_cm_write(ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu_lock, lock_flags);
+
+	return 0;
+}
+
+int ipu_module_disable(u32 mask)
+{
+	unsigned long lock_flags;
+	u32 ipu_conf;
+
+	spin_lock_irqsave(&ipu_lock, lock_flags);
+
+	ipu_conf = ipu_cm_read(IPU_CONF);
+	ipu_conf &= ~mask;
+	ipu_cm_write(ipu_conf, IPU_CONF);
+
+	spin_unlock_irqrestore(&ipu_lock, lock_flags);
+
+	return 0;
+}
+
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num)
+{
+	unsigned int chno = channel->num;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	/* Mark buffer as ready. */
+	if (buf_num == 0)
+		ipu_cm_write(idma_mask(chno), IPU_CHA_BUF0_RDY(chno));
+	else
+		ipu_cm_write(idma_mask(chno), IPU_CHA_BUF1_RDY(chno));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_idmac_select_buffer);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel)
+{
+	u32 val;
+	unsigned long flags;
+
+	ipu_get();
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	val = ipu_idmac_read(IDMAC_CHA_EN(channel->num));
+	val |= idma_mask(channel->num);
+	ipu_idmac_write(val, IDMAC_CHA_EN(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_enable_channel);
+
+int ipu_idmac_disable_channel(struct ipu_channel *channel)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	/* Disable DMA channel(s) */
+	val = ipu_idmac_read(IDMAC_CHA_EN(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_idmac_write(val, IDMAC_CHA_EN(channel->num));
+
+	/* Set channel buffers NOT to be ready */
+	ipu_cm_write(0xf0000000, IPU_GPR); /* write one to clear */
+
+	if (ipu_idma_is_set(IPU_CHA_BUF0_RDY, channel->num)) {
+		ipu_cm_write(idma_mask(channel->num),
+			     IPU_CHA_BUF0_RDY(channel->num));
+	}
+	if (ipu_idma_is_set(IPU_CHA_BUF1_RDY, channel->num)) {
+		ipu_cm_write(idma_mask(channel->num),
+			     IPU_CHA_BUF1_RDY(channel->num));
+	}
+
+	ipu_cm_write(0x0, IPU_GPR); /* write one to set */
+
+	/* Reset the double buffer */
+	val = ipu_cm_read(IPU_CHA_DB_MODE_SEL(channel->num));
+	val &= ~idma_mask(channel->num);
+	ipu_cm_write(val, IPU_CHA_DB_MODE_SEL(channel->num));
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_disable_channel);
+
+static LIST_HEAD(ipu_irq_handlers);
+
+static void ipu_irq_update_irq_mask(void)
+{
+	struct ipu_irq_handler *handler;
+	int i;
+
+	DECLARE_IPU_IRQ_BITMAP(irqs);
+
+	bitmap_zero(irqs, IPU_IRQ_COUNT);
+
+	list_for_each_entry(handler, &ipu_irq_handlers, list)
+		bitmap_or(irqs, irqs, handler->ipu_irqs, IPU_IRQ_COUNT);
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++)
+		ipu_cm_write(irqs[i], IPU_INT_CTRL(i + 1));
+}
+
+int ipu_irq_add_handler(struct ipu_irq_handler *ipuirq)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	list_add_tail(&ipuirq->list, &ipu_irq_handlers);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_irq_add_handler);
+
+void ipu_irq_remove_handler(struct ipu_irq_handler *handler)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	list_del(&handler->list);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+}
+EXPORT_SYMBOL(ipu_irq_remove_handler);
+
+int ipu_irq_update_handler(struct ipu_irq_handler *handler,
+		unsigned long *bitmap)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ipu_lock, flags);
+
+	bitmap_copy(handler->ipu_irqs, bitmap, IPU_IRQ_COUNT);
+	ipu_irq_update_irq_mask();
+
+	spin_unlock_irqrestore(&ipu_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_irq_update_handler);
+
+static void ipu_completion_handler(unsigned long *bitmask, void *context)
+{
+	struct completion *completion = context;
+
+	complete(completion);
+}
+
+int ipu_wait_for_interrupt(int interrupt, int timeout_ms)
+{
+	struct ipu_irq_handler handler;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	int ret;
+
+	bitmap_zero(handler.ipu_irqs, IPU_IRQ_COUNT);
+	bitmap_set(handler.ipu_irqs, interrupt, 1);
+
+	ipu_cm_write(1 << (interrupt % 32), IPU_INT_STAT(interrupt / 32 + 1));
+
+	handler.handler = ipu_completion_handler;
+	handler.context = &completion;
+	ipu_irq_add_handler(&handler);
+
+	ret = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(timeout_ms));
+
+	ipu_irq_remove_handler(&handler);
+
+	if (ret > 0)
+		ret = 0;
+	else
+		ret = -ETIMEDOUT;
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_wait_for_interrupt);
+
+static irqreturn_t ipu_irq_handler(int irq, void *desc)
+{
+	DECLARE_IPU_IRQ_BITMAP(status);
+	struct ipu_irq_handler *handler;
+	int i;
+
+	for (i = 0; i < BITS_TO_LONGS(IPU_IRQ_COUNT); i++) {
+		status[i] = ipu_cm_read(IPU_INT_STAT(i + 1));
+		ipu_cm_write(status[i], IPU_INT_STAT(i + 1));
+	}
+
+	list_for_each_entry(handler, &ipu_irq_handlers, list) {
+		DECLARE_IPU_IRQ_BITMAP(tmp);
+		if (bitmap_and(tmp, status, handler->ipu_irqs, IPU_IRQ_COUNT))
+			handler->handler(tmp, handler->context);
+	}
+
+	return IRQ_HANDLED;
+}
+
+ipu_color_space_t format_to_colorspace(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB666:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_LVDS666:
+	case IPU_PIX_FMT_LVDS888:
+		return RGB;
+
+	default:
+		return YCbCr;
+	}
+}
+
+static int ipu_reset(void)
+{
+	int timeout = 10000;
+	u32 val;
+
+	/* hard reset the IPU */
+	val = readl(MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+	val |= 1 << 3;
+	writel(val, MX51_IO_ADDRESS(MX51_SRC_BASE_ADDR));
+
+	ipu_cm_write(0x807FFFFF, IPU_MEM_RST);
+
+	while (ipu_cm_read(IPU_MEM_RST) & 0x80000000) {
+		if (!timeout--)
+			return -ETIME;
+		udelay(100);
+	}
+
+	return 0;
+}
+
+/*
+ * The MIPI HSC unit has been removed from the i.MX51 Reference Manual by
+ * the Freescale marketing division. However this did not remove the
+ * hardware from the chip which still needs to be configured...
+ */
+static int __devinit ipu_mipi_setup(void)
+{
+	struct clk *hsc_clk;
+	void __iomem *hsc_addr;
+	int ret = 0;
+
+	hsc_addr = ioremap(MX51_MIPI_HSC_BASE_ADDR, PAGE_SIZE);
+	if (!hsc_addr)
+		return -ENOMEM;
+
+	hsc_clk = clk_get_sys(NULL, "mipi_hsp");
+	if (IS_ERR(hsc_clk)) {
+		ret = PTR_ERR(hsc_clk);
+		goto unmap;
+	}
+	clk_enable(hsc_clk);
+
+	/* setup MIPI module to legacy mode */
+	__raw_writel(0xF00, hsc_addr);
+
+	/* CSI mode: reserved; DI control mode: legacy (from Freescale BSP) */
+	__raw_writel(__raw_readl(hsc_addr + 0x800) | 0x30ff,
+		hsc_addr + 0x800);
+
+	clk_disable(hsc_clk);
+	clk_put(hsc_clk);
+unmap:
+	iounmap(hsc_addr);
+
+	return ret;
+}
+
+static int ipu_submodules_init(struct platform_device *pdev,
+		unsigned long ipu_base, struct clk *ipu_clk)
+{
+	char *unit;
+	int ret;
+
+	ret = ipu_di_init(pdev, 0, ipu_base + IPU_DI0_REG_BASE,
+			IPU_CONF_DI0_EN, ipu_clk);
+	if (ret) {
+		unit = "di0";
+		goto err_di_0;
+	}
+
+	ret = ipu_di_init(pdev, 1, ipu_base + IPU_DI1_REG_BASE,
+			IPU_CONF_DI1_EN, ipu_clk);
+	if (ret) {
+		unit = "di1";
+		goto err_di_1;
+	}
+
+	ret = ipu_dc_init(pdev, ipu_base + IPU_DC_REG_BASE,
+			ipu_base + IPU_DC_TMPL_REG_BASE);
+	if (ret) {
+		unit = "dc_template";
+		goto err_dc;
+	}
+
+	ret = ipu_dmfc_init(pdev, ipu_base + IPU_DMFC_REG_BASE, ipu_clk);
+	if (ret) {
+		unit = "dmfc";
+		goto err_dmfc;
+	}
+
+	ret = ipu_dp_init(pdev, ipu_base + IPU_SRM_REG_BASE);
+	if (ret) {
+		unit = "dp";
+		goto err_dp;
+	}
+
+	ret = ipu_cpmem_init(pdev, ipu_base + IPU_CPMEM_REG_BASE);
+	if (ret) {
+		unit = "cpmem";
+		goto err_cpmem;
+	}
+
+	return 0;
+
+err_cpmem:
+	ipu_dp_exit(pdev);
+err_dp:
+	ipu_dmfc_exit(pdev);
+err_dmfc:
+	ipu_dc_exit(pdev);
+err_dc:
+	ipu_di_exit(pdev, 1);
+err_di_1:
+	ipu_di_exit(pdev, 0);
+err_di_0:
+	dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret);
+	return ret;
+}
+
+void ipu_get(void)
+{
+	mutex_lock(&ipu_channel_lock);
+
+	ipu_use_count++;
+
+	if (ipu_use_count == 1)
+		clk_enable(ipu_clk);
+
+	mutex_unlock(&ipu_channel_lock);
+}
+
+void ipu_put(void)
+{
+	mutex_lock(&ipu_channel_lock);
+
+	ipu_use_count--;
+
+	if (ipu_use_count == 0)
+		clk_disable(ipu_clk);
+
+	if (ipu_use_count < 0) {
+		dev_err(ipu_dev, "ipu use count < 0\n");
+		ipu_use_count = 0;
+	}
+
+	mutex_unlock(&ipu_channel_lock);
+}
+
+static void ipu_submodules_exit(struct platform_device *pdev,
+		unsigned long ipu_base)
+{
+	ipu_cpmem_exit(pdev);
+	ipu_dp_exit(pdev);
+	ipu_dmfc_exit(pdev);
+	ipu_dc_exit(pdev);
+	ipu_di_exit(pdev, 1);
+	ipu_di_exit(pdev, 0);
+}
+
+static int ipu_add_subdevice_pdata(struct platform_device *pdev,
+		const char *name, int id, void *pdata, size_t pdata_size)
+{
+	struct mfd_cell cell = {
+		.platform_data = pdata,
+		.data_size = pdata_size,
+	};
+
+	cell.name = name;
+
+	return mfd_add_devices(&pdev->dev, id, &cell, 1, NULL, 0);
+}
+
+static int ipu_add_client_devices(struct platform_device *pdev)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipuv3_fb_platform_data *fbdata;
+
+	fbdata = plat_data->fb_head0_platform_data;
+	if (fbdata) {
+		fbdata->ipu_channel_bg =
+			MX51_IPU_CHANNEL_MEM_BG_SYNC;
+		fbdata->ipu_channel_fg =
+			MX51_IPU_CHANNEL_MEM_FG_SYNC;
+		fbdata->dc_channel = 5;
+		fbdata->dp_channel = IPU_DP_FLOW_SYNC;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 0,
+				fbdata, sizeof(*fbdata));
+	}
+
+	fbdata = plat_data->fb_head1_platform_data;
+	if (fbdata) {
+		fbdata->ipu_channel_bg =
+			MX51_IPU_CHANNEL_MEM_DC_SYNC;
+		fbdata->ipu_channel_fg = -1;
+		fbdata->dc_channel = 1;
+		fbdata->dp_channel = -1;
+
+		ipu_add_subdevice_pdata(pdev, "imx-ipuv3-fb", 1,
+				fbdata, sizeof(*fbdata));
+	}
+
+	return 0;
+}
+
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned long ipu_base;
+	int ret, irq1, irq2;
+
+	/* There can be only one */
+	if (ipu_dev)
+		return -EBUSY;
+
+	spin_lock_init(&ipu_lock);
+
+	ipu_dev = &pdev->dev;
+
+	irq1 = platform_get_irq(pdev, 0);
+	irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || irq1 < 0 || irq2 < 0)
+		return -ENODEV;
+
+	ipu_base = res->start;
+
+	ipu_cm_reg = ioremap(ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+	if (!ipu_cm_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap1;
+	}
+
+	ipu_idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+	if (!ipu_idmac_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap2;
+	}
+
+	ret = ipu_mipi_setup();
+	if (ret)
+		goto failed_mipi_setup;
+
+	ipu_clk = clk_get(&pdev->dev, "ipu");
+	if (IS_ERR(ipu_clk)) {
+		ret = PTR_ERR(ipu_clk);
+		dev_err(&pdev->dev, "clk_get failed with %d", ret);
+		goto failed_clk_get;
+	}
+
+	ipu_get();
+
+	ret = request_irq(irq1, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq1, ret);
+		goto failed_request_irq1;
+	}
+
+	ret = request_irq(irq2, ipu_irq_handler, IRQF_DISABLED, pdev->name,
+			&pdev->dev);
+	if (ret) {
+		dev_err(&pdev->dev, "request irq %d failed with: %d\n", irq2, ret);
+		goto failed_request_irq2;
+	}
+
+	ipu_reset();
+
+	ret = ipu_submodules_init(pdev, ipu_base, ipu_clk);
+	if (ret)
+		goto failed_submodules_init;
+
+	/* Set sync refresh channels as high priority */
+	ipu_idmac_write(0x18800000, IDMAC_CHA_PRI(0));
+
+	ret = ipu_add_client_devices(pdev);
+        if (ret) {
+                dev_err(&pdev->dev, "adding client devices failed with %d\n", ret);
+		goto failed_add_clients;
+        }
+
+	ipu_put();
+
+	return 0;
+
+failed_add_clients:
+	ipu_submodules_exit(pdev, ipu_base);
+failed_submodules_init:
+	free_irq(irq2, &pdev->dev);
+failed_request_irq2:
+	free_irq(irq1, &pdev->dev);
+	ipu_put();
+failed_request_irq1:
+	clk_put(ipu_clk);
+failed_clk_get:
+failed_mipi_setup:
+	iounmap(ipu_idmac_reg);
+failed_ioremap2:
+	iounmap(ipu_cm_reg);
+failed_ioremap1:
+
+	return ret;
+}
+
+static int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+	unsigned long ipu_base;
+	int irq1, irq2;
+
+	irq1 = platform_get_irq(pdev, 0);
+	irq2 = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	ipu_base = res->start;
+
+	mfd_remove_devices(&pdev->dev);
+	ipu_submodules_exit(pdev, ipu_base);
+	free_irq(irq2, &pdev->dev);
+	free_irq(irq1, &pdev->dev);
+	iounmap(ipu_idmac_reg);
+	iounmap(ipu_cm_reg);
+
+	if (ipu_use_count != 0) {
+		dev_err(ipu_dev, "unbalanced use count: %d\n", ipu_use_count);
+		clk_disable(ipu_clk);
+	}
+
+	clk_put(ipu_clk);
+	ipu_dev = NULL;
+
+	return 0;
+}
+
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+		.name = "imx-ipuv3",
+	},
+	.probe = ipu_probe,
+	.remove = __devexit_p(ipu_remove),
+};
+
+static int __init ipu_gen_init(void)
+{
+	int32_t ret;
+
+	ret = platform_driver_register(&mxcipu_driver);
+	return 0;
+}
+subsys_initcall(ipu_gen_init);
+
+static void __exit ipu_gen_uninit(void)
+{
+	platform_driver_unregister(&mxcipu_driver);
+}
+module_exit(ipu_gen_uninit);
+
+MODULE_DESCRIPTION("i.MX IPU v3 driver");
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/imx-ipu-v3/ipu-cpmem.c b/drivers/video/imx-ipu-v3/ipu-cpmem.c
new file mode 100644
index 0000000..faff5ee
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-cpmem.c
@@ -0,0 +1,612 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/kernel.h>
+#include <linux/device.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/types.h>
+#include <linux/bitrev.h>
+#include <linux/io.h>
+
+#include "ipu-prv.h"
+
+#define __F(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size))
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_UBO		__F(0, 46, 22)
+#define IPU_FIELD_VBO		__F(0, 68, 22)
+#define IPU_FIELD_IOX		__F(0, 90, 4)
+#define IPU_FIELD_RDRW		__F(0, 94, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SLY		__F(1, 102, 14)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_SLUV		__F(1, 128, 14)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+
+#define IPU_FIELD_XV		__F(0, 0, 10)
+#define IPU_FIELD_YV		__F(0, 10, 9)
+#define IPU_FIELD_XB		__F(0, 19, 13)
+#define IPU_FIELD_YB		__F(0, 32, 12)
+#define IPU_FIELD_NSB_B		__F(0, 44, 1)
+#define IPU_FIELD_CF		__F(0, 45, 1)
+#define IPU_FIELD_SX		__F(0, 46, 12)
+#define IPU_FIELD_SY		__F(0, 58, 11)
+#define IPU_FIELD_NS		__F(0, 69, 10)
+#define IPU_FIELD_SDX		__F(0, 79, 7)
+#define IPU_FIELD_SM		__F(0, 86, 10)
+#define IPU_FIELD_SCC		__F(0, 96, 1)
+#define IPU_FIELD_SCE		__F(0, 97, 1)
+#define IPU_FIELD_SDY		__F(0, 98, 7)
+#define IPU_FIELD_SDRX		__F(0, 105, 1)
+#define IPU_FIELD_SDRY		__F(0, 106, 1)
+#define IPU_FIELD_BPP		__F(0, 107, 3)
+#define IPU_FIELD_DEC_SEL	__F(0, 110, 2)
+#define IPU_FIELD_DIM		__F(0, 112, 1)
+#define IPU_FIELD_SO		__F(0, 113, 1)
+#define IPU_FIELD_BNDM		__F(0, 114, 3)
+#define IPU_FIELD_BM		__F(0, 117, 2)
+#define IPU_FIELD_ROT		__F(0, 119, 1)
+#define IPU_FIELD_HF		__F(0, 120, 1)
+#define IPU_FIELD_VF		__F(0, 121, 1)
+#define IPU_FIELD_THE		__F(0, 122, 1)
+#define IPU_FIELD_CAP		__F(0, 123, 1)
+#define IPU_FIELD_CAE		__F(0, 124, 1)
+#define IPU_FIELD_FW		__F(0, 125, 13)
+#define IPU_FIELD_FH		__F(0, 138, 12)
+#define IPU_FIELD_EBA0		__F(1, 0, 29)
+#define IPU_FIELD_EBA1		__F(1, 29, 29)
+#define IPU_FIELD_ILO		__F(1, 58, 20)
+#define IPU_FIELD_NPB		__F(1, 78, 7)
+#define IPU_FIELD_PFS		__F(1, 85, 4)
+#define IPU_FIELD_ALU		__F(1, 89, 1)
+#define IPU_FIELD_ALBM		__F(1, 90, 3)
+#define IPU_FIELD_ID		__F(1, 93, 2)
+#define IPU_FIELD_TH		__F(1, 95, 7)
+#define IPU_FIELD_SL		__F(1, 102, 14)
+#define IPU_FIELD_WID0		__F(1, 116, 3)
+#define IPU_FIELD_WID1		__F(1, 119, 3)
+#define IPU_FIELD_WID2		__F(1, 122, 3)
+#define IPU_FIELD_WID3		__F(1, 125, 3)
+#define IPU_FIELD_OFS0		__F(1, 128, 5)
+#define IPU_FIELD_OFS1		__F(1, 133, 5)
+#define IPU_FIELD_OFS2		__F(1, 138, 5)
+#define IPU_FIELD_OFS3		__F(1, 143, 5)
+#define IPU_FIELD_SXYS		__F(1, 148, 1)
+#define IPU_FIELD_CRE		__F(1, 149, 1)
+#define IPU_FIELD_DEC_SEL2	__F(1, 150, 1)
+
+static u32 *ipu_cpmem_base;
+static struct device *ipu_dev;
+
+struct ipu_ch_param_word {
+	u32 data[5];
+	u32 res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+static u32 ipu_bytes_per_pixel(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/* generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YUV422P:
+		return 1;
+
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		return 2;
+
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+		return 3;
+
+	case IPU_PIX_FMT_GENERIC_32:	/* generic data */
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_ABGR32:
+		return 4;
+
+	default:
+		return 1;
+	}
+}
+
+bool ipu_pixel_format_has_alpha(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+
+	default:
+		return false;
+	}
+}
+
+#define ipu_ch_param_addr(ch) (((struct ipu_ch_param *)ipu_cpmem_base) + (ch))
+
+static inline void ipu_ch_param_set_field(struct ipu_ch_param *base, u32 wbs, u32 v)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	base->word[word].data[i] &= ~(mask << ofs);
+	base->word[word].data[i] |= v << ofs;
+
+	if ((bit + size - 1) / 32 > i) {
+		base->word[word].data[i + 1] &= ~(v >> (mask ? (32 - ofs) : 0));
+		base->word[word].data[i + 1] |= v >> (ofs ? (32 - ofs) : 0);
+	}
+}
+
+static inline u32 ipu_ch_param_read_field(struct ipu_ch_param *base, u32 wbs)
+{
+	u32 bit = (wbs >> 8) % 160;
+	u32 size = wbs & 0xff;
+	u32 word = (wbs >> 8) / 160;
+	u32 i = bit / 32;
+	u32 ofs = bit % 32;
+	u32 mask = (1 << size) - 1;
+	u32 val = 0;
+
+	pr_debug("%s %d %d %d\n", __func__, word, bit , size);
+
+	val = (base->word[word].data[i] >> ofs) & mask;
+
+	if ((bit + size - 1) / 32 > i) {
+		u32 tmp;
+		tmp = base->word[word].data[i + 1];
+		tmp &= mask >> (ofs ? (32 - ofs) : 0);
+		val |= tmp << (ofs ? (32 - ofs) : 0);
+	}
+
+	return val;
+}
+
+static inline void ipu_ch_params_set_packing(struct ipu_ch_param *p,
+					      int red_width, int red_offset,
+					      int green_width, int green_offset,
+					      int blue_width, int blue_offset,
+					      int alpha_width, int alpha_offset)
+{
+	/* Setup red width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID0, red_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS0, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID1, green_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS1, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID2, blue_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS2, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, IPU_FIELD_WID3, alpha_width - 1);
+	ipu_ch_param_set_field(p, IPU_FIELD_OFS3, alpha_offset);
+}
+
+static inline void ipu_ch_param_dump(int ch)
+{
+	struct ipu_ch_param *p = ipu_ch_param_addr(ch);
+	pr_debug("ch %d word 0 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[0].data[0], p->word[0].data[1], p->word[0].data[2],
+		 p->word[0].data[3], p->word[0].data[4]);
+	pr_debug("ch %d word 1 - %08X %08X %08X %08X %08X\n", ch,
+		 p->word[1].data[0], p->word[1].data[1], p->word[1].data[2],
+		 p->word[1].data[3], p->word[1].data[4]);
+	pr_debug("PFS 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_PFS));
+	pr_debug("BPP 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_BPP));
+	pr_debug("NPB 0x%x\n", ipu_ch_param_read_field(p, IPU_FIELD_NPB));
+
+	pr_debug("FW %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FW));
+	pr_debug("FH %d\n", ipu_ch_param_read_field(p, IPU_FIELD_FH));
+	pr_debug("Stride %d\n", ipu_ch_param_read_field(p, IPU_FIELD_SL));
+
+	pr_debug("Width0 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID0));
+	pr_debug("Width1 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID1));
+	pr_debug("Width2 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID2));
+	pr_debug("Width3 %d+1\n", ipu_ch_param_read_field(p, IPU_FIELD_WID3));
+	pr_debug("Offset0 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS0));
+	pr_debug("Offset1 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS1));
+	pr_debug("Offset2 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS2));
+	pr_debug("Offset3 %d\n", ipu_ch_param_read_field(p, IPU_FIELD_OFS3));
+}
+
+static inline void ipu_ch_param_set_burst_size(u32 ch,
+						u16 burst_pixels)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_NPB,
+			       burst_pixels - 1);
+};
+
+static inline int ipu_ch_param_get_burst_size(u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_NPB) + 1;
+};
+
+static inline int ipu_ch_param_get_bpp(u32 ch)
+{
+	return ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_BPP);
+};
+
+static inline void ipu_ch_param_set_buffer(u32 ch, int bufNum,
+					    dma_addr_t phyaddr)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch),
+			bufNum ? IPU_FIELD_EBA1 : IPU_FIELD_EBA0,
+			phyaddr / 8);
+};
+
+#define IPU_FIELD_ROT_HF_VF		__F(0, 119, 3)
+
+static inline void ipu_ch_param_set_rotation(u32 ch,
+					      ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ROT_HF_VF, temp_rot);
+};
+
+static inline void ipu_ch_param_set_block_mode(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_BM, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_use_separate_channel(u32 ch,
+		bool option)
+{
+	if (option)
+		ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALU, 1);
+	else
+		ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALU, 0);
+};
+
+static inline void ipu_ch_param_set_alpha_condition_read(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_CRE, 1);
+};
+
+static inline void ipu_ch_param_set_alpha_buffer_memory(u32 ch)
+{
+	int alp_mem_idx;
+
+	switch (ch) {
+	case 14: /* PRP graphic */
+		alp_mem_idx = 0;
+		break;
+	case 15: /* PP graphic */
+		alp_mem_idx = 1;
+		break;
+	case 23: /* DP BG SYNC graphic */
+		alp_mem_idx = 4;
+		break;
+	case 27: /* DP FG SYNC graphic */
+		alp_mem_idx = 2;
+		break;
+	default:
+		dev_err(ipu_dev, "unsupported correlated channel of local alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ALBM, alp_mem_idx);
+};
+
+static inline void ipu_ch_param_set_interlaced_scan(u32 ch)
+{
+	u32 stride;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_SO, 1);
+	stride = ipu_ch_param_read_field(ipu_ch_param_addr(ch), IPU_FIELD_SL) + 1;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ILO, stride / 8);
+	stride *= 2;
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_SLY, stride - 1);
+};
+
+static inline void ipu_ch_param_set_high_priority(u32 ch)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_ID, 1);
+};
+
+static inline void ipu_ch_params_set_alpha_width(u32 ch, int alpha_width)
+{
+	ipu_ch_param_set_field(ipu_ch_param_addr(ch), IPU_FIELD_WID3,
+			alpha_width - 1);
+}
+
+static int ipu_ch_param_init(int ch,
+			u32 pixel_fmt, u32 width,
+			u32 height, u32 stride,
+			u32 u, u32 v,
+			u32 uv_stride, dma_addr_t addr0,
+			dma_addr_t addr1)
+{
+	u32 u_offset = 0;
+	u32 v_offset = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_FW, width - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_FH, height - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_SLY, stride - 1);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA0, addr0 >> 3);
+	ipu_ch_param_set_field(&params, IPU_FIELD_EBA1, addr1 >> 3);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/* Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 63);	/* burst size */
+
+		break;
+	case IPU_PIX_FMT_GENERIC_32:
+		/* Represents 32-bit Generic data */
+		break;
+	case IPU_PIX_FMT_RGB565:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 8, 16);
+		break;
+	case IPU_PIX_FMT_BGR24:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 19);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 8, 8, 16, 8, 24, 8, 0);
+		break;
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+
+		ipu_ch_params_set_packing(&params, 8, 24, 8, 16, 8, 8, 8, 0);
+		break;
+	case IPU_PIX_FMT_ABGR32:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 7);	/* pix format */
+
+		ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_UYVY:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0xA);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 15);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, IPU_FIELD_BPP, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 0x8);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);  /* burst size */
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = (v == 0) ? stride * height : v;
+		u_offset = (u == 0) ? v_offset + v_offset / 2 : u;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = (u == 0) ? stride * height : u;
+		v_offset = (v == 0) ? u_offset + u_offset / 2 : v;
+		break;
+	case IPU_PIX_FMT_NV12:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_PFS, 4);	/* pix format */
+		ipu_ch_param_set_field(&params, IPU_FIELD_NPB, 31);	/* burst size */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		break;
+	default:
+		dev_err(ipu_dev, "mxc ipu: unimplemented pixel format: %d\n",
+			pixel_fmt);
+		return -EINVAL;
+	}
+	/* set burst size to 16 */
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, IPU_FIELD_SLUV, uv_stride - 1);
+
+	if (u > u_offset)
+		u_offset = u;
+
+	if (v > v_offset)
+		v_offset = v;
+
+	ipu_ch_param_set_field(&params, IPU_FIELD_UBO, u_offset / 8);
+	ipu_ch_param_set_field(&params, IPU_FIELD_VBO, v_offset / 8);
+
+	pr_debug("initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ch));
+	memcpy(ipu_ch_param_addr(ch), &params, sizeof(params));
+	return 0;
+}
+
+/*
+ * This function is called to initialize a buffer for a IPU channel.
+ *
+ * @param       channel         The IPU channel.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           Input parameter for width of buffer in pixels.
+ *
+ * @param       height          Input parameter for height of buffer in pixels.
+ *
+ * @param       stride          Input parameter for stride length of buffer
+ *                              in pixels.
+ *
+ * @param       rot_mode        Input parameter for rotation setting of buffer.
+ *                              A rotation setting other than
+ *                              IPU_ROTATE_VERT_FLIP
+ *                              should only be used for input buffers of
+ *                              rotation channels.
+ *
+ * @param       phyaddr_0       Input parameter buffer 0 physical address.
+ *
+ * @param       phyaddr_1       Input parameter buffer 1 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              double buffering mode.
+ *
+ * @param       u		private u offset for additional cropping,
+ *				zero if not used.
+ *
+ * @param       v		private v offset for additional cropping,
+ *				zero if not used.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u, u32 v, bool interlaced)
+{
+	int ret = 0;
+	u32 dma_chan = channel->num;
+
+	if (stride < width * ipu_bytes_per_pixel(pixel_fmt))
+		stride = width * ipu_bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu_dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+
+	ipu_get();
+
+	/* Build parameter memory data for DMA channel */
+	ret = ipu_ch_param_init(dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1);
+	if (ret)
+		goto out;
+
+	if (rot_mode)
+		ipu_ch_param_set_rotation(dma_chan, rot_mode);
+
+	if (interlaced)
+		ipu_ch_param_set_interlaced_scan(dma_chan);
+
+	if (idmac_idma_is_set(IDMAC_CHA_PRI, dma_chan))
+		ipu_ch_param_set_high_priority(dma_chan);
+
+	ipu_ch_param_dump(dma_chan);
+out:
+	ipu_put();
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_idmac_init_channel_buffer);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 buf_num, dma_addr_t phyaddr)
+{
+	u32 dma_chan = channel->num;
+
+	ipu_ch_param_set_buffer(dma_chan, buf_num, phyaddr);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_idmac_update_channel_buffer);
+
+int ipu_cpmem_init(struct platform_device *pdev, unsigned long base)
+{
+	ipu_cpmem_base = ioremap(base, PAGE_SIZE);
+	if (!ipu_cpmem_base)
+		return -ENOMEM;
+	ipu_dev = &pdev->dev;
+	return 0;
+}
+
+void ipu_cpmem_exit(struct platform_device *pdev)
+{
+	iounmap(ipu_cpmem_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dc.c b/drivers/video/imx-ipu-v3/ipu-dc.c
new file mode 100644
index 0000000..b8c601e
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dc.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define ASYNC_SER_WAVE 6
+
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+#define DC_MAP_CONF_PTR(n)	(ipu_dc_reg + 0x0108 + ((n) & ~0x1) * 2)
+#define DC_MAP_CONF_VAL(n)	(ipu_dc_reg + 0x0144 + ((n) & ~0x1) * 2)
+
+#define DC_EVT_NF		0
+#define DC_EVT_NL		1
+#define DC_EVT_EOF		2
+#define DC_EVT_NFIELD		3
+#define DC_EVT_EOL		4
+#define DC_EVT_EOFIELD		5
+#define DC_EVT_NEW_ADDR		6
+#define DC_EVT_NEW_CHAN		7
+#define DC_EVT_NEW_DATA		8
+
+#define DC_EVT_NEW_ADDR_W_0	0
+#define DC_EVT_NEW_ADDR_W_1	1
+#define DC_EVT_NEW_CHAN_W_0	2
+#define DC_EVT_NEW_CHAN_W_1	3
+#define DC_EVT_NEW_DATA_W_0	4
+#define DC_EVT_NEW_DATA_W_1	5
+#define DC_EVT_NEW_ADDR_R_0	6
+#define DC_EVT_NEW_ADDR_R_1	7
+#define DC_EVT_NEW_CHAN_R_0	8
+#define DC_EVT_NEW_CHAN_R_1	9
+#define DC_EVT_NEW_DATA_R_0	10
+#define DC_EVT_NEW_DATA_R_1	11
+
+#define DC_WR_CH_CONF(ch)	(ipu_dc_reg + dc_channels[ch].channel_offset)
+#define DC_WR_CH_ADDR(ch)	(ipu_dc_reg + dc_channels[ch].channel_offset + 4)
+#define DC_RL_CH(ch, evt)	(ipu_dc_reg + dc_channels[ch].channel_offset + 8 + ((evt) & ~0x1) * 2)
+
+#define DC_GEN			(ipu_dc_reg + 0x00D4)
+#define DC_DISP_CONF1(disp)	(ipu_dc_reg + 0x00D8 + disp * 4)
+#define DC_DISP_CONF2(disp)	(ipu_dc_reg + 0x00E8 + disp * 4)
+#define DC_STAT			(ipu_dc_reg + 0x01C8)
+
+#define WROD(lf)		(0x18 | (lf << 1))
+
+#define DC_WR_CH_CONF_FIELD_MODE		(1 << 9)
+#define DC_WR_CH_CONF_PROG_TYPE_OFFSET		5
+#define DC_WR_CH_CONF_PROG_TYPE_MASK		(7 << 5)
+#define DC_WR_CH_CONF_PROG_DI_ID		(1 << 2)
+#define DC_WR_CH_CONF_PROG_DISP_ID_OFFSET	3
+#define DC_WR_CH_CONF_PROG_DISP_ID_MASK		(3 << 3)
+
+static void __iomem *ipu_dc_reg;
+static void __iomem *ipu_dc_tmpl_reg;
+static struct device *ipu_dev;
+
+struct ipu_dc {
+	unsigned int di; /* The display interface number assigned to this dc channel */
+	unsigned int channel_offset;
+};
+
+static struct ipu_dc dc_channels[10];
+
+static void ipu_dc_link_event(int chan, int event, int addr, int priority)
+{
+	u32 reg;
+
+	reg = __raw_readl(DC_RL_CH(chan, event));
+	reg &= ~(0xFFFF << (16 * (event & 0x1)));
+	reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+	__raw_writel(reg, DC_RL_CH(chan, event));
+}
+
+static void ipu_dc_write_tmpl(int word, u32 opcode, u32 operand, int map,
+			       int wave, int glue, int sync)
+{
+	u32 reg;
+	int stop = 1;
+
+	reg = sync;
+	reg |= (glue << 4);
+	reg |= (++wave << 11);
+	reg |= (++map << 15);
+	reg |= (operand << 20) & 0xFFF00000;
+	__raw_writel(reg, ipu_dc_tmpl_reg + word * 8);
+
+	reg = (operand >> 12);
+	reg |= opcode << 4;
+	reg |= (stop << 9);
+	__raw_writel(reg, ipu_dc_tmpl_reg + word * 8 + 4);
+}
+
+static int ipu_pixfmt_to_map(u32 fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_RGB24:
+		return 0;
+	case IPU_PIX_FMT_RGB666:
+		return 1;
+	case IPU_PIX_FMT_YUV444:
+		return 2;
+	case IPU_PIX_FMT_RGB565:
+		return 3;
+	case IPU_PIX_FMT_LVDS666:
+		return 4;
+	}
+
+	return -EINVAL;
+}
+
+#define SYNC_WAVE 0
+
+int ipu_dc_init_sync(int dc_chan, int di, bool interlaced, u32 pixel_fmt, u32 width)
+{
+	u32 reg = 0, map;
+
+	dc_channels[dc_chan].di = di;
+
+	map = ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu_dev, "IPU_DISP: No MAP\n");
+		return -EINVAL;
+	}
+
+	ipu_get();
+
+	if (interlaced) {
+		ipu_dc_link_event(dc_chan, DC_EVT_NL, 0, 3);
+		ipu_dc_link_event(dc_chan, DC_EVT_EOL, 0, 2);
+		ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 0, 1);
+
+		/* Init template microcode */
+		ipu_dc_write_tmpl(0, WROD(0), 0, map, SYNC_WAVE, 0, 8);
+	} else {
+		if (di) {
+			ipu_dc_link_event(dc_chan, DC_EVT_NL, 2, 3);
+			ipu_dc_link_event(dc_chan, DC_EVT_EOL, 3, 2);
+			ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 4, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(2, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(3, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(4, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		} else {
+			ipu_dc_link_event(dc_chan, DC_EVT_NL, 5, 3);
+			ipu_dc_link_event(dc_chan, DC_EVT_EOL, 6, 2);
+			ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA, 7, 1);
+			/* Init template microcode */
+			ipu_dc_write_tmpl(5, WROD(0), 0, map, SYNC_WAVE, 8, 5);
+			ipu_dc_write_tmpl(6, WROD(0), 0, map, SYNC_WAVE, 4, 5);
+			ipu_dc_write_tmpl(7, WROD(0), 0, map, SYNC_WAVE, 0, 5);
+		}
+	}
+	ipu_dc_link_event(dc_chan, DC_EVT_NF, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NFIELD, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_EOF, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_EOFIELD, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+	reg = 0x2;
+	reg |= di << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	reg |= di << 2;
+	if (interlaced)
+		reg |= DC_WR_CH_CONF_FIELD_MODE;
+
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+	__raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	__raw_writel(0x00000084, DC_GEN);
+
+	__raw_writel(width, DC_DISP_CONF2(di));
+
+	ipu_module_enable(IPU_CONF_DC_EN);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dc_init_sync);
+
+void ipu_dc_init_async(int dc_chan, int di, bool interlaced)
+{
+	u32 reg = 0;
+	dc_channels[dc_chan].di = di;
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+	ipu_dc_link_event(dc_chan, DC_EVT_NEW_DATA_W_1, 0x64, 1);
+
+	reg = 0x3;
+	reg |= DC_DISP_ID_SERIAL << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+
+	__raw_writel(0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	__raw_writel(0x00000084, DC_GEN);
+
+	ipu_module_enable(IPU_CONF_DC_EN);
+}
+EXPORT_SYMBOL(ipu_dc_init_async);
+
+void ipu_dc_enable_channel(u32 dc_chan)
+{
+	int di;
+	u32 reg;
+
+	di = dc_channels[dc_chan].di;
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = __raw_readl(DC_WR_CH_CONF(6 - dc_chan));
+	if ((di << 2) == (reg & DC_WR_CH_CONF_PROG_DI_ID)) {
+		reg &= ~DC_WR_CH_CONF_PROG_DI_ID;
+		reg |= di ? 0 : DC_WR_CH_CONF_PROG_DI_ID;
+		__raw_writel(reg, DC_WR_CH_CONF(6 - dc_chan));
+	}
+
+	reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+}
+EXPORT_SYMBOL(ipu_dc_enable_channel);
+
+void ipu_dc_disable_channel(u32 dc_chan)
+{
+	u32 reg;
+	int irq = 0, ret, timeout = 50;
+
+	if (dc_chan == 1) {
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (dc_chan == 5) {
+		irq = IPU_IRQ_DP_SF_END;
+	} else {
+		return;
+	}
+
+	ret = ipu_wait_for_interrupt(irq, 50);
+	if (ret)
+		return;
+
+	/* Wait for DC triple buffer to empty */
+	if (dc_channels[dc_chan].di == 0)
+		while ((__raw_readl(DC_STAT) & 0x00000002)
+			!= 0x00000002) {
+			msleep(2);
+			timeout -= 2;
+			if (timeout <= 0)
+				break;
+		}
+	else if (dc_channels[dc_chan].di == 1)
+		while ((__raw_readl(DC_STAT) & 0x00000020)
+			!= 0x00000020) {
+			msleep(2);
+			timeout -= 2;
+			if (timeout <= 0)
+				break;
+	}
+
+	reg = __raw_readl(DC_WR_CH_CONF(dc_chan));
+	reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+	__raw_writel(reg, DC_WR_CH_CONF(dc_chan));
+}
+EXPORT_SYMBOL(ipu_dc_disable_channel);
+
+static void ipu_dc_map_config(int map, int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = __raw_readl(DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xffff << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	__raw_writel(reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = __raw_readl(DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	__raw_writel(reg, DC_MAP_CONF_PTR(map));
+}
+
+static void ipu_dc_map_clear(int map)
+{
+	u32 reg = __raw_readl(DC_MAP_CONF_PTR(map));
+	__raw_writel(reg & ~(0xffff << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base, unsigned long template_base)
+{
+	static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, 0x78, 0, 0x94, 0xb4};
+	int i;
+
+	ipu_dc_reg = ioremap(base, PAGE_SIZE);
+	if (!ipu_dc_reg)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	ipu_dc_tmpl_reg = ioremap(template_base, PAGE_SIZE);
+	if (!ipu_dc_tmpl_reg) {
+		iounmap(ipu_dc_reg);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < 10; i++)
+		dc_channels[i].channel_offset = channel_offsets[i];
+
+	/* IPU_PIX_FMT_RGB24 */
+	ipu_dc_map_clear(0);
+	ipu_dc_map_config(0, 0, 7, 0xff);
+	ipu_dc_map_config(0, 1, 15, 0xff);
+	ipu_dc_map_config(0, 2, 23, 0xff);
+
+	/* IPU_PIX_FMT_RGB666 */
+	ipu_dc_map_clear(1);
+	ipu_dc_map_config(1, 0, 5, 0xfc);
+	ipu_dc_map_config(1, 1, 11, 0xfc);
+	ipu_dc_map_config(1, 2, 17, 0xfc);
+
+	/* IPU_PIX_FMT_YUV444 */
+	ipu_dc_map_clear(2);
+	ipu_dc_map_config(2, 0, 15, 0xff);
+	ipu_dc_map_config(2, 1, 23, 0xff);
+	ipu_dc_map_config(2, 2, 7, 0xff);
+
+	/* IPU_PIX_FMT_RGB565 */
+	ipu_dc_map_clear(3);
+	ipu_dc_map_config(3, 0, 4, 0xf8);
+	ipu_dc_map_config(3, 1, 10, 0xfc);
+	ipu_dc_map_config(3, 2, 15, 0xf8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	ipu_dc_map_clear(4);
+	ipu_dc_map_config(4, 0, 5, 0xfc);
+	ipu_dc_map_config(4, 1, 13, 0xfc);
+	ipu_dc_map_config(4, 2, 21, 0xfc);
+
+	return 0;
+}
+
+void ipu_dc_exit(struct platform_device *pdev)
+{
+	iounmap(ipu_dc_reg);
+	iounmap(ipu_dc_tmpl_reg);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-di.c b/drivers/video/imx-ipu-v3/ipu-di.c
new file mode 100644
index 0000000..62e3d01
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-di.c
@@ -0,0 +1,550 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/platform_device.h>
+
+#include "ipu-prv.h"
+
+#define SYNC_WAVE 0
+
+#define DC_DISP_ID_SYNC(di)	(di)
+
+struct ipu_di {
+	void __iomem *base;
+	int id;
+	u32 module;
+	struct clk *clk;
+	struct clk *ipu_clk;
+	bool external_clk;
+	bool inuse;
+	bool initialized;
+};
+
+static struct ipu_di dis[2];
+
+static DEFINE_MUTEX(di_mutex);
+static struct device *ipu_dev;
+
+struct di_sync_config {
+	int run_count;
+	int run_src;
+	int offset_count;
+	int offset_src;
+	int repeat_count;
+	int cnt_clr_src;
+	int cnt_polarity_gen_en;
+	int cnt_polarity_clr_src;
+	int cnt_polarity_trigger_src;
+	int cnt_up;
+	int cnt_down;
+};
+
+enum di_pins {
+	DI_PIN11 = 0,
+	DI_PIN12 = 1,
+	DI_PIN13 = 2,
+	DI_PIN14 = 3,
+	DI_PIN15 = 4,
+	DI_PIN16 = 5,
+	DI_PIN17 = 6,
+	DI_PIN_CS = 7,
+
+	DI_PIN_SER_CLK = 0,
+	DI_PIN_SER_RS = 1,
+};
+
+enum di_sync_wave {
+	DI_SYNC_NONE = 0,
+	DI_SYNC_CLK = 1,
+	DI_SYNC_INT_HSYNC = 2,
+	DI_SYNC_HSYNC = 3,
+	DI_SYNC_VSYNC = 4,
+	DI_SYNC_DE = 6,
+};
+
+#define DI_GENERAL		0x0000
+#define DI_BS_CLKGEN0		0x0004
+#define DI_BS_CLKGEN1		0x0008
+#define DI_SW_GEN0(gen)		(0x000c + 4 * ((gen) - 1))
+#define DI_SW_GEN1(gen)		(0x0030 + 4 * ((gen) - 1))
+#define DI_STP_REP(gen)		(0x0148 + 4 * (((gen) - 1)/2))
+#define DI_SYNC_AS_GEN		0x0054
+#define DI_DW_GEN(gen)		(0x0058 + 4 * (gen))
+#define DI_DW_SET(gen, set)	(0x0088 + 4 * ((gen) + 0xc * (set)))
+#define DI_SER_CONF		0x015c
+#define DI_SSC			0x0160
+#define DI_POL			0x0164
+#define DI_AW0			0x0168
+#define DI_AW1			0x016c
+#define DI_SCR_CONF		0x0170
+#define DI_STAT			0x0174
+
+#define DI_SW_GEN0_RUN_COUNT(x)			((x) << 19)
+#define DI_SW_GEN0_RUN_SRC(x)			((x) << 16)
+#define DI_SW_GEN0_OFFSET_COUNT(x)		((x) << 3)
+#define DI_SW_GEN0_OFFSET_SRC(x)		((x) << 0)
+
+#define DI_SW_GEN1_CNT_POL_GEN_EN(x)		((x) << 29)
+#define DI_SW_GEN1_CNT_CLR_SRC(x)		((x) << 25)
+#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x)	((x) << 12)
+#define DI_SW_GEN1_CNT_POL_CLR_SRC(x)		((x) << 9)
+#define DI_SW_GEN1_CNT_DOWN(x)			((x) << 16)
+#define DI_SW_GEN1_CNT_UP(x)			(x)
+#define DI_SW_GEN1_AUTO_RELOAD			(0x10000000)
+
+#define DI_DW_GEN_ACCESS_SIZE_OFFSET		24
+#define DI_DW_GEN_COMPONENT_SIZE_OFFSET		16
+
+#define DI_GEN_DI_CLK_EXT			(1 << 20)
+#define DI_GEN_POLARITY_1			(1 << 0)
+#define DI_GEN_POLARITY_2			(1 << 1)
+#define DI_GEN_POLARITY_3			(1 << 2)
+#define DI_GEN_POLARITY_4			(1 << 3)
+#define DI_GEN_POLARITY_5			(1 << 4)
+#define DI_GEN_POLARITY_6			(1 << 5)
+#define DI_GEN_POLARITY_7			(1 << 6)
+#define DI_GEN_POLARITY_8			(1 << 7)
+
+#define DI_POL_DRDY_DATA_POLARITY		(1 << 7)
+#define DI_POL_DRDY_POLARITY_15			(1 << 4)
+
+#define DI_VSYNC_SEL_OFFSET			13
+
+#define DI0_COUNTER_RELEASE			(1 << 24)
+#define DI1_COUNTER_RELEASE			(1 << 25)
+
+static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset)
+{
+	return __raw_readl(di->base + offset);
+}
+
+static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset)
+{
+	__raw_writel(value, di->base + offset);
+}
+
+static void ipu_di_data_wave_config(struct ipu_di *di,
+				     int wave_gen,
+				     int access_size, int component_size)
+{
+	u32 reg;
+	reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) |
+	    (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, int set,
+				    int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, int count)
+{
+	u32 reg;
+	int i;
+
+	for (i = 0; i < count; i++) {
+		struct di_sync_config *c = &config[i];
+		int wave_gen = i + 1;
+
+		pr_debug("%s %d\n", __func__, wave_gen);
+		if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || (c->repeat_count >= 0x1000) ||
+			(c->cnt_up >= 0x400) || (c->cnt_down >= 0x400)) {
+			dev_err(ipu_dev, "DI%d counters out of range.\n", di->id);
+			return;
+		}
+
+		reg = DI_SW_GEN0_RUN_COUNT(c->run_count) |
+			DI_SW_GEN0_RUN_SRC(c->run_src) |
+			DI_SW_GEN0_OFFSET_COUNT(c->offset_count) |
+			DI_SW_GEN0_OFFSET_SRC(c->offset_src);
+		ipu_di_write(di, reg, DI_SW_GEN0(wave_gen));
+
+		reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) |
+			DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) |
+			DI_SW_GEN1_CNT_POL_TRIGGER_SRC(c->cnt_polarity_trigger_src) |
+			DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) |
+			DI_SW_GEN1_CNT_DOWN(c->cnt_down) |
+			DI_SW_GEN1_CNT_UP(c->cnt_up);
+
+		if (c->repeat_count == 0) {
+			/* Enable auto reload */
+			reg |= DI_SW_GEN1_AUTO_RELOAD;
+		}
+
+		ipu_di_write(di, reg, DI_SW_GEN1(wave_gen));
+
+		reg = ipu_di_read(di, DI_STP_REP(wave_gen));
+		reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1)));
+		reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1));
+		ipu_di_write(di, reg, DI_STP_REP(wave_gen));
+	}
+}
+
+static void ipu_di_sync_config_interlaced(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width;
+	u32 reg;
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total / 2 - 1,
+			.run_src = DI_SYNC_CLK,
+		}, {
+			.run_count = h_total - 11,
+			.run_src = DI_SYNC_CLK,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total * 2 - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = 1,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = 4,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height / 2,
+			.cnt_clr_src = 4,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_HSYNC,
+		}, {
+			.run_count = v_total / 2 - 1,
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = 9,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = 2,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		}, {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		}, {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.offset_count = v_total / 2,
+			.offset_src = DI_SYNC_INT_HSYNC,
+			.cnt_clr_src = DI_SYNC_HSYNC,
+			.cnt_down = 4,
+		}
+	};
+
+	ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+
+	/* set gentime select and tag sel */
+	reg = ipu_di_read(di, DI_SW_GEN1(9));
+	reg &= 0x1FFFFFFF;
+	reg |= (3 - 1) << 29 | 0x00008000;
+	ipu_di_write(di, reg, DI_SW_GEN1(9));
+
+	ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF);
+}
+
+static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
+		struct ipu_di_signal_cfg *sig, int div)
+{
+	u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
+		sig->h_end_width;
+	u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
+		sig->v_end_width + (sig->v_end_width < 2 ? 1 : 0);
+	struct di_sync_config cfg[] = {
+		{
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+		} , {
+			.run_count = h_total - 1,
+			.run_src = DI_SYNC_CLK,
+			.offset_count = div * sig->v_to_h_sync,
+			.offset_src = DI_SYNC_CLK,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_CLK,
+			.cnt_down = sig->h_sync_width * 2,
+		} , {
+			.run_count = v_total - 1,
+			.run_src = DI_SYNC_INT_HSYNC,
+			.cnt_polarity_gen_en = 1,
+			.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
+			.cnt_down = sig->v_sync_width * 2,
+		} , {
+			.run_src = DI_SYNC_HSYNC,
+			.offset_count = sig->v_sync_width + sig->v_start_width,
+			.offset_src = DI_SYNC_HSYNC,
+			.repeat_count = sig->height,
+			.cnt_clr_src = DI_SYNC_VSYNC,
+		} , {
+			.run_src = DI_SYNC_CLK,
+			.offset_count = sig->h_sync_width + sig->h_start_width,
+			.offset_src = DI_SYNC_CLK,
+			.repeat_count = sig->width,
+			.cnt_clr_src = 5,
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		} , {
+			/* unused */
+		},
+	};
+
+	ipu_di_write(di, v_total - 1, DI_SCR_CONF);
+	ipu_di_sync_config(di, cfg, ARRAY_SIZE(cfg));
+}
+
+int ipu_di_init_sync_panel(struct ipu_di *di, u32 pixel_clk, struct ipu_di_signal_cfg *sig)
+{
+	u32 reg;
+	u32 disp_gen, di_gen, vsync_cnt;
+	u32 div;
+	u32 h_total, v_total;
+	struct clk *di_clk;
+
+	dev_dbg(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;
+
+	mutex_lock(&di_mutex);
+	ipu_get();
+
+	/* Init clocking */
+	if (sig->ext_clk) {
+		di->external_clk = true;
+		di_clk = di->clk;
+	} else {
+		di->external_clk = false;
+		di_clk = di->ipu_clk;
+	}
+
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = (clk_get_rate(di_clk) * 16) / pixel_clk;
+	if (div < 0x10)	/* Min DI disp clock divider is 1 */
+		div = 0x10;
+
+	disp_gen = ipu_cm_read(IPU_DISP_GEN);
+	disp_gen &= di->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(disp_gen, IPU_DISP_GEN);
+
+	ipu_di_write(di, div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* Down time is half of period */
+	ipu_di_write(di, (div / 16) << 16, DI_BS_CLKGEN1);
+
+	ipu_di_data_wave_config(di, SYNC_WAVE, div / 16 - 1, div / 16 - 1);
+	ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div / 16 * 2);
+
+	div = div / 16;		/* Now divider is integer portion */
+
+	di_gen = 0;
+	if (sig->ext_clk)
+		di_gen |= DI_GEN_DI_CLK_EXT;
+
+	if (sig->interlaced) {
+		ipu_di_sync_config_interlaced(di, sig);
+
+		/* set y_sel = 1 */
+		di_gen |= 0x10000000;
+		di_gen |= DI_GEN_POLARITY_5;
+		di_gen |= DI_GEN_POLARITY_8;
+
+		vsync_cnt = 7;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		ipu_di_sync_config_noninterlaced(di, sig, div);
+
+		vsync_cnt = 3;
+
+		if (sig->Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+		if (sig->Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+	}
+
+	ipu_di_write(di, di_gen, DI_GENERAL);
+	ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002,
+		     DI_SYNC_AS_GEN);
+
+	reg = ipu_di_read(di, DI_POL);
+	reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15);
+
+	if (sig->enable_pol)
+		reg |= DI_POL_DRDY_POLARITY_15;
+	if (sig->data_pol)
+		reg |= DI_POL_DRDY_DATA_POLARITY;
+
+	ipu_di_write(di, reg, DI_POL);
+
+	ipu_put();
+	mutex_unlock(&di_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_init_sync_panel);
+
+int ipu_di_enable(struct ipu_di *di)
+{
+	u32 reg;
+
+	ipu_get();
+	reg = ipu_cm_read(IPU_DISP_GEN);
+	if (di->id)
+		reg |= DI1_COUNTER_RELEASE;
+	else
+		reg |= DI0_COUNTER_RELEASE;
+	ipu_cm_write(reg, IPU_DISP_GEN);
+
+	if (di->external_clk)
+		clk_enable(di->clk);
+
+	ipu_module_enable(di->module);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_enable);
+
+int ipu_di_disable(struct ipu_di *di)
+{
+	u32 reg;
+
+	ipu_module_disable(di->module);
+	ipu_put();
+
+	if (di->external_clk)
+		clk_disable(di->clk);
+
+	reg = ipu_cm_read(IPU_DISP_GEN);
+	if (di->id)
+		reg &= ~DI1_COUNTER_RELEASE;
+	else
+		reg &= ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(reg, IPU_DISP_GEN);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_di_disable);
+
+static DEFINE_MUTEX(ipu_di_lock);
+
+struct ipu_di *ipu_di_get(int disp)
+{
+	struct ipu_di *di;
+
+	if (disp > 1)
+		return ERR_PTR(-EINVAL);
+
+	di = &dis[disp];
+
+	mutex_lock(&ipu_di_lock);
+
+	if (!di->initialized) {
+		di = ERR_PTR(-ENOSYS);
+		goto out;
+	}
+
+	if (di->inuse) {
+		di = ERR_PTR(-EBUSY);
+		goto out;
+	}
+
+	di->inuse = true;
+out:
+	mutex_unlock(&ipu_di_lock);
+
+	return di;
+}
+EXPORT_SYMBOL(ipu_di_get);
+
+void ipu_di_put(struct ipu_di *di)
+{
+	mutex_lock(&ipu_di_lock);
+
+	di->inuse = false;
+
+	mutex_unlock(&ipu_di_lock);
+}
+EXPORT_SYMBOL(ipu_di_put);
+
+int ipu_di_init(struct platform_device *pdev, int id, unsigned long base,
+		u32 module, struct clk *ipu_clk)
+{
+	char *clkid;
+
+	if (id > 1)
+		return -EINVAL;
+
+	if (id)
+		clkid = "di1";
+	else
+		clkid = "di0";
+
+	ipu_dev = &pdev->dev;
+
+	dis[id].clk = clk_get(&pdev->dev, clkid);
+	dis[id].module = module;
+	dis[id].id = id;
+	dis[id].ipu_clk = ipu_clk;
+	dis[id].base = ioremap(base, PAGE_SIZE);
+	dis[id].initialized = true;
+	dis[id].inuse = false;
+	if (!dis[id].base)
+		return -ENOMEM;
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+	return 0;
+}
+
+void ipu_di_exit(struct platform_device *pdev, int id)
+{
+	clk_put(dis[id].clk);
+	iounmap(dis[id].base);
+	dis[id].initialized = false;
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dmfc.c b/drivers/video/imx-ipu-v3/ipu-dmfc.c
new file mode 100644
index 0000000..3d47a76
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dmfc.c
@@ -0,0 +1,355 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+
+#include "ipu-prv.h"
+
+#define DMFC_RD_CHAN		0x0000
+#define DMFC_WR_CHAN		0x0004
+#define DMFC_WR_CHAN_DEF	0x0008
+#define DMFC_DP_CHAN		0x000c
+#define DMFC_DP_CHAN_DEF	0x0010
+#define DMFC_GENERAL1		0x0014
+#define DMFC_GENERAL2		0x0018
+#define DMFC_IC_CTRL		0x001c
+#define DMFC_STAT		0x0020
+
+#define DMFC_WR_CHAN_1_28		0
+#define DMFC_WR_CHAN_2_41		8
+#define DMFC_WR_CHAN_1C_42		16
+#define DMFC_WR_CHAN_2C_43		24
+
+#define DMFC_DP_CHAN_5B_23		0
+#define DMFC_DP_CHAN_5F_27		8
+#define DMFC_DP_CHAN_6B_24		16
+#define DMFC_DP_CHAN_6F_29		24
+
+#define DMFC_FIFO_SIZE_64		(3 << 3)
+#define DMFC_FIFO_SIZE_128		(2 << 3)
+#define DMFC_FIFO_SIZE_256		(1 << 3)
+#define DMFC_FIFO_SIZE_512		(0 << 3)
+
+#define DMFC_SEGMENT(x)			((x & 0x7) << 0)
+#define DMFC_BURSTSIZE_32		(0 << 6)
+#define DMFC_BURSTSIZE_16		(1 << 6)
+#define DMFC_BURSTSIZE_8		(2 << 6)
+#define DMFC_BURSTSIZE_4		(3 << 6)
+
+static struct device *ipu_dev;
+
+struct dmfc_channel {
+	int		ipu_channel;
+	unsigned long	channel_reg;
+	unsigned long	shift;
+	unsigned	eot_shift;
+	unsigned	slots;
+	unsigned	max_fifo_lines;
+	unsigned	slotmask;
+	unsigned	segment;
+};
+
+static struct dmfc_channel dmfcs[] = {
+	{
+		.ipu_channel	= 23,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5B_23,
+		.eot_shift	= 20,
+		.max_fifo_lines	= 3,
+	}, {
+		.ipu_channel	= 24,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6B_24,
+		.eot_shift	= 22,
+		.max_fifo_lines	= 1,
+	}, {
+		.ipu_channel	= 27,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_5F_27,
+		.eot_shift	= 21,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 28,
+		.channel_reg	= DMFC_WR_CHAN,
+		.shift		= DMFC_WR_CHAN_1_28,
+		.eot_shift	= 16,
+		.max_fifo_lines	= 2,
+	}, {
+		.ipu_channel	= 29,
+		.channel_reg	= DMFC_DP_CHAN,
+		.shift		= DMFC_DP_CHAN_6F_29,
+		.eot_shift	= 23,
+		.max_fifo_lines	= 1,
+	},
+};
+
+#define DMFC_NUM_CHANNELS	ARRAY_SIZE(dmfcs)
+
+static int dmfc_use_count;
+static void __iomem *dmfc_regs;
+static unsigned long dmfc_bandwidth_per_slot;
+static DEFINE_MUTEX(dmfc_mutex);
+
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc)
+{
+	mutex_lock(&dmfc_mutex);
+	ipu_get();
+
+	if (!dmfc_use_count)
+		ipu_module_enable(IPU_CONF_DMFC_EN);
+
+	dmfc_use_count++;
+
+	mutex_unlock(&dmfc_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dmfc_enable_channel);
+
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc)
+{
+	mutex_lock(&dmfc_mutex);
+
+	dmfc_use_count--;
+
+	if (!dmfc_use_count)
+		ipu_module_disable(IPU_CONF_DMFC_EN);
+
+	if (dmfc_use_count < 0)
+		dmfc_use_count = 0;
+
+	ipu_put();
+	mutex_unlock(&dmfc_mutex);
+}
+EXPORT_SYMBOL(ipu_dmfc_disable_channel);
+
+static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, int segment)
+{
+	u32 val, field;
+
+	dev_dbg(ipu_dev, "dmfc: using %d slots starting from segment %d for IPU channel %d\n",
+			slots, segment, dmfc->ipu_channel);
+
+	if (!dmfc)
+		return -EINVAL;
+
+	switch (slots) {
+	case 1:
+		field = DMFC_FIFO_SIZE_64;
+		break;
+	case 2:
+		field = DMFC_FIFO_SIZE_128;
+		break;
+	case 4:
+		field = DMFC_FIFO_SIZE_256;
+		break;
+	case 8:
+		field = DMFC_FIFO_SIZE_512;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	field |= DMFC_SEGMENT(segment) | DMFC_BURSTSIZE_8;
+
+	val = readl(dmfc_regs + dmfc->channel_reg);
+
+	val &= ~(0xff << dmfc->shift);
+	val |= field << dmfc->shift;
+
+	writel(val, dmfc_regs + dmfc->channel_reg);
+
+	dmfc->slots = slots;
+	dmfc->segment = segment;
+	dmfc->slotmask = ((1 << slots) - 1) << segment;
+
+	return 0;
+}
+
+static int dmfc_bandwidth_to_slots(unsigned long bandwidth)
+{
+	int slots = 1;
+
+	while (slots * dmfc_bandwidth_per_slot < bandwidth)
+		slots *= 2;
+
+	return slots;
+}
+
+static int dmfc_find_slots(int slots)
+{
+	unsigned slotmask_need, slotmask_used = 0;
+	int i, segment = 0;
+
+	slotmask_need = (1 << slots) - 1;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		slotmask_used |= dmfcs[i].slotmask;
+
+	while (slotmask_need <= 0xff) {
+		if (!(slotmask_used & slotmask_need))
+			return segment;
+
+		slotmask_need <<= 1;
+		segment++;
+	}
+
+	return -EBUSY;
+}
+
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc)
+{
+	int i;
+
+	dev_dbg(ipu_dev, "dmfc: freeing %d slots starting from segment %d\n",
+			dmfc->slots, dmfc->segment);
+
+	mutex_lock(&dmfc_mutex);
+
+	if (!dmfc->slots)
+		goto out;
+
+	dmfc->slotmask = 0;
+	dmfc->slots = 0;
+	dmfc->segment = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++)
+		dmfcs[i].slotmask = 0;
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++) {
+		if (dmfcs[i].slots > 0) {
+			dmfcs[i].segment = dmfc_find_slots(dmfcs[i].slots);
+			dmfcs[i].slotmask = ((1 << dmfcs[i].slots) - 1) << dmfcs[i].segment;
+		}
+	}
+
+	for (i = 0; i < ARRAY_SIZE(dmfcs); i++) {
+		if (dmfcs[i].slots > 0)
+			ipu_dmfc_setup_channel(&dmfcs[i], dmfcs[i].slots, dmfcs[i].segment);
+	}
+out:
+	mutex_unlock(&dmfc_mutex);
+}
+EXPORT_SYMBOL(ipu_dmfc_free_bandwidth);
+
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc,
+		unsigned long bandwidth_pixel_per_second)
+{
+	int slots = dmfc_bandwidth_to_slots(bandwidth_pixel_per_second);
+	int segment = 0, ret = 0;
+
+	dev_dbg(ipu_dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n",
+			bandwidth_pixel_per_second / 1000000, dmfc->ipu_channel);
+
+	ipu_dmfc_free_bandwidth(dmfc);
+
+	ipu_get();
+	mutex_lock(&dmfc_mutex);
+
+	if (slots > 8) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	segment = dmfc_find_slots(slots);
+	if (segment < 0) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	ipu_dmfc_setup_channel(dmfc, slots, segment);
+
+out:
+	ipu_put();
+	mutex_unlock(&dmfc_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_dmfc_alloc_bandwidth);
+
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width)
+{
+	u32 dmfc_gen1;
+
+	ipu_get();
+
+	dmfc_gen1 = readl(dmfc_regs + DMFC_GENERAL1);
+
+	if ((dmfc->slots * 64 * 4) / width > dmfc->max_fifo_lines)
+		dmfc_gen1 |= 1 << dmfc->eot_shift;
+	else
+		dmfc_gen1 &= ~(1 << dmfc->eot_shift);
+
+	writel(dmfc_gen1, dmfc_regs + DMFC_GENERAL1);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dmfc_init_channel);
+
+struct dmfc_channel *ipu_dmfc_get(int ipu_channel)
+{
+	int i;
+
+	for (i = 0; i < DMFC_NUM_CHANNELS; i++)
+		if (dmfcs[i].ipu_channel == ipu_channel)
+			return &dmfcs[i];
+	return NULL;
+}
+EXPORT_SYMBOL(ipu_dmfc_get);
+
+void ipu_dmfc_put(struct dmfc_channel *dmfc)
+{
+	ipu_dmfc_free_bandwidth(dmfc);
+}
+EXPORT_SYMBOL(ipu_dmfc_put);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base,
+		struct clk *ipu_clk)
+{
+	dmfc_regs = ioremap(base, PAGE_SIZE);
+
+	if (!dmfc_regs)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	writel(0x0, dmfc_regs + DMFC_WR_CHAN);
+	writel(0x0, dmfc_regs + DMFC_DP_CHAN);
+
+	/*
+	 * We have a total bandwidth of clkrate * 4pixel divided
+	 * into 8 slots.
+	 */
+	dmfc_bandwidth_per_slot = clk_get_rate(ipu_clk) / 4;
+
+	dev_dbg(ipu_dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n",
+			dmfc_bandwidth_per_slot / 1000000);
+
+	writel(0x202020f6, dmfc_regs + DMFC_WR_CHAN_DEF);
+	writel(0x2020f6f6, dmfc_regs + DMFC_DP_CHAN_DEF);
+	writel(0x00000003, dmfc_regs + DMFC_GENERAL1);
+
+	return 0;
+}
+
+void ipu_dmfc_exit(struct platform_device *pdev)
+{
+	iounmap(dmfc_regs);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-dp.c b/drivers/video/imx-ipu-v3/ipu-dp.c
new file mode 100644
index 0000000..57a7fec
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-dp.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/mfd/imx-ipu-v3.h>
+#include <linux/err.h>
+
+#include "ipu-prv.h"
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+
+#define DP_COM_CONF(flow)		(ipu_dp_base + flow)
+#define DP_GRAPH_WIND_CTRL(flow)	(ipu_dp_base + 0x0004 + flow)
+#define DP_FG_POS(flow)			(ipu_dp_base + 0x0008 + flow)
+#define DP_CSC_A_0(flow)		(ipu_dp_base + 0x0044 + flow)
+#define DP_CSC_A_1(flow)		(ipu_dp_base + 0x0048 + flow)
+#define DP_CSC_A_2(flow)		(ipu_dp_base + 0x004C + flow)
+#define DP_CSC_A_3(flow)		(ipu_dp_base + 0x0050 + flow)
+#define DP_CSC_0(flow)			(ipu_dp_base + 0x0054 + flow)
+#define DP_CSC_1(flow)			(ipu_dp_base + 0x0058 + flow)
+
+#define DP_COM_CONF_FG_EN		(1 << 0)
+#define DP_COM_CONF_GWSEL		(1 << 1)
+#define DP_COM_CONF_GWAM		(1 << 2)
+#define DP_COM_CONF_GWCKE		(1 << 3)
+#define DP_COM_CONF_CSC_DEF_MASK	(3 << 8)
+#define DP_COM_CONF_CSC_DEF_OFFSET	8
+#define DP_COM_CONF_CSC_DEF_FG		(3 << 8)
+#define DP_COM_CONF_CSC_DEF_BG		(2 << 8)
+#define DP_COM_CONF_CSC_DEF_BOTH	(1 << 8)
+
+struct ipu_dp {
+	u32 flow;
+	bool in_use;
+};
+
+static struct ipu_dp ipu_dp[3];
+static struct device *ipu_dev;
+
+static u32 ipu_flows[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1};
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+static void __iomem *ipu_dp_base;
+static int dp_use_count;
+static DEFINE_MUTEX(dp_mutex);
+
+/*     Y = R *  .299 + G *  .587 + B *  .114;
+       U = R * -.169 + G * -.332 + B *  .500 + 128.;
+       V = R *  .500 + G * -.419 + B * -.0813 + 128.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{ 153, 301, 58, },
+	{ -87, -170, 0x0100, },
+	{ 0x100, -215, -42, },
+	{ 0x0000, 0x0200, 0x0200, },	/* B0, B1, B2 */
+	{ 0x2, 0x2, 0x2, },	/* S0, S1, S2 */
+};
+
+/*     R = (1.164 * (Y - 16)) + (1.596 * (Cr - 128));
+       G = (1.164 * (Y - 16)) - (0.392 * (Cb - 128)) - (0.813 * (Cr - 128));
+       B = (1.164 * (Y - 16)) + (2.017 * (Cb - 128); */
+static const int ycbcr2rgb_coeff[5][3] = {
+	{ 0x095, 0x000, 0x0CC, },
+	{ 0x095, 0x3CE, 0x398, },
+	{ 0x095, 0x0FF, 0x000, },
+	{ 0x3E42, 0x010A, 0x3DD6, },	/*B0,B1,B2 */
+	{ 0x1, 0x1, 0x1, },	/*S0,S1,S2 */
+};
+
+/* Please keep S0, S1 and S2 as 0x2 by using this conversion */
+static int _rgb_to_yuv(int n, int red, int green, int blue)
+{
+	int c;
+
+	c = red * rgb2ycbcr_coeff[n][0];
+	c += green * rgb2ycbcr_coeff[n][1];
+	c += blue * rgb2ycbcr_coeff[n][2];
+	c /= 16;
+	c += rgb2ycbcr_coeff[3][n] * 4;
+	c += 8;
+	c /= 16;
+	if (c < 0)
+		c = 0;
+	if (c > 255)
+		c = 255;
+	return c;
+}
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+/*
+ * Row is for BG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ * Column is for FG:	RGB2YUV YUV2RGB RGB2RGB YUV2YUV CSC_NONE
+ */
+static struct dp_csc_param_t dp_csc_array[CSC_NUM][CSC_NUM] = {
+	{
+		{ DP_COM_CONF_CSC_DEF_BOTH, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &rgb2ycbcr_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BOTH, &ycbcr2rgb_coeff, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_BG, &ycbcr2rgb_coeff, },
+	}, {
+		{ 0, 0, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}, {
+		{ DP_COM_CONF_CSC_DEF_FG, &rgb2ycbcr_coeff, },
+		{ DP_COM_CONF_CSC_DEF_FG, &ycbcr2rgb_coeff, },
+		{ 0, 0, },
+		{ 0, 0, },
+		{ 0, 0, },
+	}
+};
+
+static enum csc_type_t fg_csc_type = CSC_NONE, bg_csc_type = CSC_NONE;
+
+static int color_key_4rgb = 1;
+
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 color_key)
+{
+	u32 reg;
+	int y, u, v;
+	int red, green, blue;
+
+	mutex_lock(&dp_mutex);
+
+	color_key_4rgb = 1;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB))) {
+
+		dev_dbg(ipu_dev, "color key 0x%x need change to yuv fmt\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu_dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFF000000L;
+		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp->flow));
+
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg | DP_COM_CONF_GWCKE, DP_COM_CONF(dp->flow));
+	} else {
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(dp->flow));
+	}
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_color_key);
+
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, bool bg_chan)
+{
+	u32 reg;
+
+	mutex_lock(&dp_mutex);
+
+	reg = __raw_readl(DP_COM_CONF(dp->flow));
+	if (bg_chan)
+		reg &= ~DP_COM_CONF_GWSEL;
+	else
+		reg |= DP_COM_CONF_GWSEL;
+	__raw_writel(reg, DP_COM_CONF(dp->flow));
+
+	if (enable) {
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0x00FFFFFFL;
+		__raw_writel(reg | ((u32) alpha << 24),
+			     DP_GRAPH_WIND_CTRL(dp->flow));
+
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg | DP_COM_CONF_GWAM, DP_COM_CONF(dp->flow));
+	} else {
+		reg = __raw_readl(DP_COM_CONF(dp->flow));
+		__raw_writel(reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(dp->flow));
+	}
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_global_alpha);
+
+int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos)
+{
+	u32 reg;
+
+	mutex_lock(&dp_mutex);
+
+	__raw_writel((x_pos << 16) | y_pos, DP_FG_POS(dp->flow));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_set_window_pos);
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+void __ipu_dp_csc_setup(int dp, struct dp_csc_param_t dp_csc_param,
+			bool srm_mode_update)
+{
+	u32 reg;
+	const int (*coeff)[5][3];
+
+	if (dp_csc_param.mode >= 0) {
+		reg = __raw_readl(DP_COM_CONF(dp));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		__raw_writel(reg, DP_COM_CONF(dp));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		__raw_writel(mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
+		__raw_writel(mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
+		__raw_writel(mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
+		__raw_writel(mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
+		__raw_writel(mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(dp));
+		__raw_writel(mask_b((*coeff)[3][1]) | ((*coeff)[4][1] << 14) |
+				(mask_b((*coeff)[3][2]) << 16) |
+				((*coeff)[4][2] << 30), DP_CSC_1(dp));
+	}
+
+	if (srm_mode_update) {
+		reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(reg, IPU_SRM_PRI2);
+	}
+}
+
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg)
+{
+	int in_fmt, out_fmt;
+	enum csc_type_t *csc_type;
+	u32 reg;
+
+	ipu_get();
+
+	if (bg)
+		csc_type = &bg_csc_type;
+	else
+		csc_type = &fg_csc_type;
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (in_fmt == RGB) {
+		if (out_fmt == RGB)
+			*csc_type = RGB2RGB;
+		else
+			*csc_type = RGB2YUV;
+	} else {
+		if (out_fmt == RGB)
+			*csc_type = YUV2RGB;
+		else
+			*csc_type = YUV2YUV;
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = __raw_readl(DP_COM_CONF(dp->flow));
+	if (color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((fg_csc_type == RGB2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == RGB2YUV)) ||
+			 ((fg_csc_type == YUV2YUV) && (bg_csc_type == YUV2YUV)) ||
+			 ((fg_csc_type == YUV2RGB) && (bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		u32 color_key = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFFFFFFL;
+
+		dev_dbg(ipu_dev, "_ipu_dp_init color key 0x%x need change to yuv fmt!\n", color_key);
+
+		red = (color_key >> 16) & 0xFF;
+		green = (color_key >> 8) & 0xFF;
+		blue = color_key & 0xFF;
+
+		y = _rgb_to_yuv(0, red, green, blue);
+		u = _rgb_to_yuv(1, red, green, blue);
+		v = _rgb_to_yuv(2, red, green, blue);
+		color_key = (y << 16) | (u << 8) | v;
+
+		reg = __raw_readl(DP_GRAPH_WIND_CTRL(dp->flow)) & 0xFF000000L;
+		__raw_writel(reg | color_key, DP_GRAPH_WIND_CTRL(dp->flow));
+		color_key_4rgb = 0;
+
+		dev_dbg(ipu_dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(dp->flow, dp_csc_array[bg_csc_type][fg_csc_type], true);
+
+	ipu_put();
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_setup_channel);
+
+int ipu_dp_enable_channel(struct ipu_dp *dp)
+{
+	mutex_lock(&dp_mutex);
+	ipu_get();
+
+	if (!dp_use_count)
+		ipu_module_enable(IPU_CONF_DP_EN);
+
+	dp_use_count++;
+
+	mutex_unlock(&dp_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_dp_enable_channel);
+
+void ipu_dp_disable_channel(struct ipu_dp *dp)
+{
+	mutex_lock(&dp_mutex);
+
+	dp_use_count--;
+
+	if (!dp_use_count)
+		ipu_module_disable(IPU_CONF_DP_EN);
+
+	if (dp_use_count < 0)
+		dp_use_count = 0;
+
+	ipu_put();
+	mutex_unlock(&dp_mutex);
+}
+EXPORT_SYMBOL(ipu_dp_disable_channel);
+
+void ipu_dp_enable_fg(struct ipu_dp *dp)
+{
+	u32 reg;
+
+	/* Enable FG channel */
+	reg = __raw_readl(DP_COM_CONF(DP_SYNC));
+	__raw_writel(reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2);
+	reg |= 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+}
+EXPORT_SYMBOL(ipu_dp_enable_fg);
+
+void ipu_dp_disable_fg(struct ipu_dp *dp)
+{
+	u32 reg, csc;
+
+	ipu_get();
+
+	reg = __raw_readl(DP_COM_CONF(DP_SYNC));
+	csc = reg & DP_COM_CONF_CSC_DEF_MASK;
+	if (csc == DP_COM_CONF_CSC_DEF_FG)
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+
+	reg &= ~DP_COM_CONF_FG_EN;
+	__raw_writel(reg, DP_COM_CONF(DP_SYNC));
+
+	reg = ipu_cm_read(IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(reg, IPU_SRM_PRI2);
+
+	ipu_put();
+}
+EXPORT_SYMBOL(ipu_dp_disable_fg);
+
+struct ipu_dp *ipu_dp_get(unsigned int flow)
+{
+	struct ipu_dp *dp;
+
+	if (flow > 2)
+		return ERR_PTR(-EINVAL);
+
+	dp = &ipu_dp[flow];
+
+	if (dp->in_use)
+		return ERR_PTR(-EBUSY);
+
+	dp->in_use = true;
+	dp->flow = ipu_flows[flow];
+
+	return dp;
+}
+EXPORT_SYMBOL(ipu_dp_get);
+
+void ipu_dp_put(struct ipu_dp *dp)
+{
+	dp->in_use = false;
+}
+EXPORT_SYMBOL(ipu_dp_put);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base)
+{
+	ipu_dp_base = ioremap(base, PAGE_SIZE);
+	if (!ipu_dp_base)
+		return -ENOMEM;
+
+	ipu_dev = &pdev->dev;
+
+	return 0;
+}
+
+void ipu_dp_exit(struct platform_device *pdev)
+{
+	 iounmap(ipu_dp_base);
+}
diff --git a/drivers/video/imx-ipu-v3/ipu-prv.h b/drivers/video/imx-ipu-v3/ipu-prv.h
new file mode 100644
index 0000000..339b554
--- /dev/null
+++ b/drivers/video/imx-ipu-v3/ipu-prv.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+#ifndef __IPU_PRV_H__
+#define __IPU_PRV_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <mach/hardware.h>
+
+#define MX51_IPU_CHANNEL_CSI0			 0
+#define MX51_IPU_CHANNEL_CSI1			 1
+#define MX51_IPU_CHANNEL_CSI2			 2
+#define MX51_IPU_CHANNEL_CSI3			 3
+#define MX51_IPU_CHANNEL_MEM_BG_SYNC		23
+#define MX51_IPU_CHANNEL_MEM_FG_SYNC		27
+#define MX51_IPU_CHANNEL_MEM_DC_SYNC		28
+#define MX51_IPU_CHANNEL_MEM_FG_SYNC_ALPHA	31
+#define MX51_IPU_CHANNEL_MEM_DC_ASYNC		41
+#define MX51_IPU_CHANNEL_ROT_ENC_MEM		45
+#define MX51_IPU_CHANNEL_ROT_VF_MEM		46
+#define MX51_IPU_CHANNEL_ROT_PP_MEM		47
+#define MX51_IPU_CHANNEL_ROT_ENC_MEM_OUT	48
+#define MX51_IPU_CHANNEL_ROT_VF_MEM_OUT		49
+#define MX51_IPU_CHANNEL_ROT_PP_MEM_OUT		50
+#define MX51_IPU_CHANNEL_MEM_BG_SYNC_ALPHA	51
+
+#define IPU_DISP0_BASE		0x00000000
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_DISP1_BASE		(IPU_MCU_T_DEFAULT << 25)
+#define IPU_CM_REG_BASE		0x1e000000
+#define IPU_IDMAC_REG_BASE	0x1e008000
+#define IPU_ISP_REG_BASE	0x1e010000
+#define IPU_DP_REG_BASE		0x1e018000
+#define IPU_IC_REG_BASE		0x1e020000
+#define IPU_IRT_REG_BASE	0x1e028000
+#define IPU_CSI0_REG_BASE	0x1e030000
+#define IPU_CSI1_REG_BASE	0x1e038000
+#define IPU_DI0_REG_BASE	0x1e040000
+#define IPU_DI1_REG_BASE	0x1e048000
+#define IPU_SMFC_REG_BASE	0x1e050000
+#define IPU_DC_REG_BASE		0x1e058000
+#define IPU_DMFC_REG_BASE	0x1e060000
+#define IPU_CPMEM_REG_BASE	0x1f000000
+#define IPU_LUT_REG_BASE	0x1f020000
+#define IPU_SRM_REG_BASE	0x1f040000
+#define IPU_TPM_REG_BASE	0x1f060000
+#define IPU_DC_TMPL_REG_BASE	0x1f080000
+#define IPU_ISP_TBPR_REG_BASE	0x1f0c0000
+#define IPU_VDI_REG_BASE	0x1e068000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CM_REG(offset)	(offset)
+
+#define IPU_CONF			IPU_CM_REG(0)
+
+#define IPU_SRM_PRI1			IPU_CM_REG(0x00a0)
+#define IPU_SRM_PRI2			IPU_CM_REG(0x00a4)
+#define IPU_FS_PROC_FLOW1		IPU_CM_REG(0x00a8)
+#define IPU_FS_PROC_FLOW2		IPU_CM_REG(0x00ac)
+#define IPU_FS_PROC_FLOW3		IPU_CM_REG(0x00b0)
+#define IPU_FS_DISP_FLOW1		IPU_CM_REG(0x00b4)
+#define IPU_FS_DISP_FLOW2		IPU_CM_REG(0x00b8)
+#define IPU_SKIP			IPU_CM_REG(0x00bc)
+#define IPU_DISP_ALT_CONF		IPU_CM_REG(0x00c0)
+#define IPU_DISP_GEN			IPU_CM_REG(0x00c4)
+#define IPU_DISP_ALT1			IPU_CM_REG(0x00c8)
+#define IPU_DISP_ALT2			IPU_CM_REG(0x00cc)
+#define IPU_DISP_ALT3			IPU_CM_REG(0x00d0)
+#define IPU_DISP_ALT4			IPU_CM_REG(0x00d4)
+#define IPU_SNOOP			IPU_CM_REG(0x00d8)
+#define IPU_MEM_RST			IPU_CM_REG(0x00dc)
+#define IPU_PM				IPU_CM_REG(0x00e0)
+#define IPU_GPR				IPU_CM_REG(0x00e4)
+#define IPU_CHA_DB_MODE_SEL(ch)		IPU_CM_REG(0x0150 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch)	IPU_CM_REG(0x0168 + 4 * ((ch) / 32))
+#define IPU_CHA_CUR_BUF(ch)		IPU_CM_REG(0x023C + 4 * ((ch) / 32))
+#define IPU_ALT_CUR_BUF0		IPU_CM_REG(0x0244)
+#define IPU_ALT_CUR_BUF1		IPU_CM_REG(0x0248)
+#define IPU_SRM_STAT			IPU_CM_REG(0x024C)
+#define IPU_PROC_TASK_STAT		IPU_CM_REG(0x0250)
+#define IPU_DISP_TASK_STAT		IPU_CM_REG(0x0254)
+#define IPU_CHA_BUF0_RDY(ch)		IPU_CM_REG(0x0268 + 4 * ((ch) / 32))
+#define IPU_CHA_BUF1_RDY(ch)		IPU_CM_REG(0x0270 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF0_RDY(ch)	IPU_CM_REG(0x0278 + 4 * ((ch) / 32))
+#define IPU_ALT_CHA_BUF1_RDY(ch)	IPU_CM_REG(0x0280 + 4 * ((ch) / 32))
+
+#define IPU_INT_CTRL(n)		IPU_CM_REG(0x003C + 4 * ((n) - 1))
+#define IPU_INT_CTRL_IRQ(irq)	IPU_INT_CTRL(((irq) / 32))
+#define IPU_INT_STAT_IRQ(irq)	IPU_INT_STAT(((irq) / 32))
+#define IPU_INT_STAT(n)		IPU_CM_REG(0x0200 + 4 * ((n) - 1))
+
+extern void __iomem *ipu_cm_reg;
+
+static inline u32 ipu_cm_read(unsigned offset)
+{
+	return __raw_readl(ipu_cm_reg + offset);
+}
+
+static inline void ipu_cm_write(u32 value, unsigned offset)
+{
+	__raw_writel(value, ipu_cm_reg + offset);
+}
+
+#define IPU_IDMAC_REG(offset)	(offset)
+
+#define IDMAC_CONF			IPU_IDMAC_REG(0x0000)
+#define IDMAC_CHA_EN(ch)		IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32))
+#define IDMAC_SEP_ALPHA			IPU_IDMAC_REG(0x000c)
+#define IDMAC_ALT_SEP_ALPHA		IPU_IDMAC_REG(0x0010)
+#define IDMAC_CHA_PRI(ch)		IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32))
+#define IDMAC_WM_EN(ch)			IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32))
+#define IDMAC_CH_LOCK_EN_1		IPU_IDMAC_REG(0x0024)
+#define IDMAC_CH_LOCK_EN_2		IPU_IDMAC_REG(0x0028)
+#define IDMAC_SUB_ADDR_0		IPU_IDMAC_REG(0x002c)
+#define IDMAC_SUB_ADDR_1		IPU_IDMAC_REG(0x0030)
+#define IDMAC_SUB_ADDR_2		IPU_IDMAC_REG(0x0034)
+#define IDMAC_BAND_EN(ch)		IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32))
+#define IDMAC_CHA_BUSY(ch)		IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32))
+
+extern void __iomem *ipu_idmac_reg;
+
+static inline u32 ipu_idmac_read(unsigned offset)
+{
+	return __raw_readl(ipu_idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(u32 value, unsigned offset)
+{
+	__raw_writel(value, ipu_idmac_reg + offset);
+}
+
+#define idmac_idma_is_set(reg, dma)	(ipu_idmac_read(reg(dma)) & idma_mask(dma))
+#define idma_mask(ch)			(1 << (ch & 0x1f))
+#define ipu_idma_is_set(reg, dma)	(ipu_cm_read(reg(dma)) & idma_mask(dma))
+
+enum ipu_modules {
+	IPU_CONF_CSI0_EN		= (1 << 0),
+	IPU_CONF_CSI1_EN		= (1 << 1),
+	IPU_CONF_IC_EN			= (1 << 2),
+	IPU_CONF_ROT_EN			= (1 << 3),
+	IPU_CONF_ISP_EN			= (1 << 4),
+	IPU_CONF_DP_EN			= (1 << 5),
+	IPU_CONF_DI0_EN			= (1 << 6),
+	IPU_CONF_DI1_EN			= (1 << 7),
+	IPU_CONF_SMFC_EN		= (1 << 8),
+	IPU_CONF_DC_EN			= (1 << 9),
+	IPU_CONF_DMFC_EN		= (1 << 10),
+
+	IPU_CONF_VDI_EN			= (1 << 12),
+
+	IPU_CONF_IDMAC_DIS		= (1 << 22),
+
+	IPU_CONF_IC_DMFC_SEL		= (1 << 25),
+	IPU_CONF_IC_DMFC_SYNC		= (1 << 26),
+	IPU_CONF_VDI_DMFC_SYNC		= (1 << 27),
+
+	IPU_CONF_CSI0_DATA_SOURCE	= (1 << 28),
+	IPU_CONF_CSI1_DATA_SOURCE	= (1 << 29),
+	IPU_CONF_IC_INPUT		= (1 << 30),
+	IPU_CONF_CSI_SEL		= (1 << 31),
+};
+
+struct ipu_channel {
+	unsigned int num;
+
+	bool enabled;
+	bool busy;
+};
+
+ipu_color_space_t format_to_colorspace(u32 fmt);
+bool ipu_pixel_format_has_alpha(u32 fmt);
+
+u32 _ipu_channel_status(struct ipu_channel *channel);
+
+int _ipu_chan_is_interlaced(struct ipu_channel *channel);
+
+int ipu_module_enable(u32 mask);
+int ipu_module_disable(u32 mask);
+
+int ipu_di_init(struct platform_device *pdev, int id, unsigned long base,
+		u32 module, struct clk *ipu_clk);
+void ipu_di_exit(struct platform_device *pdev, int id);
+
+int ipu_dmfc_init(struct platform_device *pdev, unsigned long base,
+		struct clk *ipu_clk);
+void ipu_dmfc_exit(struct platform_device *pdev);
+
+int ipu_dp_init(struct platform_device *pdev, unsigned long base);
+void ipu_dp_exit(struct platform_device *pdev);
+
+int ipu_dc_init(struct platform_device *pdev, unsigned long base,
+		unsigned long template_base);
+void ipu_dc_exit(struct platform_device *pdev);
+
+int ipu_cpmem_init(struct platform_device *pdev, unsigned long base);
+void ipu_cpmem_exit(struct platform_device *pdev);
+
+void ipu_get(void);
+void ipu_put(void);
+
+#endif				/* __IPU_PRV_H__ */
diff --git a/include/linux/mfd/imx-ipu-v3.h b/include/linux/mfd/imx-ipu-v3.h
new file mode 100644
index 0000000..7243360
--- /dev/null
+++ b/include/linux/mfd/imx-ipu-v3.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2005-2009 Freescale Semiconductor, Inc.
+ *
+ * The code contained herein is licensed under the GNU Lesser General
+ * Public License.  You may obtain a copy of the GNU Lesser General
+ * Public License Version 2.1 or later@the following locations:
+ *
+ * http://www.opensource.org/licenses/lgpl-license.html
+ * http://www.gnu.org/copyleft/lgpl.html
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/bitmap.h>
+
+/*
+ * Enumeration of IPU rotation modes
+ */
+typedef enum {
+	/* Note the enum values correspond to BAM value */
+	IPU_ROTATE_NONE = 0,
+	IPU_ROTATE_VERT_FLIP = 1,
+	IPU_ROTATE_HORIZ_FLIP = 2,
+	IPU_ROTATE_180 = 3,
+	IPU_ROTATE_90_RIGHT = 4,
+	IPU_ROTATE_90_RIGHT_VFLIP = 5,
+	IPU_ROTATE_90_RIGHT_HFLIP = 6,
+	IPU_ROTATE_90_LEFT = 7,
+} ipu_rotate_mode_t;
+
+/*
+ * IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/* Generic or Raw Data Formats */
+#define IPU_PIX_FMT_GENERIC v4l2_fourcc('I', 'P', 'U', '0')	/* IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 v4l2_fourcc('I', 'P', 'U', '1')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 v4l2_fourcc('L', 'V', 'D', '6')	/* IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 v4l2_fourcc('L', 'V', 'D', '8')	/* IPU Generic Data */
+/* RGB Formats */
+#define IPU_PIX_FMT_RGB332  V4L2_PIX_FMT_RGB332			/*  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  V4L2_PIX_FMT_RGB555			/* 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  V4L2_PIX_FMT_RGB565			/* 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  v4l2_fourcc('R', 'G', 'B', '6')	/* 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  v4l2_fourcc('B', 'G', 'R', '6')	/* 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   V4L2_PIX_FMT_BGR24			/* 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   V4L2_PIX_FMT_RGB24			/* 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_BGR32   V4L2_PIX_FMT_BGR32			/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  v4l2_fourcc('B', 'G', 'R', 'A')	/* 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   V4L2_PIX_FMT_RGB32			/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  v4l2_fourcc('R', 'G', 'B', 'A')	/* 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  v4l2_fourcc('A', 'B', 'G', 'R')	/* 32  ABGR-8-8-8-8 */
+/* YUV Interleaved Formats */
+#define IPU_PIX_FMT_YUYV    V4L2_PIX_FMT_YUYV			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    V4L2_PIX_FMT_UYVY			/* 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_Y41P    V4L2_PIX_FMT_Y41P			/* 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  V4L2_PIX_FMT_YUV444			/* 24 YUV 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    V4L2_PIX_FMT_NV12			/* 12  Y/CbCr 4:2:0  */
+/* YUV Planar Formats */
+#define IPU_PIX_FMT_GREY    V4L2_PIX_FMT_GREY			/* 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P V4L2_PIX_FMT_YVU410P		/* 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P V4L2_PIX_FMT_YUV410P		/* 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P v4l2_fourcc('Y', 'V', '1', '2')	/* 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P v4l2_fourcc('I', '4', '2', '0')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 v4l2_fourcc('Y', 'U', '1', '2')	/* 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P v4l2_fourcc('Y', 'V', '1', '6')	/* 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P V4L2_PIX_FMT_YUV422P		/* 16 YUV 4:2:2 */
+
+/*
+ * Bitfield of Display Interface signal polarities.
+ */
+struct ipu_di_signal_cfg {
+	unsigned datamask_en:1;
+	unsigned ext_clk:1;
+	unsigned interlaced:1;
+	unsigned odd_field_first:1;
+	unsigned clksel_en:1;
+	unsigned clkidle_en:1;
+	unsigned data_pol:1;	/* true = inverted */
+	unsigned clk_pol:1;	/* true = rising edge */
+	unsigned enable_pol:1;
+	unsigned Hsync_pol:1;	/* true = active high */
+	unsigned Vsync_pol:1;
+
+	u16 width;
+	u16 height;
+	u32 pixel_fmt;
+	u16 h_start_width;
+	u16 h_sync_width;
+	u16 h_end_width;
+	u16 v_start_width;
+	u16 v_sync_width;
+	u16 v_end_width;
+	u32 v_to_h_sync;
+};
+
+typedef enum {
+	RGB,
+	YCbCr,
+	YUV
+} ipu_color_space_t;
+
+#define IPU_IRQ_EOF(channel)		(channel)		/* 0 .. 63 */
+#define IPU_IRQ_NFACK(channel)		((channel) + 64)	/* 64 .. 127 */
+#define IPU_IRQ_NFB4EOF(channel)	((channel) + 128)	/* 128 .. 191 */
+#define IPU_IRQ_EOS(channel)		((channel) + 192)	/* 192 .. 255 */
+
+#define IPU_IRQ_DP_SF_START		(448 + 2)
+#define IPU_IRQ_DP_SF_END		(448 + 3)
+#define IPU_IRQ_BG_SF_END		IPU_IRQ_DP_SF_END,
+#define IPU_IRQ_DC_FC_0			(448 + 8)
+#define IPU_IRQ_DC_FC_1			(448 + 9)
+#define IPU_IRQ_DC_FC_2			(448 + 10)
+#define IPU_IRQ_DC_FC_3			(448 + 11)
+#define IPU_IRQ_DC_FC_4			(448 + 12)
+#define IPU_IRQ_DC_FC_6			(448 + 13)
+#define IPU_IRQ_VSYNC_PRE_0		(448 + 14)
+#define IPU_IRQ_VSYNC_PRE_1		(448 + 15)
+
+#define IPU_IRQ_COUNT	(15 * 32)
+
+#define DECLARE_IPU_IRQ_BITMAP(name)	DECLARE_BITMAP(name, IPU_IRQ_COUNT)
+
+struct ipu_irq_handler {
+	struct list_head	list;
+	void			(*handler)(unsigned long *, void *);
+	void			*context;
+	DECLARE_IPU_IRQ_BITMAP(ipu_irqs);
+};
+
+int ipu_irq_add_handler(struct ipu_irq_handler *ipuirq);
+void ipu_irq_remove_handler(struct ipu_irq_handler *handler);
+int ipu_irq_update_handler(struct ipu_irq_handler *handler,
+		unsigned long *bitmap);
+int ipu_wait_for_interrupt(int interrupt, int timeout_ms);
+
+struct ipu_channel;
+
+/*
+ * IPU Image DMA Controller (idmac) functions
+ */
+struct ipu_channel *ipu_idmac_get(unsigned channel);
+void ipu_idmac_put(struct ipu_channel *);
+int ipu_idmac_init_channel_buffer(struct ipu_channel *channel,
+				u32 pixel_fmt,
+				u16 width, u16 height,
+				u32 stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				u32 u_offset, u32 v_offset, bool interlaced);
+
+int ipu_idmac_update_channel_buffer(struct ipu_channel *channel,
+				  u32 bufNum, dma_addr_t phyaddr);
+
+int ipu_idmac_enable_channel(struct ipu_channel *channel);
+int ipu_idmac_disable_channel(struct ipu_channel *channel);
+
+void ipu_idmac_set_double_buffer(struct ipu_channel *channel, bool doublebuffer);
+void ipu_idmac_select_buffer(struct ipu_channel *channel, u32 buf_num);
+
+/*
+ * IPU Display Controller (dc) functions
+ */
+int ipu_dc_init_sync(int dc_chan, int di, bool interlaced, u32 pixel_fmt, u32 width);
+void ipu_dc_init_async(int dc_chan, int di, bool interlaced);
+void ipu_dc_enable_channel(u32 dc_chan);
+void ipu_dc_disable_channel(u32 dc_chan);
+
+/*
+ * IPU Display Interface (di) functions
+ */
+struct ipu_di;
+struct ipu_di *ipu_di_get(int disp);
+void ipu_di_put(struct ipu_di *);
+int ipu_di_disable(struct ipu_di *);
+int ipu_di_enable(struct ipu_di *);
+int ipu_di_init_sync_panel(struct ipu_di *, u32 pixel_clk,
+		struct ipu_di_signal_cfg *sig);
+
+/*
+ * IPU Display Multi FIFO Controller (dmfc) functions
+ */
+struct dmfc_channel;
+int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc);
+void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc);
+int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, unsigned long bandwidth_mbs);
+void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc);
+int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width);
+struct dmfc_channel *ipu_dmfc_get(int ipu_channel);
+void ipu_dmfc_put(struct dmfc_channel *dmfc);
+
+/*
+ * IPU Display Processor (dp) functions
+ */
+#define IPU_DP_FLOW_SYNC	0
+#define IPU_DP_FLOW_ASYNC0	1
+#define IPU_DP_FLOW_ASYNC1	2
+
+struct ipu_dp *ipu_dp_get(unsigned int flow);
+void ipu_dp_put(struct ipu_dp *);
+int ipu_dp_enable_channel(struct ipu_dp *dp);
+void ipu_dp_disable_channel(struct ipu_dp *dp);
+void ipu_dp_enable_fg(struct ipu_dp *dp);
+void ipu_dp_disable_fg(struct ipu_dp *dp);
+int ipu_dp_setup_channel(struct ipu_dp *dp, u32 in_pixel_fmt,
+		 u32 out_pixel_fmt, int bg);
+int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos);
+int ipu_dp_set_color_key(struct ipu_dp *dp, bool enable, u32 colorKey);
+int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha,
+		bool bg_chan);
+
+#endif
-- 
1.7.2.3

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

end of thread, other threads:[~2011-04-25 13:37 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-04-13 15:53 [PATCH 1/7] Add a mfd IPUv3 driver weitway at gmail.com
2011-04-13 15:53 ` [PATCH 2/7] ARM i.MX5: Add IPU device support weitway at gmail.com
2011-04-14  9:25   ` Sascha Hauer
2011-04-14 12:40     ` Jason Chen
2011-04-13 15:53 ` [PATCH 3/7] Add i.MX5 framebuffer driver weitway at gmail.com
2011-04-14  8:49   ` Sascha Hauer
2011-04-13 15:53 ` [PATCH 4/7] ARM i.MX51 babbage: Add framebuffer support weitway at gmail.com
2011-04-13 15:53 ` [PATCH 5/7] ARM i.MX53 loco: " weitway at gmail.com
2011-04-14  8:57   ` Sascha Hauer
2011-04-14  9:01     ` Chen Jie-B02280
2011-04-14  9:12       ` Sascha Hauer
2011-04-14 12:37         ` Jason Chen
2011-04-13 15:53 ` [PATCH 6/7] ARM i.MX53: add pwm devices support weitway at gmail.com
2011-04-13 15:53 ` [PATCH 7/7] ARM: i.MX53 loco: add pwm backlight device weitway at gmail.com
2011-04-14  9:08 ` [PATCH 1/7] Add a mfd IPUv3 driver Sascha Hauer
  -- strict thread matches above, loose matches on Subject: below --
2011-04-14  2:27 Chen Jie-B02280
2011-04-25 13:37 ` Jason Chen
2011-04-14  2:04 jason.chen at freescale.com
2011-02-16 14:10 [PATCH v3] Add i.MX51/53 IPU framebuffer support Sascha Hauer
2011-02-16 14:10 ` [PATCH 1/7] Add a mfd IPUv3 driver Sascha Hauer
2011-02-16 14:10   ` Sascha Hauer
2011-02-17 18:10   ` Arnaud Patard
2011-02-17 18:10     ` Arnaud Patard (Rtp)
2011-02-17 18:10     ` Arnaud Patard
2011-02-18  9:49     ` Sascha Hauer
2011-02-18  9:49       ` Sascha Hauer
2011-02-18  9:49       ` Sascha Hauer
2011-02-18 12:07       ` Samuel Ortiz
2011-02-18 12:07         ` Samuel Ortiz
2011-02-18 12:07         ` Samuel Ortiz
2011-02-21  5:38   ` Jason Chen
2011-02-21  5:38     ` Jason Chen
2011-02-21  5:38     ` Jason Chen

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