ipuv3: add base driver for ipuv3

Base IPUv3 driver copied directly from linux-imx-2.6.38.

Signed-off-by: Jason Chen <b02280@freescale.com>
diff --git a/arch/arm/mach-mx5/Kconfig b/arch/arm/mach-mx5/Kconfig
index 419e43e..d9d89b9 100644
--- a/arch/arm/mach-mx5/Kconfig
+++ b/arch/arm/mach-mx5/Kconfig
@@ -32,6 +32,7 @@
 	select ARCH_HAS_CPUFREQ
 	select ARCH_MX5
 	select IMX_HAVE_PLATFORM_IMX_IIM
+	select IMX_HAVE_PLATFORM_IMX_IPUV3
 
 config	SOC_IMX53
 	bool
@@ -43,6 +44,7 @@
 	select ARCH_MX5
 	select ARCH_MX53
 	select IMX_HAVE_PLATFORM_IMX_IIM
+	select IMX_HAVE_PLATFORM_IMX_IPUV3
 
 if ARCH_MX50_SUPPORTED
 #comment "i.MX50 machines:"
diff --git a/arch/arm/mach-mx5/clock.c b/arch/arm/mach-mx5/clock.c
index fc28dfc..5eb4f0b 100644
--- a/arch/arm/mach-mx5/clock.c
+++ b/arch/arm/mach-mx5/clock.c
@@ -4447,9 +4447,9 @@
 	_REGISTER_CLOCK(NULL, "vpu_core_clk", vpu_clk[1]),
 	_REGISTER_CLOCK(NULL, "nfc_clk", emi_enfc_clk),
 	_REGISTER_CLOCK("imx-sdma", NULL, sdma_clk[0]),
-	_REGISTER_CLOCK(NULL, "ipu_clk", ipu_clk[0]),
-	_REGISTER_CLOCK(NULL, "ipu_di0_clk", ipu_di_clk[0]),
-	_REGISTER_CLOCK(NULL, "ipu_di1_clk", ipu_di_clk[1]),
+	_REGISTER_CLOCK(NULL, "ipu1_clk", ipu_clk[0]),
+	_REGISTER_CLOCK(NULL, "ipu1_di0_clk", ipu_di_clk[0]),
+	_REGISTER_CLOCK(NULL, "ipu1_di1_clk", ipu_di_clk[1]),
 	_REGISTER_CLOCK(NULL, "csi_mclk1", csi0_clk),
 	_REGISTER_CLOCK(NULL, "csi_mclk2", csi1_clk),
 	_REGISTER_CLOCK(NULL, "tve_clk", tve_clk),
diff --git a/arch/arm/mach-mx5/devices-imx51.h b/arch/arm/mach-mx5/devices-imx51.h
index e11bc0e..5446680 100644
--- a/arch/arm/mach-mx5/devices-imx51.h
+++ b/arch/arm/mach-mx5/devices-imx51.h
@@ -52,3 +52,7 @@
 extern const struct imx_imx_keypad_data imx51_imx_keypad_data;
 #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(id, pdata)	imx_add_ipuv3(id, &imx51_ipuv3_data, pdata)
+#define imx51_add_ipuv3fb(id, pdata)	imx_add_ipuv3_fb(id, pdata)
diff --git a/arch/arm/mach-mx5/devices-imx53.h b/arch/arm/mach-mx5/devices-imx53.h
index c7e42de..00f03df 100644
--- a/arch/arm/mach-mx5/devices-imx53.h
+++ b/arch/arm/mach-mx5/devices-imx53.h
@@ -52,3 +52,7 @@
 extern const struct imx_ahci_imx_data imx53_ahci_imx_data __initconst;
 #define imx53_add_ahci_imx(id, pdata)   \
 	imx_add_ahci_imx(&imx53_ahci_imx_data, pdata)
+
+extern const struct imx_ipuv3_data imx53_ipuv3_data __initconst;
+#define imx53_add_ipuv3(id, pdata)	imx_add_ipuv3(id, &imx53_ipuv3_data, pdata)
+#define imx53_add_ipuv3fb(id, pdata)	imx_add_ipuv3_fb(id, pdata)
diff --git a/arch/arm/plat-mxc/devices/Kconfig b/arch/arm/plat-mxc/devices/Kconfig
index 7974585..3e78ca6 100644
--- a/arch/arm/plat-mxc/devices/Kconfig
+++ b/arch/arm/plat-mxc/devices/Kconfig
@@ -43,6 +43,9 @@
 config IMX_HAVE_PLATFORM_IMX_UDC
 	bool
 
+config IMX_HAVE_PLATFORM_IMX_IPUV3
+	bool
+
 config IMX_HAVE_PLATFORM_IPU_CORE
 	bool
 
diff --git a/arch/arm/plat-mxc/devices/Makefile b/arch/arm/plat-mxc/devices/Makefile
index 7b491d8..c0286b9 100644
--- a/arch/arm/plat-mxc/devices/Makefile
+++ b/arch/arm/plat-mxc/devices/Makefile
@@ -15,6 +15,7 @@
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UART) += platform-imx-uart.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_UDC) += platform-imx_udc.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_IPU_CORE) += platform-ipu-core.o
+obj-$(CONFIG_IMX_HAVE_PLATFORM_IMX_IPUV3) +=  platform-imx_ipuv3.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MX1_CAMERA) += platform-mx1-camera.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MX2_CAMERA) += platform-mx2-camera.o
 obj-$(CONFIG_IMX_HAVE_PLATFORM_MXC_EHCI) += platform-mxc-ehci.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..a353060
--- /dev/null
+++ b/arch/arm/plat-mxc/devices/platform-imx_ipuv3.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ */
+
+/*
+ * 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.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <linux/dma-mapping.h>
+#include <linux/clk.h>
+
+#define imx5_ipuv3_data_entry_single(soc, size, ipu_init, ipu_pg)	\
+	{								\
+		.iobase = soc ## _IPU_CTRL_BASE_ADDR,			\
+		.irq_err = soc ## _INT_IPU_ERR,				\
+		.irq = soc ## _INT_IPU_SYN,				\
+		.irq_start = MXC_IPU_IRQ_START, 			\
+		.iosize = size,						\
+		.init = ipu_init,					\
+		.pg = ipu_pg,						\
+	}
+
+#define imx6_ipuv3_data_entry_single(soc, id, size, ipu_init, ipu_pg)	\
+	{								\
+		.iobase = soc ## _IPU ## id ## _ARB_BASE_ADDR,			\
+		.irq_err = soc ## _INT_IPU ## id ## _ERR,			\
+		.irq = soc ## _INT_IPU ## id ## _SYN,				\
+		.irq_start = MXC_IPU_IRQ_START, 			\
+		.iosize = size,						\
+		.init = ipu_init,					\
+		.pg = ipu_pg,						\
+	}
+
+#ifdef CONFIG_SOC_IMX51
+/*
+ * 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 __init 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 */
+	writel(0xF00, hsc_addr);
+
+	/* CSI mode: reserved; DI control mode: legacy (from Freescale BSP) */
+	writel(readl(hsc_addr + 0x800) | 0x30ff,
+			hsc_addr + 0x800);
+
+	clk_disable(hsc_clk);
+	clk_put(hsc_clk);
+unmap:
+	iounmap(hsc_addr);
+
+	return ret;
+}
+
+int __init mx51_ipuv3_init(int id)
+{
+	int ret = 0;
+	u32 val;
+
+	ret = ipu_mipi_setup();
+
+	/* 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;
+}
+
+void mx51_ipuv3_pg(int enable)
+{
+	if (enable) {
+		writel(MXC_PGCR_PCR, MX51_PGC_IPU_PGCR);
+		writel(MXC_PGSR_PSR, MX51_PGC_IPU_PGSR);
+	} else {
+		writel(0x0, MX51_PGC_IPU_PGCR);
+		if (readl(MX51_PGC_IPU_PGSR) & MXC_PGSR_PSR)
+			printk(KERN_DEBUG "power gating successful\n");
+		writel(MXC_PGSR_PSR, MX51_PGC_IPU_PGSR);
+	}
+}
+
+const struct imx_ipuv3_data imx51_ipuv3_data __initconst =
+			imx5_ipuv3_data_entry_single(MX51, SZ_512M,
+					mx51_ipuv3_init, mx51_ipuv3_pg);
+#endif
+
+#ifdef CONFIG_SOC_IMX53
+int __init mx53_ipuv3_init(int id)
+{
+	int ret = 0;
+	u32 val;
+
+	/* 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;
+}
+
+void mx53_ipuv3_pg(int enable)
+{
+	if (enable) {
+		writel(MXC_PGCR_PCR, MX53_PGC_IPU_PGCR);
+		writel(MXC_PGSR_PSR, MX53_PGC_IPU_PGSR);
+	} else {
+		writel(0x0, MX53_PGC_IPU_PGCR);
+		if (readl(MX53_PGC_IPU_PGSR) & MXC_PGSR_PSR)
+			printk(KERN_DEBUG "power gating successful\n");
+		writel(MXC_PGSR_PSR, MX53_PGC_IPU_PGSR);
+	}
+}
+
+const struct imx_ipuv3_data imx53_ipuv3_data __initconst =
+			imx5_ipuv3_data_entry_single(MX53, SZ_128M,
+					mx53_ipuv3_init, mx53_ipuv3_pg);
+#endif
+
+#ifdef CONFIG_SOC_IMX6Q
+int __init mx6q_ipuv3_init(int id)
+{
+	int ret = 0;
+	u32 val;
+
+	/* hard reset the IPU */
+	val = readl(MX6_IO_ADDRESS(SRC_BASE_ADDR));
+	if (id == 0)
+		val |= 1 << 3;
+	else
+		val |= 1 << 12;
+	writel(val, MX6_IO_ADDRESS(SRC_BASE_ADDR));
+
+	return ret;
+}
+
+void mx6q_ipuv3_pg(int enable)
+{
+	/*TODO*/
+}
+
+const struct imx_ipuv3_data imx6q_ipuv3_data[] __initconst = {
+	imx6_ipuv3_data_entry_single(MX6Q, 1, SZ_4M,
+			mx6q_ipuv3_init, mx6q_ipuv3_pg),
+	imx6_ipuv3_data_entry_single(MX6Q, 2, SZ_4M,
+			mx6q_ipuv3_init, mx6q_ipuv3_pg),
+};
+#endif
+
+struct platform_device *__init imx_add_ipuv3(
+		const int id,
+		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;
+	pdata->pg = data->pg;
+
+	return imx_add_platform_device_dmamask("imx-ipuv3", id,
+			res, ARRAY_SIZE(res), pdata, sizeof(*pdata),
+			DMA_BIT_MASK(32));
+}
+
+struct platform_device *__init imx_add_ipuv3_fb(
+		const int id,
+		const struct ipuv3_fb_platform_data *pdata)
+{
+	if (pdata->res_size > 0) {
+		struct resource res[] = {
+			{
+				.start = pdata->res_base,
+				.end = pdata->res_base + pdata->res_size - 1,
+				.flags = IORESOURCE_MEM,
+			},
+		};
+
+		return imx_add_platform_device_dmamask("mxc_sdc_fb",
+				id, res, ARRAY_SIZE(res), pdata,
+				sizeof(*pdata), DMA_BIT_MASK(32));
+	} else
+		return imx_add_platform_device_dmamask("mxc_sdc_fb", id,
+				NULL, 0, pdata, sizeof(*pdata),
+				DMA_BIT_MASK(32));
+}
diff --git a/arch/arm/plat-mxc/include/mach/devices-common.h b/arch/arm/plat-mxc/include/mach/devices-common.h
index 9b1b7df..72d7151 100644
--- a/arch/arm/plat-mxc/include/mach/devices-common.h
+++ b/arch/arm/plat-mxc/include/mach/devices-common.h
@@ -171,23 +171,24 @@
 		const struct imx_imx_udc_data *data,
 		const struct imxusb_platform_data *pdata);
 
-#include <mach/ipu.h>
-#include <mach/mx3fb.h>
-#include <mach/mx3_camera.h>
-struct imx_ipu_core_data {
+#include <mach/ipu-v3.h>
+struct imx_ipuv3_data {
 	resource_size_t iobase;
-	resource_size_t synirq;
-	resource_size_t errirq;
+	resource_size_t iosize;
+	resource_size_t irq_err;
+	resource_size_t irq;
+	unsigned int irq_start;
+	int (*init) (int);
+	void (*pg) (int);
 };
-struct platform_device *__init imx_add_ipu_core(
-		const struct imx_ipu_core_data *data,
-		const struct ipu_platform_data *pdata);
-struct platform_device *__init imx_alloc_mx3_camera(
-		const struct imx_ipu_core_data *data,
-		const struct mx3_camera_pdata *pdata);
-struct platform_device *__init imx_add_mx3_sdc_fb(
-		const struct imx_ipu_core_data *data,
-		struct mx3fb_platform_data *pdata);
+struct platform_device *__init imx_add_ipuv3(
+		const int id,
+		const struct imx_ipuv3_data *data,
+		struct imx_ipuv3_platform_data *pdata);
+
+struct platform_device *__init imx_add_ipuv3_fb(
+		const int id,
+		const struct ipuv3_fb_platform_data *pdata);
 
 #include <mach/mx1_camera.h>
 struct imx_mx1_camera_data {
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..713ee9f
--- /dev/null
+++ b/arch/arm/plat-mxc/include/mach/ipu-v3.h
@@ -0,0 +1,770 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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_
+
+#include <linux/ipu.h>
+
+/*  IPU Pixel format definitions */
+/*  Four-character-code (FOURCC) */
+#define fourcc(a, b, c, d)\
+	 (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+
+/*!
+ * @name IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/*! @{ */
+/*! @name Generic or Raw Data Formats */
+/*! @{ */
+#define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8')	/*!< IPU Generic Data */
+/*! @} */
+/*! @name RGB Formats */
+/*! @{ */
+#define IPU_PIX_FMT_RGB332  fourcc('R', 'G', 'B', '1')	/*!<  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  fourcc('R', 'G', 'B', 'O')	/*!< 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  fourcc('R', 'G', 'B', 'P')	/*!< 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  fourcc('R', 'G', 'B', '6')	/*!< 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  fourcc('B', 'G', 'R', '6')	/*!< 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   fourcc('B', 'G', 'R', '3')	/*!< 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   fourcc('R', 'G', 'B', '3')	/*!< 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_GBR24   fourcc('G', 'B', 'R', '3')	/*!< 24  GBR-8-8-8    */
+#define IPU_PIX_FMT_BGR32   fourcc('B', 'G', 'R', '4')	/*!< 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  fourcc('B', 'G', 'R', 'A')	/*!< 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   fourcc('R', 'G', 'B', '4')	/*!< 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  fourcc('R', 'G', 'B', 'A')	/*!< 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  fourcc('A', 'B', 'G', 'R')	/*!< 32  ABGR-8-8-8-8 */
+/*! @} */
+/*! @name YUV Interleaved Formats */
+/*! @{ */
+#define IPU_PIX_FMT_YUYV    fourcc('Y', 'U', 'Y', 'V')	/*!< 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    fourcc('U', 'Y', 'V', 'Y')	/*!< 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_YVYU    fourcc('Y', 'V', 'Y', 'U')  /*!< 16 YVYU 4:2:2 */
+#define IPU_PIX_FMT_VYUY    fourcc('V', 'Y', 'U', 'Y')  /*!< 16 VYYU 4:2:2 */
+#define IPU_PIX_FMT_Y41P    fourcc('Y', '4', '1', 'P')	/*!< 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  fourcc('Y', '4', '4', '4')	/*!< 24 YUV 4:4:4 */
+#define IPU_PIX_FMT_VYU444  fourcc('V', '4', '4', '4')	/*!< 24 VYU 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
+/*! @} */
+/*! @name YUV Planar Formats */
+/*! @{ */
+#define IPU_PIX_FMT_GREY    fourcc('G', 'R', 'E', 'Y')	/*!< 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P fourcc('Y', 'V', 'U', '9')	/*!< 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P fourcc('Y', 'U', 'V', '9')	/*!< 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P fourcc('Y', 'V', '1', '2')	/*!< 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P fourcc('I', '4', '2', '0')	/*!< 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 fourcc('Y', 'U', '1', '2')	/*!< 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P fourcc('Y', 'V', '1', '6')	/*!< 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P')	/*!< 16 YUV 4:2:2 */
+/*! @} */
+
+/* IPU Driver channels definitions.	*/
+/* Note these are different from IDMA channels */
+#define IPU_MAX_CH	32
+#define _MAKE_CHAN(num, v_in, g_in, a_in, out) \
+	((num << 24) | (v_in << 18) | (g_in << 12) | (a_in << 6) | out)
+#define _MAKE_ALT_CHAN(ch)		(ch | (IPU_MAX_CH << 24))
+#define IPU_CHAN_ID(ch)			(ch >> 24)
+#define IPU_CHAN_ALT(ch)		(ch & 0x02000000)
+#define IPU_CHAN_ALPHA_IN_DMA(ch)	((uint32_t) (ch >> 6) & 0x3F)
+#define IPU_CHAN_GRAPH_IN_DMA(ch)	((uint32_t) (ch >> 12) & 0x3F)
+#define IPU_CHAN_VIDEO_IN_DMA(ch)	((uint32_t) (ch >> 18) & 0x3F)
+#define IPU_CHAN_OUT_DMA(ch)		((uint32_t) (ch & 0x3F))
+#define NO_DMA 0x3F
+#define ALT	1
+/*!
+ * Enumeration of IPU logical channels. An IPU logical channel is defined as a
+ * combination of an input (memory to IPU), output (IPU to memory), and/or
+ * secondary input IDMA channels and in some cases an Image Converter task.
+ * Some channels consist of only an input or output.
+ */
+typedef enum {
+	CHAN_NONE = -1,
+	MEM_ROT_ENC_MEM = _MAKE_CHAN(1, 45, NO_DMA, NO_DMA, 48),
+	MEM_ROT_VF_MEM = _MAKE_CHAN(2, 46, NO_DMA, NO_DMA, 49),
+	MEM_ROT_PP_MEM = _MAKE_CHAN(3, 47, NO_DMA, NO_DMA, 50),
+
+	MEM_PRP_ENC_MEM = _MAKE_CHAN(4, 12, 14, 17, 20),
+	MEM_PRP_VF_MEM = _MAKE_CHAN(5, 12, 14, 17, 21),
+	MEM_PP_MEM = _MAKE_CHAN(6, 11, 15, 18, 22),
+
+	MEM_DC_SYNC = _MAKE_CHAN(7, 28, NO_DMA, NO_DMA, NO_DMA),
+	MEM_DC_ASYNC = _MAKE_CHAN(8, 41, NO_DMA, NO_DMA, NO_DMA),
+	MEM_BG_SYNC = _MAKE_CHAN(9, 23, NO_DMA, 51, NO_DMA),
+	MEM_FG_SYNC = _MAKE_CHAN(10, 27, NO_DMA, 31, NO_DMA),
+
+	MEM_BG_ASYNC0 = _MAKE_CHAN(11, 24, NO_DMA, 52, NO_DMA),
+	MEM_FG_ASYNC0 = _MAKE_CHAN(12, 29, NO_DMA, 33, NO_DMA),
+	MEM_BG_ASYNC1 = _MAKE_ALT_CHAN(MEM_BG_ASYNC0),
+	MEM_FG_ASYNC1 = _MAKE_ALT_CHAN(MEM_FG_ASYNC0),
+
+	DIRECT_ASYNC0 = _MAKE_CHAN(13, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
+	DIRECT_ASYNC1 = _MAKE_CHAN(14, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
+
+	CSI_MEM0 = _MAKE_CHAN(15, NO_DMA, NO_DMA, NO_DMA, 0),
+	CSI_MEM1 = _MAKE_CHAN(16, NO_DMA, NO_DMA, NO_DMA, 1),
+	CSI_MEM2 = _MAKE_CHAN(17, NO_DMA, NO_DMA, NO_DMA, 2),
+	CSI_MEM3 = _MAKE_CHAN(18, NO_DMA, NO_DMA, NO_DMA, 3),
+
+	CSI_MEM = CSI_MEM0,
+
+	CSI_PRP_ENC_MEM = _MAKE_CHAN(19, NO_DMA, NO_DMA, NO_DMA, 20),
+	CSI_PRP_VF_MEM = _MAKE_CHAN(20, NO_DMA, NO_DMA, NO_DMA, 21),
+
+	MEM_VDI_PRP_VF_MEM_P = _MAKE_CHAN(21, 8, 14, 17, 21),
+	MEM_VDI_PRP_VF_MEM = _MAKE_CHAN(22, 9, 14, 17, 21),
+	MEM_VDI_PRP_VF_MEM_N = _MAKE_CHAN(23, 10, 14, 17, 21),
+
+	MEM_PP_ADC = CHAN_NONE,
+	ADC_SYS2 = CHAN_NONE,
+
+} ipu_channel_t;
+
+/*!
+ * Enumeration of types of buffers for a logical channel.
+ */
+typedef enum {
+	IPU_OUTPUT_BUFFER = 0,	/*!< Buffer for output from IPU */
+	IPU_ALPHA_IN_BUFFER = 1,	/*!< Buffer for input to IPU */
+	IPU_GRAPH_IN_BUFFER = 2,	/*!< Buffer for input to IPU */
+	IPU_VIDEO_IN_BUFFER = 3,	/*!< Buffer for input to IPU */
+	IPU_INPUT_BUFFER = IPU_VIDEO_IN_BUFFER,
+	IPU_SEC_INPUT_BUFFER = IPU_GRAPH_IN_BUFFER,
+} ipu_buffer_t;
+
+#define IPU_PANEL_SERIAL		1
+#define IPU_PANEL_PARALLEL		2
+
+/*!
+ * Enumeration of ADC channel operation mode.
+ */
+typedef enum {
+	Disable,
+	WriteTemplateNonSeq,
+	ReadTemplateNonSeq,
+	WriteTemplateUnCon,
+	ReadTemplateUnCon,
+	WriteDataWithRS,
+	WriteDataWoRS,
+	WriteCmd
+} mcu_mode_t;
+
+/*!
+ * Enumeration of ADC channel addressing mode.
+ */
+typedef enum {
+	FullWoBE,
+	FullWithBE,
+	XY
+} display_addressing_t;
+
+/*!
+ * Union of initialization parameters for a logical channel.
+ */
+typedef union {
+	struct {
+		uint32_t csi;
+		uint32_t mipi_id;
+		bool mipi_en;
+		bool interlaced;
+	} csi_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		uint32_t csi;
+	} csi_prp_enc_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		uint32_t outh_resize_ratio;
+		uint32_t outv_resize_ratio;
+	} mem_prp_enc_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+	} mem_rot_enc_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		bool graphics_combine_en;
+		bool global_alpha_en;
+		bool key_color_en;
+		uint32_t csi;
+	} csi_prp_vf_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		bool graphics_combine_en;
+		bool global_alpha_en;
+		bool key_color_en;
+		display_port_t disp;
+		uint32_t out_left;
+		uint32_t out_top;
+	} csi_prp_vf_adc;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		uint32_t outh_resize_ratio;
+		uint32_t outv_resize_ratio;
+		bool graphics_combine_en;
+		bool global_alpha_en;
+		bool key_color_en;
+		uint32_t in_g_pixel_fmt;
+		uint8_t alpha;
+		uint32_t key_color;
+		bool alpha_chan_en;
+		ipu_motion_sel motion_sel;
+		enum v4l2_field field_fmt;
+	} mem_prp_vf_mem;
+	struct {
+		uint32_t temp;
+	} mem_prp_vf_adc;
+	struct {
+		uint32_t temp;
+	} mem_rot_vf_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		uint32_t outh_resize_ratio;
+		uint32_t outv_resize_ratio;
+		bool graphics_combine_en;
+		bool global_alpha_en;
+		bool key_color_en;
+		uint32_t in_g_pixel_fmt;
+		uint8_t alpha;
+		uint32_t key_color;
+		bool alpha_chan_en;
+	} mem_pp_mem;
+	struct {
+		uint32_t temp;
+	} mem_rot_mem;
+	struct {
+		uint32_t in_width;
+		uint32_t in_height;
+		uint32_t in_pixel_fmt;
+		uint32_t out_width;
+		uint32_t out_height;
+		uint32_t out_pixel_fmt;
+		bool graphics_combine_en;
+		bool global_alpha_en;
+		bool key_color_en;
+		display_port_t disp;
+		uint32_t out_left;
+		uint32_t out_top;
+	} mem_pp_adc;
+	struct {
+		uint32_t di;
+		bool interlaced;
+		uint32_t in_pixel_fmt;
+		uint32_t out_pixel_fmt;
+	} mem_dc_sync;
+	struct {
+		uint32_t temp;
+	} mem_sdc_fg;
+	struct {
+		uint32_t di;
+		bool interlaced;
+		uint32_t in_pixel_fmt;
+		uint32_t out_pixel_fmt;
+		bool alpha_chan_en;
+	} mem_dp_bg_sync;
+	struct {
+		uint32_t temp;
+	} mem_sdc_bg;
+	struct {
+		uint32_t di;
+		bool interlaced;
+		uint32_t in_pixel_fmt;
+		uint32_t out_pixel_fmt;
+		bool alpha_chan_en;
+	} mem_dp_fg_sync;
+	struct {
+		uint32_t di;
+	} direct_async;
+	struct {
+		display_port_t disp;
+		mcu_mode_t ch_mode;
+		uint32_t out_left;
+		uint32_t out_top;
+	} adc_sys1;
+	struct {
+		display_port_t disp;
+		mcu_mode_t ch_mode;
+		uint32_t out_left;
+		uint32_t out_top;
+	} adc_sys2;
+} ipu_channel_params_t;
+
+/*!
+ * Enumeration of IPU interrupt sources.
+ */
+enum ipu_irq_line {
+	IPU_IRQ_CSI0_OUT_EOF = 0,
+	IPU_IRQ_CSI1_OUT_EOF = 1,
+	IPU_IRQ_CSI2_OUT_EOF = 2,
+	IPU_IRQ_CSI3_OUT_EOF = 3,
+	IPU_IRQ_VDI_P_IN_EOF = 8,
+	IPU_IRQ_VDI_C_IN_EOF = 9,
+	IPU_IRQ_VDI_N_IN_EOF = 10,
+	IPU_IRQ_PP_IN_EOF = 11,
+	IPU_IRQ_PRP_IN_EOF = 12,
+	IPU_IRQ_PRP_GRAPH_IN_EOF = 14,
+	IPU_IRQ_PP_GRAPH_IN_EOF = 15,
+	IPU_IRQ_PRP_ALPHA_IN_EOF = 17,
+	IPU_IRQ_PP_ALPHA_IN_EOF = 18,
+	IPU_IRQ_PRP_ENC_OUT_EOF = 20,
+	IPU_IRQ_PRP_VF_OUT_EOF = 21,
+	IPU_IRQ_PP_OUT_EOF = 22,
+	IPU_IRQ_BG_SYNC_EOF = 23,
+	IPU_IRQ_BG_ASYNC_EOF = 24,
+	IPU_IRQ_FG_SYNC_EOF = 27,
+	IPU_IRQ_DC_SYNC_EOF = 28,
+	IPU_IRQ_FG_ASYNC_EOF = 29,
+	IPU_IRQ_FG_ALPHA_SYNC_EOF = 31,
+
+	IPU_IRQ_FG_ALPHA_ASYNC_EOF = 33,
+	IPU_IRQ_DC_READ_EOF = 40,
+	IPU_IRQ_DC_ASYNC_EOF = 41,
+	IPU_IRQ_DC_CMD1_EOF = 42,
+	IPU_IRQ_DC_CMD2_EOF = 43,
+	IPU_IRQ_DC_MASK_EOF = 44,
+	IPU_IRQ_PRP_ENC_ROT_IN_EOF = 45,
+	IPU_IRQ_PRP_VF_ROT_IN_EOF = 46,
+	IPU_IRQ_PP_ROT_IN_EOF = 47,
+	IPU_IRQ_PRP_ENC_ROT_OUT_EOF = 48,
+	IPU_IRQ_PRP_VF_ROT_OUT_EOF = 49,
+	IPU_IRQ_PP_ROT_OUT_EOF = 50,
+	IPU_IRQ_BG_ALPHA_SYNC_EOF = 51,
+	IPU_IRQ_BG_ALPHA_ASYNC_EOF = 52,
+
+	IPU_IRQ_DP_SF_START = 448 + 2,
+	IPU_IRQ_DP_SF_END = 448 + 3,
+	IPU_IRQ_BG_SF_END = IPU_IRQ_DP_SF_END,
+	IPU_IRQ_DC_FC_0 = 448 + 8,
+	IPU_IRQ_DC_FC_1 = 448 + 9,
+	IPU_IRQ_DC_FC_2 = 448 + 10,
+	IPU_IRQ_DC_FC_3 = 448 + 11,
+	IPU_IRQ_DC_FC_4 = 448 + 12,
+	IPU_IRQ_DC_FC_6 = 448 + 13,
+	IPU_IRQ_VSYNC_PRE_0 = 448 + 14,
+	IPU_IRQ_VSYNC_PRE_1 = 448 + 15,
+
+	IPU_IRQ_COUNT
+};
+
+/*!
+ * Bitfield of Display Interface signal polarities.
+ */
+typedef struct {
+	unsigned datamask_en:1;
+	unsigned int_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;
+} ipu_di_signal_cfg_t;
+
+/*!
+ * Bitfield of CSI signal polarities and modes.
+ */
+
+typedef struct {
+	unsigned data_width:4;
+	unsigned clk_mode:3;
+	unsigned ext_vsync:1;
+	unsigned Vsync_pol:1;
+	unsigned Hsync_pol:1;
+	unsigned pixclk_pol:1;
+	unsigned data_pol:1;
+	unsigned sens_clksrc:1;
+	unsigned pack_tight:1;
+	unsigned force_eof:1;
+	unsigned data_en_pol:1;
+	unsigned data_fmt;
+	unsigned csi;
+	unsigned mclk;
+} ipu_csi_signal_cfg_t;
+
+/*!
+ * Enumeration of CSI data bus widths.
+ */
+enum {
+	IPU_CSI_DATA_WIDTH_4,
+	IPU_CSI_DATA_WIDTH_8,
+	IPU_CSI_DATA_WIDTH_10,
+	IPU_CSI_DATA_WIDTH_16,
+};
+
+/*!
+ * Enumeration of CSI clock modes.
+ */
+enum {
+	IPU_CSI_CLK_MODE_GATED_CLK,
+	IPU_CSI_CLK_MODE_NONGATED_CLK,
+	IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE,
+	IPU_CSI_CLK_MODE_CCIR656_INTERLACED,
+	IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR,
+	IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR,
+	IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR,
+	IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR,
+};
+
+enum {
+	IPU_CSI_MIPI_DI0,
+	IPU_CSI_MIPI_DI1,
+	IPU_CSI_MIPI_DI2,
+	IPU_CSI_MIPI_DI3,
+};
+
+typedef enum {
+	RGB,
+	YCbCr,
+	YUV
+} ipu_color_space_t;
+
+/*!
+ * Enumeration of ADC vertical sync mode.
+ */
+typedef enum {
+	VsyncNone,
+	VsyncInternal,
+	VsyncCSI,
+	VsyncExternal
+} vsync_t;
+
+typedef enum {
+	DAT,
+	CMD
+} cmddata_t;
+
+/*!
+ * Enumeration of ADC display update mode.
+ */
+typedef enum {
+	IPU_ADC_REFRESH_NONE,
+	IPU_ADC_AUTO_REFRESH,
+	IPU_ADC_AUTO_REFRESH_SNOOP,
+	IPU_ADC_SNOOPING,
+} ipu_adc_update_mode_t;
+
+/*!
+ * Enumeration of ADC display interface types (serial or parallel).
+ */
+enum {
+	IPU_ADC_IFC_MODE_SYS80_TYPE1,
+	IPU_ADC_IFC_MODE_SYS80_TYPE2,
+	IPU_ADC_IFC_MODE_SYS68K_TYPE1,
+	IPU_ADC_IFC_MODE_SYS68K_TYPE2,
+	IPU_ADC_IFC_MODE_3WIRE_SERIAL,
+	IPU_ADC_IFC_MODE_4WIRE_SERIAL,
+	IPU_ADC_IFC_MODE_5WIRE_SERIAL_CLK,
+	IPU_ADC_IFC_MODE_5WIRE_SERIAL_CS,
+};
+
+enum {
+	IPU_ADC_IFC_WIDTH_8,
+	IPU_ADC_IFC_WIDTH_16,
+};
+
+/*!
+ * Enumeration of ADC display interface burst mode.
+ */
+enum {
+	IPU_ADC_BURST_WCS,
+	IPU_ADC_BURST_WBLCK,
+	IPU_ADC_BURST_NONE,
+	IPU_ADC_BURST_SERIAL,
+};
+
+/*!
+ * Enumeration of ADC display interface RW signal timing modes.
+ */
+enum {
+	IPU_ADC_SER_NO_RW,
+	IPU_ADC_SER_RW_BEFORE_RS,
+	IPU_ADC_SER_RW_AFTER_RS,
+};
+
+/*!
+ * Bitfield of ADC signal polarities and modes.
+ */
+typedef struct {
+	unsigned data_pol:1;
+	unsigned clk_pol:1;
+	unsigned cs_pol:1;
+	unsigned rs_pol:1;
+	unsigned addr_pol:1;
+	unsigned read_pol:1;
+	unsigned write_pol:1;
+	unsigned Vsync_pol:1;
+	unsigned burst_pol:1;
+	unsigned burst_mode:2;
+	unsigned ifc_mode:3;
+	unsigned ifc_width:5;
+	unsigned ser_preamble_len:4;
+	unsigned ser_preamble:8;
+	unsigned ser_rw_mode:2;
+} ipu_adc_sig_cfg_t;
+
+/*!
+ * Enumeration of ADC template commands.
+ */
+enum {
+	RD_DATA,
+	RD_ACK,
+	RD_WAIT,
+	WR_XADDR,
+	WR_YADDR,
+	WR_ADDR,
+	WR_CMND,
+	WR_DATA,
+};
+
+/*!
+ * Enumeration of ADC template command flow control.
+ */
+enum {
+	SINGLE_STEP,
+	PAUSE,
+	STOP,
+};
+
+
+/*Define template constants*/
+#define     ATM_ADDR_RANGE      0x20	/*offset address of DISP */
+#define     TEMPLATE_BUF_SIZE   0x20	/*size of template */
+
+/*!
+ * Define to create ADC template command entry.
+ */
+#define ipu_adc_template_gen(oc, rs, fc, dat) (((rs) << 29) | ((fc) << 27) | \
+			((oc) << 24) | (dat))
+
+typedef struct {
+	u32 reg;
+	u32 value;
+} ipu_lpmc_reg_t;
+
+#define IPU_LPMC_REG_READ       0x80000000L
+
+#define CSI_MCLK_VF  1
+#define CSI_MCLK_ENC 2
+#define CSI_MCLK_RAW 4
+#define CSI_MCLK_I2C 8
+
+struct ipu_soc;
+/* Common IPU API */
+struct ipu_soc *ipu_get_soc(int id);
+int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
+void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel);
+
+static inline bool ipu_can_rotate_in_place(ipu_rotate_mode_t rot)
+{
+#ifdef CONFIG_MXC_IPU_V3D
+	return (rot < IPU_ROTATE_HORIZ_FLIP);
+#else
+	return (rot < IPU_ROTATE_90_RIGHT);
+#endif
+}
+
+int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				dma_addr_t phyaddr_2,
+				uint32_t u_offset, uint32_t v_offset);
+
+int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+				  uint32_t bufNum, dma_addr_t phyaddr);
+
+int32_t ipu_update_channel_offset(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				uint32_t u, uint32_t v,
+				uint32_t vertical_offset, uint32_t horizontal_offset);
+
+int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+			  ipu_buffer_t type, uint32_t bufNum);
+int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum);
+
+int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
+int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch);
+
+int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel);
+int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum);
+void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum);
+uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type);
+int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel);
+int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop);
+int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch);
+
+int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi);
+int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi);
+
+int ipu_lowpwr_display_enable(void);
+int ipu_lowpwr_display_disable(void);
+
+void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq);
+void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq);
+void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq);
+int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
+		    irqreturn_t(*handler) (int, void *),
+		    uint32_t irq_flags, const char *devname, void *dev_id);
+void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id);
+bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq);
+void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
+
+/* two stripe calculations */
+struct stripe_param{
+	unsigned int input_width; /* width of the input stripe */
+	unsigned int output_width; /* width of the output stripe */
+	unsigned int input_column; /* the first column on the input stripe */
+	unsigned int output_column; /* the first column on the output stripe */
+	unsigned int idr;
+	/* inverse downisizing ratio parameter; expressed as a power of 2 */
+	unsigned int irr;
+	/* inverse resizing ratio parameter; expressed as a multiple of 2^-13 */
+};
+int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
+				unsigned int output_frame_width,
+				const unsigned int maximal_stripe_width,
+				const unsigned long long cirr,
+				const unsigned int equal_stripes,
+				u32 input_pixelformat,
+				u32 output_pixelformat,
+				struct stripe_param *left,
+				struct stripe_param *right);
+
+/* SDC API */
+int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp,
+			    uint32_t pixel_clk,
+			    uint16_t width, uint16_t height,
+			    uint32_t pixel_fmt,
+			    uint16_t h_start_width, uint16_t h_sync_width,
+			    uint16_t h_end_width, uint16_t v_start_width,
+			    uint16_t v_sync_width, uint16_t v_end_width,
+			    uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig);
+
+void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp);
+
+int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t x_pos,
+				int16_t y_pos);
+int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel, int16_t *x_pos,
+				int16_t *y_pos);
+int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
+				  uint8_t alpha);
+int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
+			       uint32_t colorKey);
+int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable,
+				int constk[], int slopek[]);
+
+int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
+			 uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig);
+void ipu_disp_direct_write(struct ipu_soc *ipu, ipu_channel_t channel, u32 value, u32 offset);
+void ipu_reset_disp_panel(struct ipu_soc *ipu);
+
+/* CMOS Sensor Interface API */
+int32_t ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
+			       uint32_t pixel_fmt, ipu_csi_signal_cfg_t sig);
+
+int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi);
+
+int32_t ipu_csi_enable_mclk(struct ipu_soc *ipu, int src, bool flag, bool wait);
+
+static inline int32_t ipu_csi_enable_mclk_if(struct ipu_soc *ipu, int src, uint32_t csi,
+		bool flag, bool wait)
+{
+	return ipu_csi_enable_mclk(ipu, csi, flag, wait);
+}
+
+int ipu_csi_read_mclk_flag(void);
+
+void ipu_csi_flash_strobe(bool flag);
+
+void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi);
+
+void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi);
+
+void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi);
+
+uint32_t bytes_per_pixel(uint32_t fmt);
+
+struct ipuv3_fb_platform_data {
+	char				disp_dev[32];
+	u32				interface_pix_fmt;
+	char				*mode_str;
+	int				default_bpp;
+	bool				int_clk;
+
+	/* reserved mem */
+	resource_size_t 		res_base;
+	resource_size_t 		res_size;
+};
+
+struct imx_ipuv3_platform_data {
+	int rev;
+	int (*init) (int);
+	void (*pg) (int);
+
+	char *csi_clk[2];
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/arch/arm/plat-mxc/include/mach/ipu.h b/arch/arm/plat-mxc/include/mach/ipu.h
index a9221f1..f7344ab 100644
--- a/arch/arm/plat-mxc/include/mach/ipu.h
+++ b/arch/arm/plat-mxc/include/mach/ipu.h
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/dmaengine.h>
+#include <linux/ipu.h>
 
 /* IPU DMA Controller channel definitions. */
 enum ipu_channel {
@@ -95,35 +96,10 @@
 	IPU_COLORSPACE_YUV
 };
 
-/*
- * Enumeration of IPU rotation modes
- */
-enum ipu_rotate_mode {
-	/* 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,
-};
-
 struct ipu_platform_data {
 	unsigned int	irq_base;
 };
 
-/*
- * Enumeration of DI ports for ADC.
- */
-enum display_port {
-	DISP0,
-	DISP1,
-	DISP2,
-	DISP3
-};
-
 struct idmac_video_param {
 	unsigned short		in_width;
 	unsigned short		in_height;
@@ -135,7 +111,7 @@
 	bool			graphics_combine_en;
 	bool			global_alpha_en;
 	bool			key_color_en;
-	enum display_port	disp;
+	display_port_t		disp;
 	unsigned short		out_left;
 	unsigned short		out_top;
 };
diff --git a/arch/arm/plat-mxc/include/mach/mx53.h b/arch/arm/plat-mxc/include/mach/mx53.h
index 2c43447..d815e4e 100644
--- a/arch/arm/plat-mxc/include/mach/mx53.h
+++ b/arch/arm/plat-mxc/include/mach/mx53.h
@@ -157,6 +157,18 @@
 #define MX53_IO_P2V(x)			IMX_IO_P2V(x)
 #define MX53_IO_ADDRESS(x)		IOMEM(MX53_IO_P2V(x))
 
+/* PGC */
+#define MX53_GPC_BASE		(MX53_IO_ADDRESS(MX53_GPC_BASE_ADDR))
+#define MX53_PGC_IPU_BASE	(MX53_GPC_BASE + 0x220)
+#define MX53_PGC_VPU_BASE	(MX53_GPC_BASE + 0x240)
+#define MX53_PGC_GPU_BASE	(MX53_GPC_BASE + 0x260)
+#define MX53_PGC_IPU_PGCR	(MX53_PGC_IPU_BASE + 0x0)
+#define MX53_PGC_IPU_PGSR	(MX53_PGC_IPU_BASE + 0xC)
+#define MX53_PGC_VPU_PGCR	(MX53_PGC_VPU_BASE + 0x0)
+#define MX53_PGC_VPU_PGSR	(MX53_PGC_VPU_BASE + 0xC)
+#define MX53_PGC_GPU_PGCR	(MX53_PGC_GPU_BASE + 0x0)
+#define MX53_PGC_GPU_PGSR	(MX53_PGC_GPU_BASE + 0xC)
+
 /*
  * defines for SPBA modules
  */
diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig
index 98b65af..2e5b7cf 100644
--- a/drivers/mxc/Kconfig
+++ b/drivers/mxc/Kconfig
@@ -4,6 +4,21 @@
 
 menu "MXC support drivers"
 
+config MXC_IPU
+	bool "Image Processing Unit Driver"
+	depends on !ARCH_MX21
+	depends on !ARCH_MX27
+	depends on !ARCH_MX25
+	select MXC_IPU_V1 if !ARCH_MX37 && !ARCH_MX5
+	select MXC_IPU_V3 if ARCH_MX37 || ARCH_MX5
+	select MXC_IPU_V3D if ARCH_MX37
+	select MXC_IPU_V3EX if ARCH_MX5
+	help
+	  If you plan to use the Image Processing unit, say
+	  Y here. IPU is needed by Framebuffer and V4L2 drivers.
+
+source "drivers/mxc/ipu3/Kconfig"
+
 endmenu
 
 endif
diff --git a/drivers/mxc/Makefile b/drivers/mxc/Makefile
index 40b08a2..1d87f1c 100644
--- a/drivers/mxc/Makefile
+++ b/drivers/mxc/Makefile
@@ -1,2 +1,3 @@
 # drivers/mxc/Makefile
+obj-$(CONFIG_MXC_IPU_V3)		+= ipu3/
 
diff --git a/drivers/mxc/ipu3/Kconfig b/drivers/mxc/ipu3/Kconfig
new file mode 100644
index 0000000..b1461ce
--- /dev/null
+++ b/drivers/mxc/ipu3/Kconfig
@@ -0,0 +1,11 @@
+config MXC_IPU_V3
+	bool
+
+config MXC_IPU_V3D
+	bool
+
+config MXC_IPU_V3EX
+	bool
+
+config MXC_IPU_V3H
+	bool
diff --git a/drivers/mxc/ipu3/Makefile b/drivers/mxc/ipu3/Makefile
new file mode 100644
index 0000000..8be2973
--- /dev/null
+++ b/drivers/mxc/ipu3/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_MXC_IPU_V3) = mxc_ipu.o
+
+mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o ipu_calc_stripes_sizes.o
diff --git a/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
new file mode 100644
index 0000000..c4e5b40
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_calc_stripes_sizes.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2009-2011 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
+ */
+
+/*
+ * @file ipu_calc_stripes_sizes.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/module.h>
+#include <linux/ipu.h>
+#include <mach/ipu-v3.h>
+#include <asm/div64.h>
+
+#define BPP_32 0
+#define BPP_16 3
+#define BPP_8 5
+#define BPP_24 1
+#define BPP_12 4
+#define BPP_18 2
+
+static u64 _do_div(u64 a, u32 b)
+{
+	u64 div;
+	div = a;
+	do_div(div, b);
+	return div;
+}
+
+static u32 truncate(u32 up, /* 0: down; else: up */
+					u64 a, /* must be non-negative */
+					u32 b)
+{
+	u32 d;
+	u64 div;
+	div = _do_div(a, b);
+	d = b * (div >> 32);
+	if (up && (a > (((u64)d) << 32)))
+		return d+b;
+	else
+		return d;
+}
+
+static unsigned int f_calc(unsigned int pfs, unsigned int bpp, unsigned int *write)
+{/* return input_f */
+	unsigned int f_calculated = 0;
+	switch (pfs) {
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+		f_calculated = 16;
+		break;
+
+	case IPU_PIX_FMT_NV12:
+		f_calculated = 8;
+		break;
+
+	default:
+		f_calculated = 0;
+		break;
+
+	}
+	if (!f_calculated) {
+		switch (bpp) {
+		case BPP_32:
+			f_calculated = 2;
+			break;
+
+		case BPP_16:
+			f_calculated = 4;
+			break;
+
+		case BPP_8:
+		case BPP_24:
+			f_calculated = 8;
+			break;
+
+		case BPP_12:
+			f_calculated = 16;
+			break;
+
+		case BPP_18:
+			f_calculated = 32;
+			break;
+
+		default:
+			f_calculated = 0;
+			break;
+			}
+		}
+	return f_calculated;
+}
+
+
+static unsigned int m_calc(unsigned int pfs)
+{
+	unsigned int m_calculated = 0;
+	switch (pfs) {
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_NV12:
+		m_calculated = 8;
+		break;
+
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		m_calculated = 2;
+		break;
+
+	default:
+		m_calculated = 1;
+		break;
+
+	}
+	return m_calculated;
+}
+
+
+/* Stripe parameters calculator */
+/**************************************************************************
+Notes:
+MSW = the maximal width allowed for a stripe
+	i.MX31: 720, i.MX35: 800, i.MX37/51/53: 1024
+cirr = the maximal inverse resizing ratio for which overlap in the input
+	is requested; typically cirr~2
+equal_stripes:
+	0: each stripe is allowed to have independent parameters
+		for maximal image quality
+	1: the stripes are requested to have identical parameters
+	(except the base address), for maximal performance
+If performance is the top priority (above image quality)
+	Avoid overlap, by setting CIRR = 0
+		This will also force effectively identical_stripes = 1
+	Choose IF & OF that corresponds to the same IOX/SX for both stripes
+	Choose IFW & OFW such that
+	IFW/IM, IFW/IF, OFW/OM, OFW/OF are even integers
+	The function returns an error status:
+	0: no error
+	1: invalid input parameters -> aborted without result
+		Valid parameters should satisfy the following conditions
+		IFW <= OFW, otherwise downsizing is required
+					 - which is not supported yet
+		4 <= IFW,OFW, so some interpolation may be needed even without overlap
+		IM, OM, IF, OF should not vanish
+		2*IF <= IFW
+		so the frame can be split to two equal stripes, even without overlap
+		2*(OF+IF/irr_opt) <= OFW
+		so a valid positive INW exists even for equal stripes
+		OF <= MSW, otherwise, the left stripe cannot be sufficiently large
+		MSW < OFW, so splitting to stripes is required
+		OFW <= 2*MSW, so two stripes are sufficient
+		(this also implies that 2<=MSW)
+	2: OF is not a multiple of OM - not fully-supported yet
+	Output is produced but OW is not guaranited to be a multiple of OM
+	4: OFW reduced to be a multiple of OM
+	8: CIRR > 1: truncated to 1
+	Overlap is not supported (and not needed) y for upsizing)
+**************************************************************************/
+int ipu_calc_stripes_sizes(const unsigned int input_frame_width,
+			   /* input frame width;>1 */
+			   unsigned int output_frame_width, /* output frame width; >1 */
+			   const unsigned int maximal_stripe_width,
+			   /* the maximal width allowed for a stripe */
+			   const unsigned long long cirr, /* see above */
+			   const unsigned int equal_stripes, /* see above */
+			   u32 input_pixelformat,/* pixel format after of read channel*/
+			   u32 output_pixelformat,/* pixel format after of write channel*/
+			   struct stripe_param *left,
+			   struct stripe_param *right)
+{
+	const unsigned int irr_frac_bits = 13;
+	const unsigned long irr_steps = 1 << irr_frac_bits;
+	const u64 dirr = ((u64)1) << (32 - 2);
+	/* The maximum relative difference allowed between the irrs */
+	const u64 cr = ((u64)4) << 32;
+	/* The importance ratio between the two terms in the cost function below */
+
+	unsigned int status;
+	unsigned int temp;
+	unsigned int onw_min;
+	unsigned int inw, onw, inw_best = 0;
+	/* number of pixels in the left stripe NOT hidden by the right stripe */
+	u64 irr_opt; /* the optimal inverse resizing ratio */
+	u64 rr_opt; /* the optimal resizing ratio = 1/irr_opt*/
+	u64 dinw; /* the misalignment between the stripes */
+	/* (measured in units of input columns) */
+	u64 difwl, difwr;
+	/* The number of input columns not reflected in the output */
+	/* the resizing ratio used for the right stripe is */
+	/*   left->irr and right->irr respectively */
+	u64 cost, cost_min;
+	u64 div; /* result of division */
+
+	unsigned int input_m, input_f, output_m, output_f; /* parameters for upsizing by stripes */
+
+	status = 0;
+
+	/* M, F calculations */
+	/* read back pfs from params */
+
+	input_f = 16;
+	input_m = 16;
+	/* BPP should be used in the out_F calc */
+	/* Temporarily not used */
+	/* out_F = F_calc(idmac->pfs, idmac->bpp, NULL); */
+
+	output_f = 16;
+	output_m = 16;
+
+
+	if ((input_frame_width < 4) || (output_frame_width < 4))
+		return 1;
+
+	irr_opt = _do_div((((u64)(input_frame_width - 1)) << 32),
+			  (output_frame_width - 1));
+	rr_opt = _do_div((((u64)(output_frame_width - 1)) << 32),
+			 (input_frame_width - 1));
+
+	if ((input_m == 0) || (output_m == 0) || (input_f == 0) || (output_f == 0)
+	    || (input_frame_width < (2 * input_f))
+	    || ((((u64)output_frame_width) << 32) <
+		(2 * ((((u64)output_f) << 32) + (input_f * rr_opt))))
+	    || (maximal_stripe_width < output_f)
+	    || (output_frame_width <= maximal_stripe_width)
+	    || ((2 * maximal_stripe_width) < output_frame_width))
+		return 1;
+
+	if (output_f % output_m)
+		status += 2;
+
+	temp = truncate(0, (((u64)output_frame_width) << 32), output_m);
+	if (temp < output_frame_width) {
+		output_frame_width = temp;
+		status += 4;
+	}
+
+	if (equal_stripes) {
+		if ((irr_opt > cirr) /* overlap in the input is not requested */
+		    && ((input_frame_width % (input_m << 1)) == 0)
+		    && ((input_frame_width % (input_f << 1)) == 0)
+		    && ((output_frame_width % (output_m << 1)) == 0)
+		    && ((output_frame_width % (output_f << 1)) == 0)) {
+			/* without overlap */
+			left->input_width = right->input_width = right->input_column =
+				input_frame_width >> 1;
+			left->output_width = right->output_width = right->output_column =
+				output_frame_width >> 1;
+			left->input_column = 0;
+			left->output_column = 0;
+			div = _do_div(((((u64)irr_steps) << 32) *
+				       (right->input_width - 1)), (right->output_width - 1));
+			left->irr = right->irr = truncate(0, div, 1);
+		} else { /* with overlap */
+			onw = truncate(0, (((u64)output_frame_width - 1) << 32) >> 1,
+				       output_f);
+			inw = truncate(0, onw * irr_opt, input_f);
+			/* this is the maximal inw which allows the same resizing ratio */
+			/* in both stripes */
+			onw = truncate(1, (inw * rr_opt), output_f);
+			div = _do_div((((u64)(irr_steps * inw)) <<
+				       32), onw);
+			left->irr = right->irr = truncate(0, div, 1);
+			left->output_width = right->output_width =
+				output_frame_width - onw;
+			/* These are valid assignments for output_width, */
+			/* assuming output_f is a multiple of output_m */
+			div = (((u64)(left->output_width-1) * (left->irr)) << 32);
+			div = (((u64)1) << 32) + _do_div(div, irr_steps);
+
+			left->input_width = right->input_width = truncate(1, div, input_m);
+
+			div = _do_div((((u64)((right->output_width - 1) * right->irr)) <<
+				       32), irr_steps);
+			difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+			div = _do_div((difwr + (((u64)input_f) << 32)), 2);
+			left->input_column = truncate(0, div, input_f);
+
+
+			/* This splits the truncated input columns evenly */
+			/*    between the left and right margins */
+			right->input_column = left->input_column + inw;
+			left->output_column = 0;
+			right->output_column = onw;
+		}
+	} else { /* independent stripes */
+		onw_min = output_frame_width - maximal_stripe_width;
+		/* onw is a multiple of output_f, in the range */
+		/* [max(output_f,output_frame_width-maximal_stripe_width),*/
+		/*min(output_frame_width-2,maximal_stripe_width)] */
+		/* definitely beyond the cost of any valid setting */
+		cost_min = (((u64)input_frame_width) << 32) + cr;
+		onw = truncate(0, ((u64)maximal_stripe_width), output_f);
+		if (output_frame_width - onw == 1)
+			onw -= output_f; /*  => onw and output_frame_width-1-onw are positive */
+		inw = truncate(0, onw * irr_opt, input_f);
+		/* this is the maximal inw which allows the same resizing ratio */
+		/* in both stripes */
+		onw = truncate(1, inw * rr_opt, output_f);
+		do {
+			div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
+			left->irr = truncate(0, div, 1);
+			div = _do_div((((u64)(onw * left->irr)) << 32),
+				      irr_steps);
+			dinw = (((u64)inw) << 32) - div;
+
+			div = _do_div((((u64)((output_frame_width - 1 - onw) * left->irr)) <<
+				       32), irr_steps);
+
+			difwl = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+
+			cost = difwl + (((u64)(cr * dinw)) >> 32);
+
+			if (cost < cost_min) {
+				inw_best = inw;
+				cost_min = cost;
+			}
+
+			inw -= input_f;
+			onw = truncate(1, inw * rr_opt, output_f);
+			/* This is the minimal onw which allows the same resizing ratio */
+			/*     in both stripes */
+		} while (onw >= onw_min);
+
+		inw = inw_best;
+		onw = truncate(1, inw * rr_opt, output_f);
+		div = _do_div((((u64)(irr_steps * inw)) << 32), onw);
+		left->irr = truncate(0, div, 1);
+
+		left->output_width = onw;
+		right->output_width = output_frame_width - onw;
+		/* These are valid assignments for output_width, */
+		/* assuming output_f is a multiple of output_m */
+		left->input_width = truncate(1, ((u64)(inw + 1)) << 32, input_m);
+		right->input_width = truncate(1, ((u64)(input_frame_width - inw)) <<
+					      32, input_m);
+
+		div = _do_div((((u64)(irr_steps * (input_frame_width - 1 - inw))) <<
+			       32), (right->output_width - 1));
+		right->irr = truncate(0, div, 1);
+		temp = truncate(0, ((u64)left->irr) * ((((u64)1) << 32) + dirr), 1);
+		if (temp < right->irr)
+			right->irr = temp;
+		div = _do_div(((u64)((right->output_width - 1) * right->irr) <<
+			       32), irr_steps);
+		difwr = (u64)(input_frame_width - 1 - inw) - div;
+
+
+		div = _do_div((difwr + (((u64)input_f) << 32)), 2);
+		left->input_column = truncate(0, div, input_f);
+
+		/* This splits the truncated input columns evenly */
+		/*    between the left and right margins */
+		right->input_column = left->input_column + inw;
+		left->output_column = 0;
+		right->output_column = onw;
+	}
+
+	return status;
+}
+EXPORT_SYMBOL(ipu_calc_stripes_sizes);
diff --git a/drivers/mxc/ipu3/ipu_capture.c b/drivers/mxc/ipu3/ipu_capture.c
new file mode 100644
index 0000000..26b8b15
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_capture.c
@@ -0,0 +1,751 @@
+/*
+ * Copyright 2008-2011 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
+ */
+
+/*!
+ * @file ipu_capture.c
+ *
+ * @brief IPU capture dase functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/ipu.h>
+#include <linux/clk.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+/*!
+ * ipu_csi_init_interface
+ *	Sets initial values for the CSI registers.
+ *	The width and height of the sensor and the actual frame size will be
+ *	set to the same values.
+ * @param	ipu		ipu handler
+ * @param	width		Sensor width
+ * @param       height		Sensor height
+ * @param       pixel_fmt	pixel format
+ * @param       cfg_param	ipu_csi_signal_cfg_t structure
+ * @param       csi             csi 0 or csi 1
+ *
+ * @return      0 for success, -EINVAL for error
+ */
+int32_t
+ipu_csi_init_interface(struct ipu_soc *ipu, uint16_t width, uint16_t height,
+	uint32_t pixel_fmt, ipu_csi_signal_cfg_t cfg_param)
+{
+	uint32_t data = 0;
+	uint32_t csi = cfg_param.csi;
+	unsigned long lock_flags;
+
+	/* Set SENS_DATA_FORMAT bits (8, 9 and 10)
+	   RGB or YUV444 is 0 which is current value in data so not set
+	   explicitly
+	   This is also the default value if attempts are made to set it to
+	   something invalid. */
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_YUYV:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
+		break;
+	case IPU_PIX_FMT_UYVY:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
+		break;
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGR24:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB_YUV444;
+		break;
+	case IPU_PIX_FMT_GENERIC:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
+		break;
+	case IPU_PIX_FMT_RGB565:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
+		break;
+	case IPU_PIX_FMT_RGB555:
+		cfg_param.data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* Set the CSI_SENS_CONF register remaining fields */
+	data |= cfg_param.data_width << CSI_SENS_CONF_DATA_WIDTH_SHIFT |
+		cfg_param.data_fmt << CSI_SENS_CONF_DATA_FMT_SHIFT |
+		cfg_param.data_pol << CSI_SENS_CONF_DATA_POL_SHIFT |
+		cfg_param.Vsync_pol << CSI_SENS_CONF_VSYNC_POL_SHIFT |
+		cfg_param.Hsync_pol << CSI_SENS_CONF_HSYNC_POL_SHIFT |
+		cfg_param.pixclk_pol << CSI_SENS_CONF_PIX_CLK_POL_SHIFT |
+		cfg_param.ext_vsync << CSI_SENS_CONF_EXT_VSYNC_SHIFT |
+		cfg_param.clk_mode << CSI_SENS_CONF_SENS_PRTCL_SHIFT |
+		cfg_param.pack_tight << CSI_SENS_CONF_PACK_TIGHT_SHIFT |
+		cfg_param.force_eof << CSI_SENS_CONF_FORCE_EOF_SHIFT |
+		cfg_param.data_en_pol << CSI_SENS_CONF_DATA_EN_POL_SHIFT;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
+
+	/* Setup sensor frame size */
+	ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_SENS_FRM_SIZE);
+
+	/* Set CCIR registers */
+	if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_PROGRESSIVE) {
+		ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+	} else if (cfg_param.clk_mode == IPU_CSI_CLK_MODE_CCIR656_INTERLACED) {
+		if (width == 720 && height == 625) {
+			/* PAL case */
+			/*
+			 * Field0BlankEnd = 0x6, Field0BlankStart = 0x2,
+			 * Field0ActiveEnd = 0x4, Field0ActiveStart = 0
+			 */
+			ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
+			/*
+			 * Field1BlankEnd = 0x7, Field1BlankStart = 0x3,
+			 * Field1ActiveEnd = 0x5, Field1ActiveStart = 0x1
+			 */
+			ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_2);
+			ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+		} else if (width == 720 && height == 525) {
+			/* NTSC case */
+			/*
+			 * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+			 * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+			 */
+			ipu_csi_write(ipu, csi, 0xD07DF, CSI_CCIR_CODE_1);
+			/*
+			 * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+			 * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+			 */
+			ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_2);
+			ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+		} else {
+			dev_err(ipu->dev, "Unsupported CCIR656 interlaced "
+					"video mode\n");
+			_ipu_unlock(ipu, &lock_flags);
+			_ipu_put(ipu);
+			return -EINVAL;
+		}
+		_ipu_csi_ccir_err_detection_enable(ipu, csi);
+	} else if ((cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_DDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_PROGRESSIVE_SDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_DDR) ||
+		(cfg_param.clk_mode ==
+			IPU_CSI_CLK_MODE_CCIR1120_INTERLACED_SDR)) {
+		ipu_csi_write(ipu, csi, 0x40030, CSI_CCIR_CODE_1);
+		ipu_csi_write(ipu, csi, 0xFF0000, CSI_CCIR_CODE_3);
+		_ipu_csi_ccir_err_detection_enable(ipu, csi);
+	} else if ((cfg_param.clk_mode == IPU_CSI_CLK_MODE_GATED_CLK) ||
+		   (cfg_param.clk_mode == IPU_CSI_CLK_MODE_NONGATED_CLK)) {
+		_ipu_csi_ccir_err_detection_disable(ipu, csi);
+	}
+
+	dev_dbg(ipu->dev, "CSI_SENS_CONF = 0x%08X\n",
+		ipu_csi_read(ipu, csi, CSI_SENS_CONF));
+	dev_dbg(ipu->dev, "CSI_ACT_FRM_SIZE = 0x%08X\n",
+		ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE));
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_csi_init_interface);
+
+/*!
+ * ipu_csi_get_sensor_protocol
+ *
+ * @param	ipu		ipu handler
+ * @param	csi         csi 0 or csi 1
+ *
+ * @return	Returns sensor protocol
+ */
+int32_t ipu_csi_get_sensor_protocol(struct ipu_soc *ipu, uint32_t csi)
+{
+	return (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
+		CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+		CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+}
+EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
+
+/*!
+ * _ipu_csi_mclk_set
+ *
+ * @param	ipu		ipu handler
+ * @param	pixel_clk   desired pixel clock frequency in Hz
+ * @param	csi         csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_mclk_set(struct ipu_soc *ipu, uint32_t pixel_clk, uint32_t csi)
+{
+	uint32_t temp;
+	uint32_t div_ratio;
+
+	div_ratio = (clk_get_rate(ipu->ipu_clk) / pixel_clk) - 1;
+
+	if (div_ratio > 0xFF || div_ratio < 0) {
+		dev_dbg(ipu->dev, "The value of pixel_clk extends normal range\n");
+		return -EINVAL;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+	temp &= ~CSI_SENS_CONF_DIVRATIO_MASK;
+	ipu_csi_write(ipu, csi, temp | (div_ratio << CSI_SENS_CONF_DIVRATIO_SHIFT),
+			CSI_SENS_CONF);
+
+	return 0;
+}
+
+/*!
+ * ipu_csi_enable_mclk
+ *
+ * @param	ipu		ipu handler
+ * @param	csi         csi 0 or csi 1
+ * @param       flag        true to enable mclk, false to disable mclk
+ * @param       wait        true to wait 100ms make clock stable, false not wait
+ *
+ * @return      Returns 0 on success
+ */
+int ipu_csi_enable_mclk(struct ipu_soc *ipu, int csi, bool flag, bool wait)
+{
+	if (flag) {
+		clk_enable(ipu->csi_clk[csi]);
+		if (wait == true)
+			msleep(10);
+	} else {
+		clk_disable(ipu->csi_clk[csi]);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_csi_enable_mclk);
+
+/*!
+ * ipu_csi_get_window_size
+ *
+ * @param	ipu		ipu handler
+ * @param	width	pointer to window width
+ * @param	height	pointer to window height
+ * @param	csi	csi 0 or csi 1
+ */
+void ipu_csi_get_window_size(struct ipu_soc *ipu, uint32_t *width, uint32_t *height, uint32_t csi)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
+	*width = (reg & 0xFFFF) + 1;
+	*height = (reg >> 16 & 0xFFFF) + 1;
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_get_window_size);
+
+/*!
+ * ipu_csi_set_window_size
+ *
+ * @param	ipu		ipu handler
+ * @param	width	window width
+ * @param       height	window height
+ * @param       csi	csi 0 or csi 1
+ */
+void ipu_csi_set_window_size(struct ipu_soc *ipu, uint32_t width, uint32_t height, uint32_t csi)
+{
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_size);
+
+/*!
+ * ipu_csi_set_window_pos
+ *
+ * @param	ipu		ipu handler
+ * @param       left	uint32 window x start
+ * @param       top	uint32 window y start
+ * @param       csi	csi 0 or csi 1
+ */
+void ipu_csi_set_window_pos(struct ipu_soc *ipu, uint32_t left, uint32_t top, uint32_t csi)
+{
+	uint32_t temp;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~(CSI_HSC_MASK | CSI_VSC_MASK);
+	temp |= ((top << CSI_VSC_SHIFT) | (left << CSI_HSC_SHIFT));
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_csi_set_window_pos);
+
+/*!
+ * _ipu_csi_horizontal_downsize_enable
+ *	Enable horizontal downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_horizontal_downsize_disable
+ *	Disable horizontal downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_horizontal_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_HORI_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_enable
+ *	Enable vertical downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp |= CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_vertical_downsize_disable
+ *	Disable vertical downsizing(decimation) by 2.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_vertical_downsize_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_OUT_FRM_CTRL);
+	temp &= ~CSI_VERT_DOWNSIZE_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_OUT_FRM_CTRL);
+}
+
+/*!
+ * _ipu_csi_set_test_generator
+ *
+ * @param	ipu		ipu handler
+ * @param	active       1 for active and 0 for inactive
+ * @param       r_value	     red value for the generated pattern of even pixel
+ * @param       g_value      green value for the generated pattern of even
+ *			     pixel
+ * @param       b_value      blue value for the generated pattern of even pixel
+ * @param	pixel_clk   desired pixel clock frequency in Hz
+ * @param       csi          csi 0 or csi 1
+ */
+void _ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+	uint32_t g_value, uint32_t b_value, uint32_t pix_clk, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_TST_CTRL);
+
+	if (active == false) {
+		temp &= ~CSI_TEST_GEN_MODE_EN;
+		ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+	} else {
+		/* Set sensb_mclk div_ratio*/
+		_ipu_csi_mclk_set(ipu, pix_clk, csi);
+
+		temp &= ~(CSI_TEST_GEN_R_MASK | CSI_TEST_GEN_G_MASK |
+			CSI_TEST_GEN_B_MASK);
+		temp |= CSI_TEST_GEN_MODE_EN;
+		temp |= (r_value << CSI_TEST_GEN_R_SHIFT) |
+			(g_value << CSI_TEST_GEN_G_SHIFT) |
+			(b_value << CSI_TEST_GEN_B_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_TST_CTRL);
+	}
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_en
+ *	Enable error detection and correction for
+ *	CCIR interlaced mode with protection bit.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+	temp |= CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_ccir_err_detection_disable
+ *	Disable error detection and correction for
+ *	CCIR interlaced mode with protection bit.
+ *
+ * @param	ipu		ipu handler
+ * @param	csi	csi 0 or csi 1
+ */
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_csi_read(ipu, csi, CSI_CCIR_CODE_1);
+	temp &= ~CSI_CCIR_ERR_DET_EN;
+	ipu_csi_write(ipu, csi, temp, CSI_CCIR_CODE_1);
+
+}
+
+/*!
+ * _ipu_csi_set_mipi_di
+ *
+ * @param	ipu		ipu handler
+ * @param	num	MIPI data identifier 0-3 handled by CSI
+ * @param	di_val	data identifier value
+ * @param	csi	csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (di_val > 0xFFL) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_MIPI_DI);
+
+	switch (num) {
+	case IPU_CSI_MIPI_DI0:
+		temp &= ~CSI_MIPI_DI0_MASK;
+		temp |= (di_val << CSI_MIPI_DI0_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI1:
+		temp &= ~CSI_MIPI_DI1_MASK;
+		temp |= (di_val << CSI_MIPI_DI1_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI2:
+		temp &= ~CSI_MIPI_DI2_MASK;
+		temp |= (di_val << CSI_MIPI_DI2_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	case IPU_CSI_MIPI_DI3:
+		temp &= ~CSI_MIPI_DI3_MASK;
+		temp |= (di_val << CSI_MIPI_DI3_SHIFT);
+		ipu_csi_write(ipu, csi, temp, CSI_MIPI_DI);
+		break;
+	default:
+		retval = -EINVAL;
+	}
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_isp
+ *
+ * @param	ipu		ipu handler
+ * @param	skip		select frames to be skipped and set the
+ *				correspond bits to 1
+ * @param	max_ratio	number of frames in a skipping set and the
+ * 				maximum value of max_ratio is 5
+ * @param	csi		csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_isp(struct ipu_soc *ipu, uint32_t skip, uint32_t max_ratio, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (max_ratio > 5) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_ISP_MASK | CSI_SKIP_ISP_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_ISP_SHIFT) |
+		(skip << CSI_SKIP_ISP_SHIFT);
+	ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_csi_set_skip_smfc
+ *
+ * @param	ipu		ipu handler
+ * @param	skip		select frames to be skipped and set the
+ *				correspond bits to 1
+ * @param	max_ratio	number of frames in a skipping set and the
+ *				maximum value of max_ratio is 5
+ * @param	id		csi to smfc skipping id
+ * @param	csi		csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_set_skip_smfc(struct ipu_soc *ipu, uint32_t skip,
+	uint32_t max_ratio, uint32_t id, uint32_t csi)
+{
+	uint32_t temp;
+	int retval = 0;
+
+	if (max_ratio > 5 || id > 3) {
+		retval = -EINVAL;
+		goto err;
+	}
+
+	temp = ipu_csi_read(ipu, csi, CSI_SKIP);
+	temp &= ~(CSI_MAX_RATIO_SKIP_SMFC_MASK | CSI_ID_2_SKIP_MASK |
+			CSI_SKIP_SMFC_MASK);
+	temp |= (max_ratio << CSI_MAX_RATIO_SKIP_SMFC_SHIFT) |
+			(id << CSI_ID_2_SKIP_SHIFT) |
+			(skip << CSI_SKIP_SMFC_SHIFT);
+	ipu_csi_write(ipu, csi, temp, CSI_SKIP);
+
+err:
+	return retval;
+}
+
+/*!
+ * _ipu_smfc_init
+ *	Map CSI frames to IDMAC channels.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	mipi_id		mipi id number 0-3
+ * @param	csi		csi0 or csi1
+ */
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_MAP);
+
+	switch (channel) {
+	case CSI_MEM0:
+		temp &= ~SMFC_MAP_CH0_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH0_SHIFT;
+		break;
+	case CSI_MEM1:
+		temp &= ~SMFC_MAP_CH1_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH1_SHIFT;
+		break;
+	case CSI_MEM2:
+		temp &= ~SMFC_MAP_CH2_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH2_SHIFT;
+		break;
+	case CSI_MEM3:
+		temp &= ~SMFC_MAP_CH3_MASK;
+		temp |= ((csi << 2) | mipi_id) << SMFC_MAP_CH3_SHIFT;
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_MAP);
+}
+
+/*!
+ * _ipu_smfc_set_wmc
+ *	Caution: The number of required channels,  the enabled channels
+ *	and the FIFO size per channel are configured restrictedly.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	set		set 1 or clear 0
+ * @param	level		water mark level when FIFO is on the
+ *				relative size
+ */
+void _ipu_smfc_set_wmc(struct ipu_soc *ipu, ipu_channel_t channel, bool set, uint32_t level)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_WMC);
+
+	switch (channel) {
+	case CSI_MEM0:
+		if (set == true) {
+			temp &= ~SMFC_WM0_SET_MASK;
+			temp |= level << SMFC_WM0_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM0_CLR_MASK;
+			temp |= level << SMFC_WM0_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM1:
+		if (set == true) {
+			temp &= ~SMFC_WM1_SET_MASK;
+			temp |= level << SMFC_WM1_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM1_CLR_MASK;
+			temp |= level << SMFC_WM1_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM2:
+		if (set == true) {
+			temp &= ~SMFC_WM2_SET_MASK;
+			temp |= level << SMFC_WM2_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM2_CLR_MASK;
+			temp |= level << SMFC_WM2_CLR_SHIFT;
+		}
+		break;
+	case CSI_MEM3:
+		if (set == true) {
+			temp &= ~SMFC_WM3_SET_MASK;
+			temp |= level << SMFC_WM3_SET_SHIFT;
+		} else {
+			temp &= ~SMFC_WM3_CLR_MASK;
+			temp |= level << SMFC_WM3_CLR_SHIFT;
+		}
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_WMC);
+}
+
+/*!
+ * _ipu_smfc_set_burst_size
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IDMAC channel 0-3
+ * @param	bs		burst size of IDMAC channel,
+ *				the value programmed here shoud be BURST_SIZE-1
+ */
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs)
+{
+	uint32_t temp;
+
+	temp = ipu_smfc_read(ipu, SMFC_BS);
+
+	switch (channel) {
+	case CSI_MEM0:
+		temp &= ~SMFC_BS0_MASK;
+		temp |= bs << SMFC_BS0_SHIFT;
+		break;
+	case CSI_MEM1:
+		temp &= ~SMFC_BS1_MASK;
+		temp |= bs << SMFC_BS1_SHIFT;
+		break;
+	case CSI_MEM2:
+		temp &= ~SMFC_BS2_MASK;
+		temp |= bs << SMFC_BS2_SHIFT;
+		break;
+	case CSI_MEM3:
+		temp &= ~SMFC_BS3_MASK;
+		temp |= bs << SMFC_BS3_SHIFT;
+		break;
+	default:
+		return;
+	}
+
+	ipu_smfc_write(ipu, temp, SMFC_BS);
+}
+
+/*!
+ * _ipu_csi_init
+ *
+ * @param	ipu		ipu handler
+ * @param	channel      IDMAC channel
+ * @param	csi	     csi 0 or csi 1
+ *
+ * @return	Returns 0 on success or negative error code on fail
+ */
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi)
+{
+	uint32_t csi_sens_conf, csi_dest;
+	int retval = 0;
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		csi_dest = CSI_DATA_DEST_IDMAC;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case CSI_PRP_VF_MEM:
+		csi_dest = CSI_DATA_DEST_IC;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	csi_sens_conf = ipu_csi_read(ipu, csi, CSI_SENS_CONF);
+	csi_sens_conf &= ~CSI_SENS_CONF_DATA_DEST_MASK;
+	ipu_csi_write(ipu, csi, csi_sens_conf | (csi_dest <<
+		CSI_SENS_CONF_DATA_DEST_SHIFT), CSI_SENS_CONF);
+err:
+	return retval;
+}
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
new file mode 100644
index 0000000..fb06f56
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -0,0 +1,2760 @@
+/*
+ * Copyright 2005-2011 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
+ */
+
+/*!
+ * @file ipu_common.c
+ *
+ * @brief This file contains the IPU driver common API functions.
+ *
+ * @ingroup IPU
+ */
+#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/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/ipu.h>
+#include <linux/clk.h>
+#include <mach/clock.h>
+#include <mach/hardware.h>
+#include <mach/devices-common.h>
+#include <asm/cacheflush.h>
+#include <linux/delay.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+#include "ipu_param_mem.h"
+
+static struct ipu_soc ipu_array[MXC_IPU_MAX_NUM];
+int g_ipu_hw_rev;
+
+/* Static functions */
+static irqreturn_t ipu_irq_handler(int irq, void *desc);
+
+static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
+{
+	return ((uint32_t) ch >> (6 * type)) & 0x3F;
+};
+
+static inline int _ipu_is_ic_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 11) && (dma_chan <= 22) && (dma_chan != 17) && (dma_chan != 18));
+}
+
+static inline int _ipu_is_ic_graphic_chan(uint32_t dma_chan)
+{
+	return (dma_chan == 14 || dma_chan == 15);
+}
+
+/* Either DP BG or DP FG can be graphic window */
+static inline int _ipu_is_dp_graphic_chan(uint32_t dma_chan)
+{
+	return (dma_chan == 23 || dma_chan == 27);
+}
+
+static inline int _ipu_is_irt_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 45) && (dma_chan <= 50));
+}
+
+static inline int _ipu_is_dmfc_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 23) && (dma_chan <= 29));
+}
+
+static inline int _ipu_is_smfc_chan(uint32_t dma_chan)
+{
+	return ((dma_chan >= 0) && (dma_chan <= 3));
+}
+
+static inline int _ipu_is_trb_chan(uint32_t dma_chan)
+{
+	return (((dma_chan == 8) || (dma_chan == 9) ||
+		 (dma_chan == 10) || (dma_chan == 13) ||
+		 (dma_chan == 21) || (dma_chan == 23) ||
+		 (dma_chan == 27) || (dma_chan == 28)) &&
+		(g_ipu_hw_rev >= 2));
+}
+
+#define idma_is_valid(ch)	(ch != NO_DMA)
+#define idma_mask(ch)		(idma_is_valid(ch) ? (1UL << (ch & 0x1F)) : 0)
+#define idma_is_set(ipu, reg, dma)	(ipu_idmac_read(ipu, reg(dma)) & idma_mask(dma))
+#define tri_cur_buf_mask(ch)	(idma_mask(ch*2) * 3)
+#define tri_cur_buf_shift(ch)	(ffs(idma_mask(ch*2)) - 1)
+
+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 __devinit ipu_clk_setup_enable(struct ipu_soc *ipu,
+		struct platform_device *pdev)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	char ipu_clk[] = "ipu1_clk";
+	char di0_clk[] = "ipu1_di0_clk";
+	char di1_clk[] = "ipu1_di1_clk";
+
+	ipu_clk[3] += pdev->id;
+	di0_clk[3] += pdev->id;
+	di1_clk[3] += pdev->id;
+
+	ipu->ipu_clk = clk_get(ipu->dev, ipu_clk);
+	if (IS_ERR(ipu->ipu_clk)) {
+		dev_err(ipu->dev, "clk_get failed");
+		return PTR_ERR(ipu->ipu_clk);
+	}
+	dev_dbg(ipu->dev, "ipu_clk = %lu\n", clk_get_rate(ipu->ipu_clk));
+
+	ipu->pixel_clk[0] = ipu_pixel_clk[0];
+	ipu->pixel_clk[1] = ipu_pixel_clk[1];
+
+	ipu_lookups[0].clk = &ipu->pixel_clk[0];
+	ipu_lookups[1].clk = &ipu->pixel_clk[1];
+	clkdev_add(&ipu_lookups[0]);
+	clkdev_add(&ipu_lookups[1]);
+
+	clk_debug_register(&ipu->pixel_clk[0]);
+	clk_debug_register(&ipu->pixel_clk[1]);
+
+	clk_enable(ipu->ipu_clk);
+
+	clk_set_parent(&ipu->pixel_clk[0], ipu->ipu_clk);
+	clk_set_parent(&ipu->pixel_clk[1], ipu->ipu_clk);
+
+	ipu->di_clk[0] = clk_get(ipu->dev, di0_clk);
+	ipu->di_clk[1] = clk_get(ipu->dev, di1_clk);
+
+	ipu->csi_clk[0] = clk_get(ipu->dev, plat_data->csi_clk[0]);
+	ipu->csi_clk[1] = clk_get(ipu->dev, plat_data->csi_clk[1]);
+
+	return 0;
+}
+
+struct ipu_soc *ipu_get_soc(int id)
+{
+	if (id >= MXC_IPU_MAX_NUM)
+		return ERR_PTR(-ENODEV);
+	else
+		return &(ipu_array[id]);
+}
+EXPORT_SYMBOL_GPL(ipu_get_soc);
+
+void _ipu_lock(struct ipu_soc *ipu, unsigned long *flags)
+{
+	spin_lock_irqsave(&ipu->spin_lock, *flags);
+}
+
+void _ipu_unlock(struct ipu_soc *ipu, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ipu->spin_lock, *flags);
+}
+
+void _ipu_get(struct ipu_soc *ipu)
+{
+	if (ipu->ipu_use_count++ == 0)
+		clk_enable(ipu->ipu_clk);
+}
+
+void _ipu_put(struct ipu_soc *ipu)
+{
+	if (--ipu->ipu_use_count == 0)
+		clk_disable(ipu->ipu_clk);
+}
+
+/*!
+ * This function is called by the driver framework to initialize the IPU
+ * hardware.
+ *
+ * @param	dev	The device structure for the IPU passed in by the
+ *			driver framework.
+ *
+ * @return      Returns 0 on success or negative error code on error
+ */
+static int __devinit ipu_probe(struct platform_device *pdev)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipu_soc *ipu;
+	struct resource *res;
+	unsigned long ipu_base;
+	int ret = 0;
+
+	if (pdev->id >= MXC_IPU_MAX_NUM)
+		return -ENODEV;
+
+	ipu = &ipu_array[pdev->id];
+	memset(ipu, 0, sizeof(struct ipu_soc));
+
+	spin_lock_init(&ipu->spin_lock);
+	mutex_init(&ipu->mutex_lock);
+
+	g_ipu_hw_rev = plat_data->rev;
+
+	ipu->dev = &pdev->dev;
+
+	if (plat_data->init)
+		plat_data->init(pdev->id);
+
+	ipu->irq_sync = platform_get_irq(pdev, 0);
+	ipu->irq_err = platform_get_irq(pdev, 1);
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!res || ipu->irq_sync < 0 || ipu->irq_err < 0) {
+		ret = -ENODEV;
+		goto failed_get_res;
+	}
+
+	if (request_irq(ipu->irq_sync, ipu_irq_handler, 0, pdev->name, ipu) != 0) {
+		dev_err(ipu->dev, "request SYNC interrupt failed\n");
+		ret = -EBUSY;
+		goto failed_req_irq_sync;
+	}
+	/* Some platforms have 2 IPU interrupts */
+	if (ipu->irq_err >= 0) {
+		if (request_irq
+		    (ipu->irq_err, ipu_irq_handler, 0, pdev->name, ipu) != 0) {
+			dev_err(ipu->dev, "request ERR interrupt failed\n");
+			ret = -EBUSY;
+			goto failed_req_irq_err;
+		}
+	}
+
+	ipu_base = res->start;
+	/* base fixup */
+	if (g_ipu_hw_rev == 4)	/* IPUv3H */
+		ipu_base += IPUV3H_REG_BASE;
+	else if (g_ipu_hw_rev == 3)	/* IPUv3M */
+		ipu_base += IPUV3M_REG_BASE;
+	else			/* IPUv3D, v3E, v3EX */
+		ipu_base += IPUV3DEX_REG_BASE;
+
+	ipu->cm_reg = ioremap(ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+	ipu->ic_reg = ioremap(ipu_base + IPU_IC_REG_BASE, PAGE_SIZE);
+	ipu->idmac_reg = ioremap(ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+	/* DP Registers are accessed thru the SRM */
+	ipu->dp_reg = ioremap(ipu_base + IPU_SRM_REG_BASE, PAGE_SIZE);
+	ipu->dc_reg = ioremap(ipu_base + IPU_DC_REG_BASE, PAGE_SIZE);
+	ipu->dmfc_reg = ioremap(ipu_base + IPU_DMFC_REG_BASE, PAGE_SIZE);
+	ipu->di_reg[0] = ioremap(ipu_base + IPU_DI0_REG_BASE, PAGE_SIZE);
+	ipu->di_reg[1] = ioremap(ipu_base + IPU_DI1_REG_BASE, PAGE_SIZE);
+	ipu->smfc_reg = ioremap(ipu_base + IPU_SMFC_REG_BASE, PAGE_SIZE);
+	ipu->csi_reg[0] = ioremap(ipu_base + IPU_CSI0_REG_BASE, PAGE_SIZE);
+	ipu->csi_reg[1] = ioremap(ipu_base + IPU_CSI1_REG_BASE, PAGE_SIZE);
+	ipu->cpmem_base = ioremap(ipu_base + IPU_CPMEM_REG_BASE, SZ_128K);
+	ipu->tpmem_base = ioremap(ipu_base + IPU_TPM_REG_BASE, SZ_64K);
+	ipu->dc_tmpl_reg = ioremap(ipu_base + IPU_DC_TMPL_REG_BASE, SZ_128K);
+	ipu->vdi_reg = ioremap(ipu_base + IPU_VDI_REG_BASE, PAGE_SIZE);
+	ipu->disp_base[1] = ioremap(ipu_base + IPU_DISP1_BASE, SZ_4K);
+
+	if (!ipu->cm_reg || !ipu->ic_reg || !ipu->idmac_reg ||
+		!ipu->dp_reg || !ipu->dc_reg || !ipu->dmfc_reg ||
+		!ipu->di_reg[0] || !ipu->di_reg[1] || !ipu->smfc_reg ||
+		!ipu->csi_reg[0] || !ipu->csi_reg[1] || !ipu->cpmem_base ||
+		!ipu->tpmem_base || !ipu->dc_tmpl_reg || !ipu->disp_base[1]
+		|| !ipu->vdi_reg) {
+		ret = -ENOMEM;
+		goto failed_ioremap;
+	}
+
+	dev_dbg(ipu->dev, "IPU CM Regs = %p\n", ipu->cm_reg);
+	dev_dbg(ipu->dev, "IPU IC Regs = %p\n", ipu->ic_reg);
+	dev_dbg(ipu->dev, "IPU IDMAC Regs = %p\n", ipu->idmac_reg);
+	dev_dbg(ipu->dev, "IPU DP Regs = %p\n", ipu->dp_reg);
+	dev_dbg(ipu->dev, "IPU DC Regs = %p\n", ipu->dc_reg);
+	dev_dbg(ipu->dev, "IPU DMFC Regs = %p\n", ipu->dmfc_reg);
+	dev_dbg(ipu->dev, "IPU DI0 Regs = %p\n", ipu->di_reg[0]);
+	dev_dbg(ipu->dev, "IPU DI1 Regs = %p\n", ipu->di_reg[1]);
+	dev_dbg(ipu->dev, "IPU SMFC Regs = %p\n", ipu->smfc_reg);
+	dev_dbg(ipu->dev, "IPU CSI0 Regs = %p\n", ipu->csi_reg[0]);
+	dev_dbg(ipu->dev, "IPU CSI1 Regs = %p\n", ipu->csi_reg[1]);
+	dev_dbg(ipu->dev, "IPU CPMem = %p\n", ipu->cpmem_base);
+	dev_dbg(ipu->dev, "IPU TPMem = %p\n", ipu->tpmem_base);
+	dev_dbg(ipu->dev, "IPU DC Template Mem = %p\n", ipu->dc_tmpl_reg);
+	dev_dbg(ipu->dev, "IPU Display Region 1 Mem = %p\n", ipu->disp_base[1]);
+	dev_dbg(ipu->dev, "IPU VDI Regs = %p\n", ipu->vdi_reg);
+
+	ret = ipu_clk_setup_enable(ipu, pdev);
+	if (ret < 0) {
+		dev_err(ipu->dev, "ipu clk setup failed\n");
+		goto failed_clk_setup;
+	}
+
+	platform_set_drvdata(pdev, ipu);
+
+	ipu_reset(ipu);
+
+	ipu_disp_init(ipu);
+
+	/* Set sync refresh channels and CSI->mem channel as high priority */
+	ipu_idmac_write(ipu, 0x18800001L, IDMAC_CHA_PRI(0));
+
+	/* Set MCU_T to divide MCU access window into 2 */
+	ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), IPU_DISP_GEN);
+
+	clk_disable(ipu->ipu_clk);
+
+	register_ipu_device(ipu, pdev->id);
+
+	return ret;
+
+failed_clk_setup:
+	iounmap(ipu->cm_reg);
+	iounmap(ipu->ic_reg);
+	iounmap(ipu->idmac_reg);
+	iounmap(ipu->dc_reg);
+	iounmap(ipu->dp_reg);
+	iounmap(ipu->dmfc_reg);
+	iounmap(ipu->di_reg[0]);
+	iounmap(ipu->di_reg[1]);
+	iounmap(ipu->smfc_reg);
+	iounmap(ipu->csi_reg[0]);
+	iounmap(ipu->csi_reg[1]);
+	iounmap(ipu->cpmem_base);
+	iounmap(ipu->tpmem_base);
+	iounmap(ipu->dc_tmpl_reg);
+	iounmap(ipu->disp_base[1]);
+	iounmap(ipu->vdi_reg);
+failed_ioremap:
+	if (ipu->irq_sync)
+		free_irq(ipu->irq_err, ipu);
+failed_req_irq_err:
+	free_irq(ipu->irq_sync, ipu);
+failed_req_irq_sync:
+failed_get_res:
+	return ret;
+}
+
+int __devexit ipu_remove(struct platform_device *pdev)
+{
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	unregister_ipu_device(ipu, pdev->id);
+
+	if (ipu->irq_sync)
+		free_irq(ipu->irq_sync, ipu);
+	if (ipu->irq_err)
+		free_irq(ipu->irq_err, ipu);
+
+	clk_put(ipu->ipu_clk);
+
+	iounmap(ipu->cm_reg);
+	iounmap(ipu->ic_reg);
+	iounmap(ipu->idmac_reg);
+	iounmap(ipu->dc_reg);
+	iounmap(ipu->dp_reg);
+	iounmap(ipu->dmfc_reg);
+	iounmap(ipu->di_reg[0]);
+	iounmap(ipu->di_reg[1]);
+	iounmap(ipu->smfc_reg);
+	iounmap(ipu->csi_reg[0]);
+	iounmap(ipu->csi_reg[1]);
+	iounmap(ipu->cpmem_base);
+	iounmap(ipu->tpmem_base);
+	iounmap(ipu->dc_tmpl_reg);
+	iounmap(ipu->disp_base[1]);
+	iounmap(ipu->vdi_reg);
+
+	return 0;
+}
+
+void ipu_dump_registers(struct ipu_soc *ipu)
+{
+	dev_dbg(ipu->dev, "IPU_CONF = \t0x%08X\n", ipu_cm_read(ipu, IPU_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CONF = \t0x%08X\n", ipu_idmac_read(ipu, IDMAC_CONF));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_EN(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_EN2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_EN(32)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_PRI(0)));
+	dev_dbg(ipu->dev, "IDMAC_CHA_PRI2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_CHA_PRI(32)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN1 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_BAND_EN(0)));
+	dev_dbg(ipu->dev, "IDMAC_BAND_EN2 = \t0x%08X\n",
+	       ipu_idmac_read(ipu, IDMAC_BAND_EN(32)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL0 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0)));
+	dev_dbg(ipu->dev, "IPU_CHA_DB_MODE_SEL1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32)));
+	if (g_ipu_hw_rev >= 2) {
+		dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL0 = \t0x%08X\n",
+		       ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(0)));
+		dev_dbg(ipu->dev, "IPU_CHA_TRB_MODE_SEL1 = \t0x%08X\n",
+		       ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(32)));
+	}
+	dev_dbg(ipu->dev, "DMFC_WR_CHAN = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_WR_CHAN));
+	dev_dbg(ipu->dev, "DMFC_WR_CHAN_DEF = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_WR_CHAN_DEF));
+	dev_dbg(ipu->dev, "DMFC_DP_CHAN = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_DP_CHAN));
+	dev_dbg(ipu->dev, "DMFC_DP_CHAN_DEF = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_DP_CHAN_DEF));
+	dev_dbg(ipu->dev, "DMFC_IC_CTRL = \t0x%08X\n",
+	       ipu_dmfc_read(ipu, DMFC_IC_CTRL));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW1));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW2 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW2));
+	dev_dbg(ipu->dev, "IPU_FS_PROC_FLOW3 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
+	dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
+	       ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+}
+
+/*!
+ * This function is called to initialize a logical IPU channel.
+ *
+ * @param	ipu	ipu handler
+ * @param       channel Input parameter for the logical channel ID to init.
+ *
+ * @param       params  Input parameter containing union of channel
+ *                      initialization parameters.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+	int ret = 0;
+	uint32_t ipu_conf;
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	dev_dbg(ipu->dev, "init channel = %d\n", IPU_CHAN_ID(channel));
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if (ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) {
+		dev_warn(ipu->dev, "Warning: channel already initialized %d\n",
+			IPU_CHAN_ID(channel));
+	}
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		if (params->csi_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (params->csi_mem.interlaced)
+			ipu->chan_is_interlaced[channel_2_dma(channel,
+				IPU_OUTPUT_BUFFER)] = true;
+		else
+			ipu->chan_is_interlaced[channel_2_dma(channel,
+				IPU_OUTPUT_BUFFER)] = false;
+
+		ipu->smfc_use_count++;
+		ipu->csi_channel[params->csi_mem.csi] = channel;
+
+		/*SMFC setting*/
+		if (params->csi_mem.mipi_en) {
+			ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_mem.csi));
+			_ipu_smfc_init(ipu, channel, params->csi_mem.mipi_id,
+				params->csi_mem.csi);
+		} else {
+			ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+				params->csi_mem.csi));
+			_ipu_smfc_init(ipu, channel, 0, params->csi_mem.csi);
+		}
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_mem.csi);
+		break;
+	case CSI_PRP_ENC_MEM:
+		if (params->csi_prp_enc_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+		if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = CSI_PRP_ENC_MEM;
+
+		ipu->ic_use_count++;
+		ipu->csi_channel[params->csi_prp_enc_mem.csi] = channel;
+
+		/*Without SMFC, CSI only support parallel data source*/
+		ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+			params->csi_prp_enc_mem.csi));
+
+		/*CSI0/1 feed into IC*/
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+		if (params->csi_prp_enc_mem.csi)
+			ipu_conf |= IPU_CONF_CSI_SEL;
+		else
+			ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+		/*PRP skip buffer in memory, only valid when RWS_EN is true*/
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_prp_enc_mem.csi);
+		_ipu_ic_init_prpenc(ipu, params, true);
+		break;
+	case CSI_PRP_VF_MEM:
+		if (params->csi_prp_vf_mem.csi > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+		if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = CSI_PRP_VF_MEM;
+
+		ipu->ic_use_count++;
+		ipu->csi_channel[params->csi_prp_vf_mem.csi] = channel;
+
+		/*Without SMFC, CSI only support parallel data source*/
+		ipu_conf &= ~(1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+			params->csi_prp_vf_mem.csi));
+
+		/*CSI0/1 feed into IC*/
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+		if (params->csi_prp_vf_mem.csi)
+			ipu_conf |= IPU_CONF_CSI_SEL;
+		else
+			ipu_conf &= ~IPU_CONF_CSI_SEL;
+
+		/*PRP skip buffer in memory, only valid when RWS_EN is true*/
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		/*CSI data (include compander) dest*/
+		_ipu_csi_init(ipu, channel, params->csi_prp_vf_mem.csi);
+		_ipu_ic_init_prpvf(ipu, params, true);
+		break;
+	case MEM_PRP_VF_MEM:
+		ipu->ic_use_count++;
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg | FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+
+		if (params->mem_prp_vf_mem.graphics_combine_en)
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		if (params->mem_prp_vf_mem.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+		_ipu_ic_init_prpvf(ipu, params, false);
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+		     (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		ipu->using_ic_dirct_ch = MEM_VDI_PRP_VF_MEM;
+		ipu->ic_use_count++;
+		ipu->vdi_use_count++;
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		reg &= ~FS_VDI_SRC_SEL_MASK;
+		ipu_cm_write(ipu, reg , IPU_FS_PROC_FLOW1);
+
+		if (params->mem_prp_vf_mem.graphics_combine_en)
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		_ipu_ic_init_prpvf(ipu, params, false);
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_VDI_PRP_VF_MEM_N:
+		_ipu_vdi_init(ipu, channel, params);
+		break;
+	case MEM_ROT_VF_MEM:
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		_ipu_ic_init_rotate_vf(ipu, params);
+		break;
+	case MEM_PRP_ENC_MEM:
+		ipu->ic_use_count++;
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg | FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+		_ipu_ic_init_prpenc(ipu, params, false);
+		break;
+	case MEM_ROT_ENC_MEM:
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		_ipu_ic_init_rotate_enc(ipu, params);
+		break;
+	case MEM_PP_MEM:
+		if (params->mem_pp_mem.graphics_combine_en)
+			ipu->sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		if (params->mem_pp_mem.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+		_ipu_ic_init_pp(ipu, params);
+		ipu->ic_use_count++;
+		break;
+	case MEM_ROT_PP_MEM:
+		_ipu_ic_init_rotate_pp(ipu, params);
+		ipu->ic_use_count++;
+		ipu->rot_use_count++;
+		break;
+	case MEM_DC_SYNC:
+		if (params->mem_dc_sync.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[1] = params->mem_dc_sync.di;
+		_ipu_dc_init(ipu, 1, params->mem_dc_sync.di,
+			     params->mem_dc_sync.interlaced,
+			     params->mem_dc_sync.out_pixel_fmt);
+		ipu->di_use_count[params->mem_dc_sync.di]++;
+		ipu->dc_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case MEM_BG_SYNC:
+		if (params->mem_dp_bg_sync.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (params->mem_dp_bg_sync.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+		ipu->dc_di_assignment[5] = params->mem_dp_bg_sync.di;
+		_ipu_dp_init(ipu, channel, params->mem_dp_bg_sync.in_pixel_fmt,
+			     params->mem_dp_bg_sync.out_pixel_fmt);
+		_ipu_dc_init(ipu, 5, params->mem_dp_bg_sync.di,
+			     params->mem_dp_bg_sync.interlaced,
+			     params->mem_dp_bg_sync.out_pixel_fmt);
+		ipu->di_use_count[params->mem_dp_bg_sync.di]++;
+		ipu->dc_use_count++;
+		ipu->dp_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case MEM_FG_SYNC:
+		_ipu_dp_init(ipu, channel, params->mem_dp_fg_sync.in_pixel_fmt,
+			     params->mem_dp_fg_sync.out_pixel_fmt);
+
+		if (params->mem_dp_fg_sync.alpha_chan_en)
+			ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = true;
+
+		ipu->dc_use_count++;
+		ipu->dp_use_count++;
+		ipu->dmfc_use_count++;
+		break;
+	case DIRECT_ASYNC0:
+		if (params->direct_async.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[8] = params->direct_async.di;
+		_ipu_dc_init(ipu, 8, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+		ipu->di_use_count[params->direct_async.di]++;
+		ipu->dc_use_count++;
+		break;
+	case DIRECT_ASYNC1:
+		if (params->direct_async.di > 1) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		ipu->dc_di_assignment[9] = params->direct_async.di;
+		_ipu_dc_init(ipu, 9, params->direct_async.di, false, IPU_PIX_FMT_GENERIC);
+		ipu->di_use_count[params->direct_async.di]++;
+		ipu->dc_use_count++;
+		break;
+	default:
+		dev_err(ipu->dev, "Missing channel initialization\n");
+		break;
+	}
+
+	/* Enable IPU sub module */
+	ipu->channel_init_mask |= 1L << IPU_CHAN_ID(channel);
+
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+err:
+	_ipu_unlock(ipu, &lock_flags);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_init_channel);
+
+/*!
+ * This function is called to uninitialize a logical IPU channel.
+ *
+ * @param	ipu	ipu handler
+ * @param       channel Input parameter for the logical channel ID to uninit.
+ */
+void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t in_dma, out_dma = 0;
+	uint32_t ipu_conf;
+	unsigned long lock_flags;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if ((ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+		dev_err(ipu->dev, "Channel already uninitialized %d\n",
+			IPU_CHAN_ID(channel));
+		_ipu_unlock(ipu, &lock_flags);
+		return;
+	}
+
+	/* Make sure channel is disabled */
+	/* Get input and output dma channels */
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+
+	if (idma_is_set(ipu, IDMAC_CHA_EN, in_dma) ||
+	    idma_is_set(ipu, IDMAC_CHA_EN, out_dma)) {
+		dev_err(ipu->dev,
+			"Channel %d is not disabled, disable first\n",
+			IPU_CHAN_ID(channel));
+		_ipu_unlock(ipu, &lock_flags);
+		return;
+	}
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+
+	/* Reset the double buffer */
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(in_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(in_dma), IPU_CHA_DB_MODE_SEL(in_dma));
+	reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(out_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(out_dma), IPU_CHA_DB_MODE_SEL(out_dma));
+
+	/* Reset the triple buffer */
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(in_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(in_dma), IPU_CHA_TRB_MODE_SEL(in_dma));
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(out_dma));
+	ipu_cm_write(ipu, reg & ~idma_mask(out_dma), IPU_CHA_TRB_MODE_SEL(out_dma));
+
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_dp_graphic_chan(in_dma)) {
+		ipu->sec_chan_en[IPU_CHAN_ID(channel)] = false;
+		ipu->thrd_chan_en[IPU_CHAN_ID(channel)] = false;
+	}
+
+	switch (channel) {
+	case CSI_MEM0:
+	case CSI_MEM1:
+	case CSI_MEM2:
+	case CSI_MEM3:
+		ipu->smfc_use_count--;
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case CSI_PRP_ENC_MEM:
+		ipu->ic_use_count--;
+		if (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpenc(ipu);
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case CSI_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		if (ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpvf(ipu);
+		if (ipu->csi_channel[0] == channel) {
+			ipu->csi_channel[0] = CHAN_NONE;
+		} else if (ipu->csi_channel[1] == channel) {
+			ipu->csi_channel[1] = CHAN_NONE;
+		}
+		break;
+	case MEM_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_prpvf(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ipu->ic_use_count--;
+		ipu->vdi_use_count--;
+		if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM)
+			ipu->using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpvf(ipu);
+		_ipu_vdi_uninit(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+	case MEM_VDI_PRP_VF_MEM_N:
+		break;
+	case MEM_ROT_VF_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_vf(ipu);
+		break;
+	case MEM_PRP_ENC_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_prpenc(ipu);
+		reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+		ipu_cm_write(ipu, reg & ~FS_ENC_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
+	case MEM_ROT_ENC_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_enc(ipu);
+		break;
+	case MEM_PP_MEM:
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_pp(ipu);
+		break;
+	case MEM_ROT_PP_MEM:
+		ipu->rot_use_count--;
+		ipu->ic_use_count--;
+		_ipu_ic_uninit_rotate_pp(ipu);
+		break;
+	case MEM_DC_SYNC:
+		_ipu_dc_uninit(ipu, 1);
+		ipu->di_use_count[ipu->dc_di_assignment[1]]--;
+		ipu->dc_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case MEM_BG_SYNC:
+		_ipu_dp_uninit(ipu, channel);
+		_ipu_dc_uninit(ipu, 5);
+		ipu->di_use_count[ipu->dc_di_assignment[5]]--;
+		ipu->dc_use_count--;
+		ipu->dp_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case MEM_FG_SYNC:
+		_ipu_dp_uninit(ipu, channel);
+		ipu->dc_use_count--;
+		ipu->dp_use_count--;
+		ipu->dmfc_use_count--;
+		break;
+	case DIRECT_ASYNC0:
+		_ipu_dc_uninit(ipu, 8);
+		ipu->di_use_count[ipu->dc_di_assignment[8]]--;
+		ipu->dc_use_count--;
+		break;
+	case DIRECT_ASYNC1:
+		_ipu_dc_uninit(ipu, 9);
+		ipu->di_use_count[ipu->dc_di_assignment[9]]--;
+		ipu->dc_use_count--;
+		break;
+	default:
+		break;
+	}
+
+	if (ipu->ic_use_count == 0)
+		ipu_conf &= ~IPU_CONF_IC_EN;
+	if (ipu->vdi_use_count == 0) {
+		ipu_conf &= ~IPU_CONF_ISP_EN;
+		ipu_conf &= ~IPU_CONF_VDI_EN;
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+	}
+	if (ipu->rot_use_count == 0)
+		ipu_conf &= ~IPU_CONF_ROT_EN;
+	if (ipu->dc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DC_EN;
+	if (ipu->dp_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DP_EN;
+	if (ipu->dmfc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_DMFC_EN;
+	if (ipu->di_use_count[0] == 0) {
+		ipu_conf &= ~IPU_CONF_DI0_EN;
+	}
+	if (ipu->di_use_count[1] == 0) {
+		ipu_conf &= ~IPU_CONF_DI1_EN;
+	}
+	if (ipu->smfc_use_count == 0)
+		ipu_conf &= ~IPU_CONF_SMFC_EN;
+
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	ipu->channel_init_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+
+	WARN_ON(ipu->ic_use_count < 0);
+	WARN_ON(ipu->vdi_use_count < 0);
+	WARN_ON(ipu->rot_use_count < 0);
+	WARN_ON(ipu->dc_use_count < 0);
+	WARN_ON(ipu->dp_use_count < 0);
+	WARN_ON(ipu->dmfc_use_count < 0);
+	WARN_ON(ipu->smfc_use_count < 0);
+}
+EXPORT_SYMBOL(ipu_uninit_channel);
+
+/*!
+ * This function is called to initialize buffer(s) for logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ *
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @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       phyaddr_2       Input parameter buffer 2 physical address.
+ *                              Setting this to a value other than NULL enables
+ *                              triple buffering mode, phyaddr_1 should not be
+ *                              NULL then.
+ *
+ * @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
+ */
+int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+				ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				ipu_rotate_mode_t rot_mode,
+				dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+				dma_addr_t phyaddr_2,
+				uint32_t u, uint32_t v)
+{
+	uint32_t reg;
+	uint32_t dma_chan;
+	uint32_t burst_size;
+	unsigned long lock_flags;
+
+	dma_chan = channel_2_dma(channel, type);
+	if (!idma_is_valid(dma_chan))
+		return -EINVAL;
+
+	if (stride < width * bytes_per_pixel(pixel_fmt))
+		stride = width * bytes_per_pixel(pixel_fmt);
+
+	if (stride % 4) {
+		dev_err(ipu->dev,
+			"Stride not 32-bit aligned, stride = %d\n", stride);
+		return -EINVAL;
+	}
+	/* IC & IRT channels' width must be multiple of 8 pixels */
+	if ((_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan))
+		&& (width % 8)) {
+		dev_err(ipu->dev, "Width must be 8 pixel multiple\n");
+		return -EINVAL;
+	}
+
+	/* IPUv3EX and IPUv3M support triple buffer */
+	if ((!_ipu_is_trb_chan(dma_chan)) && phyaddr_2) {
+		dev_err(ipu->dev, "Chan%d doesn't support triple buffer "
+				   "mode\n", dma_chan);
+		return -EINVAL;
+	}
+	if (!phyaddr_1 && phyaddr_2) {
+		dev_err(ipu->dev, "Chan%d's buf1 physical addr is NULL for "
+				   "triple buffer mode\n", dma_chan);
+		return -EINVAL;
+	}
+
+	_ipu_lock(ipu, &lock_flags);
+
+	/* Build parameter memory data for DMA channel */
+	_ipu_ch_param_init(ipu, dma_chan, pixel_fmt, width, height, stride, u, v, 0,
+			   phyaddr_0, phyaddr_1, phyaddr_2);
+
+	/* Set correlative channel parameter of local alpha channel */
+	if ((_ipu_is_ic_graphic_chan(dma_chan) ||
+	     _ipu_is_dp_graphic_chan(dma_chan)) &&
+	    (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] == true)) {
+		_ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, true);
+		_ipu_ch_param_set_alpha_buffer_memory(ipu, dma_chan);
+		_ipu_ch_param_set_alpha_condition_read(ipu, dma_chan);
+		/* fix alpha width as 8 and burst size as 16*/
+		_ipu_ch_params_set_alpha_width(ipu, dma_chan, 8);
+		_ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+	} else if (_ipu_is_ic_graphic_chan(dma_chan) &&
+		   ipu_pixel_format_has_alpha(pixel_fmt))
+		_ipu_ch_param_set_alpha_use_separate_channel(ipu, dma_chan, false);
+
+	if (rot_mode)
+		_ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
+
+	/* IC and ROT channels have restriction of 8 or 16 pix burst length */
+	if (_ipu_is_ic_chan(dma_chan)) {
+		if ((width % 16) == 0)
+			_ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
+		else
+			_ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+	} else if (_ipu_is_irt_chan(dma_chan)) {
+		_ipu_ch_param_set_burst_size(ipu, dma_chan, 8);
+		_ipu_ch_param_set_block_mode(ipu, dma_chan);
+	} else if (_ipu_is_dmfc_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		_ipu_dmfc_set_wait4eot(ipu, dma_chan, width);
+		_ipu_dmfc_set_burst_size(ipu, dma_chan, burst_size);
+	}
+
+	if (_ipu_disp_chan_is_interlaced(ipu, channel) ||
+		ipu->chan_is_interlaced[dma_chan])
+		_ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
+
+	if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		_ipu_ic_idma_init(ipu, dma_chan, width, height, burst_size,
+			rot_mode);
+	} else if (_ipu_is_smfc_chan(dma_chan)) {
+		burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
+		if ((pixel_fmt == IPU_PIX_FMT_GENERIC) &&
+			((_ipu_ch_param_get_bpp(ipu, dma_chan) == 5) ||
+			(_ipu_ch_param_get_bpp(ipu, dma_chan) == 3)))
+			burst_size = burst_size >> 4;
+		else
+			burst_size = burst_size >> 2;
+		_ipu_smfc_set_burst_size(ipu, channel, burst_size-1);
+	}
+
+	/* AXI-id */
+	if (idma_is_set(ipu, IDMAC_CHA_PRI, dma_chan)) {
+		unsigned reg = IDMAC_CH_LOCK_EN_1;
+		uint32_t value = 0;
+		if (cpu_is_mx53()) {
+			_ipu_ch_param_set_axi_id(ipu, dma_chan, 0);
+			switch (dma_chan) {
+			case 5:
+				value = 0x3;
+				break;
+			case 11:
+				value = 0x3 << 2;
+				break;
+			case 12:
+				value = 0x3 << 4;
+				break;
+			case 14:
+				value = 0x3 << 6;
+				break;
+			case 15:
+				value = 0x3 << 8;
+				break;
+			case 20:
+				value = 0x3 << 10;
+				break;
+			case 21:
+				value = 0x3 << 12;
+				break;
+			case 22:
+				value = 0x3 << 14;
+				break;
+			case 23:
+				value = 0x3 << 16;
+				break;
+			case 27:
+				value = 0x3 << 18;
+				break;
+			case 28:
+				value = 0x3 << 20;
+				break;
+			case 45:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 0;
+				break;
+			case 46:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 2;
+				break;
+			case 47:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 4;
+				break;
+			case 48:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 6;
+				break;
+			case 49:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 8;
+				break;
+			case 50:
+				reg = IDMAC_CH_LOCK_EN_2;
+				value = 0x3 << 10;
+				break;
+			default:
+				break;
+			}
+			value |= ipu_idmac_read(ipu, reg);
+			ipu_idmac_write(ipu, value, reg);
+		} else
+			_ipu_ch_param_set_axi_id(ipu, dma_chan, 1);
+	}
+
+	_ipu_ch_param_dump(ipu, dma_chan);
+
+	if (phyaddr_2 && g_ipu_hw_rev >= 2) {
+		reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+		reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+		reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(dma_chan));
+		reg |= idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_TRB_MODE_SEL(dma_chan));
+
+		/* Set IDMAC third buffer's cpmem number */
+		/* See __ipu_ch_get_third_buf_cpmem_num() for mapping */
+		ipu_idmac_write(ipu, 0x00444047L, IDMAC_SUB_ADDR_4);
+		ipu_idmac_write(ipu, 0x46004241L, IDMAC_SUB_ADDR_3);
+		ipu_idmac_write(ipu, 0x00000045L, IDMAC_SUB_ADDR_1);
+
+		/* Reset to buffer 0 */
+		ipu_cm_write(ipu, tri_cur_buf_mask(dma_chan),
+				IPU_CHA_TRIPLE_CUR_BUF(dma_chan));
+	} else {
+		reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(dma_chan));
+		reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_TRB_MODE_SEL(dma_chan));
+
+		reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(dma_chan));
+		if (phyaddr_1)
+			reg |= idma_mask(dma_chan);
+		else
+			reg &= ~idma_mask(dma_chan);
+		ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(dma_chan));
+
+		/* Reset to buffer 0 */
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+				IPU_CHA_CUR_BUF(dma_chan));
+
+	}
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_channel_buffer);
+
+/*!
+ * This function is called to update the physical address of a buffer for
+ * a logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       bufNum          Input parameter for buffer number to update.
+ *                              0 or 1 are the only valid values.
+ *
+ * @param       phyaddr         Input parameter buffer physical address.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail. This function will fail if the buffer is set to ready.
+ */
+int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+				ipu_buffer_t type, uint32_t bufNum, dma_addr_t phyaddr)
+{
+	uint32_t reg;
+	int ret = 0;
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if (bufNum == 0)
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(dma_chan));
+	else if (bufNum == 1)
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(dma_chan));
+	else
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(dma_chan));
+
+	if ((reg & idma_mask(dma_chan)) == 0)
+		_ipu_ch_param_set_buffer(ipu, dma_chan, bufNum, phyaddr);
+	else
+		ret = -EACCES;
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_buffer);
+
+
+/*!
+ * This function is called to initialize a buffer for logical IPU channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @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       u		predefined private u offset for additional cropping,
+ *								zero if not used.
+ *
+ * @param       v		predefined private v offset for additional cropping,
+ *								zero if not used.
+ *
+ * @param			vertical_offset vertical offset for Y coordinate
+ * 								in the existed frame
+ *
+ *
+ * @param			horizontal_offset horizontal offset for X coordinate
+ * 								in the existed frame
+ *
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ *              This function will fail if any buffer is set to ready.
+ */
+
+int32_t ipu_update_channel_offset(struct ipu_soc *ipu,
+				ipu_channel_t channel, ipu_buffer_t type,
+				uint32_t pixel_fmt,
+				uint16_t width, uint16_t height,
+				uint32_t stride,
+				uint32_t u, uint32_t v,
+				uint32_t vertical_offset, uint32_t horizontal_offset)
+{
+	int ret = 0;
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if ((ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(dma_chan)) & idma_mask(dma_chan)) ||
+	    (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(dma_chan)) & idma_mask(dma_chan)) ||
+	    ((ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(dma_chan)) & idma_mask(dma_chan)) &&
+	     (ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(dma_chan)) & idma_mask(dma_chan)) &&
+	     _ipu_is_trb_chan(dma_chan)))
+		ret = -EACCES;
+	else
+		_ipu_ch_offset_update(ipu, dma_chan, pixel_fmt, width, height, stride,
+				      u, v, 0, vertical_offset, horizontal_offset);
+
+	_ipu_unlock(ipu, &lock_flags);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_offset);
+
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       bufNum          Input parameter for which buffer number set to
+ *                              ready state.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
+			ipu_buffer_t type, uint32_t bufNum)
+{
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	unsigned long lock_flags;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	/* Mark buffer to be ready. */
+	_ipu_lock(ipu, &lock_flags);
+	if (bufNum == 0)
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF0_RDY(dma_chan));
+	else if (bufNum == 1)
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF1_RDY(dma_chan));
+	else
+		ipu_cm_write(ipu, idma_mask(dma_chan),
+			     IPU_CHA_BUF2_RDY(dma_chan));
+	_ipu_unlock(ipu, &lock_flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_select_buffer);
+
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param	ipu		ipu handler
+ * @param       bufNum          Input parameter for which buffer number set to
+ *                              ready state.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_multi_vdi_buffer(struct ipu_soc *ipu, uint32_t bufNum)
+{
+
+	uint32_t dma_chan = channel_2_dma(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER);
+	uint32_t mask_bit =
+		idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_P, IPU_INPUT_BUFFER))|
+		idma_mask(dma_chan)|
+		idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_N, IPU_INPUT_BUFFER));
+	unsigned long lock_flags;
+
+	/* Mark buffers to be ready. */
+	_ipu_lock(ipu, &lock_flags);
+	if (bufNum == 0)
+		ipu_cm_write(ipu, mask_bit, IPU_CHA_BUF0_RDY(dma_chan));
+	else
+		ipu_cm_write(ipu, mask_bit, IPU_CHA_BUF1_RDY(dma_chan));
+	_ipu_unlock(ipu, &lock_flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_select_multi_vdi_buffer);
+
+#define NA	-1
+static int proc_dest_sel[] = {
+	0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
+	0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 };
+static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA,
+  NA, NA, NA, NA, NA,  1,  2,  3,  4,  7,  8, NA, 8, NA };
+static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA,
+  NA, NA, NA, NA, NA,  1, NA,  2, NA,  3,  4,  4,  4,  4 };
+
+
+/*!
+ * This function links 2 channels together for automatic frame
+ * synchronization. The output of the source channel is linked to the input of
+ * the destination channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       src_ch          Input parameter for the logical channel ID of
+ *                              the source channel.
+ *
+ * @param       dest_ch         Input parameter for the logical channel ID of
+ *                              the destination channel.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+	int retval = 0;
+	uint32_t fs_proc_flow1;
+	uint32_t fs_proc_flow2;
+	uint32_t fs_proc_flow3;
+	uint32_t fs_disp_flow1;
+	unsigned long lock_flags;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+	fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+	fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+	switch (src_ch) {
+	case CSI_MEM0:
+		fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC0_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM1:
+		fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC1_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM2:
+		fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC2_DEST_SEL_OFFSET;
+		break;
+	case CSI_MEM3:
+		fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+		fs_proc_flow3 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_SMFC3_DEST_SEL_OFFSET;
+		break;
+	case CSI_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_PRPENC_DEST_SEL_OFFSET;
+		break;
+	case CSI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+			proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+			FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PP_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PP_ROT_DEST_SEL_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPENC_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPENC_ROT_DEST_SEL_OFFSET;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_DEST_SEL_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_ROT_DEST_SEL_OFFSET;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	switch (dest_ch) {
+	case MEM_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PP_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PRPENC_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_PRPVF_ROT_SRC_SEL_OFFSET;
+		break;
+	case MEM_DC_SYNC:
+		fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC1_SRC_SEL_OFFSET;
+		break;
+	case MEM_BG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_SYNC0_SRC_SEL_OFFSET;
+		break;
+	case MEM_FG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_SYNC1_SRC_SEL_OFFSET;
+		break;
+	case MEM_DC_ASYNC:
+		fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] << FS_DC2_SRC_SEL_OFFSET;
+		break;
+	case MEM_BG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_ASYNC0_SRC_SEL_OFFSET;
+		break;
+	case MEM_FG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+		fs_disp_flow1 |=
+		    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
+		    FS_DP_ASYNC1_SRC_SEL_OFFSET;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+	ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+	ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+	_ipu_unlock(ipu, &lock_flags);
+	return retval;
+}
+EXPORT_SYMBOL(ipu_link_channels);
+
+/*!
+ * This function unlinks 2 channels and disables automatic frame
+ * synchronization.
+ *
+ * @param	ipu		ipu handler
+ * @param       src_ch          Input parameter for the logical channel ID of
+ *                              the source channel.
+ *
+ * @param       dest_ch         Input parameter for the logical channel ID of
+ *                              the destination channel.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel_t dest_ch)
+{
+	int retval = 0;
+	uint32_t fs_proc_flow1;
+	uint32_t fs_proc_flow2;
+	uint32_t fs_proc_flow3;
+	uint32_t fs_disp_flow1;
+	unsigned long lock_flags;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	fs_proc_flow1 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
+	fs_proc_flow2 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW2);
+	fs_proc_flow3 = ipu_cm_read(ipu, IPU_FS_PROC_FLOW3);
+	fs_disp_flow1 = ipu_cm_read(ipu, IPU_FS_DISP_FLOW1);
+
+	switch (src_ch) {
+	case CSI_MEM0:
+		fs_proc_flow3 &= ~FS_SMFC0_DEST_SEL_MASK;
+		break;
+	case CSI_MEM1:
+		fs_proc_flow3 &= ~FS_SMFC1_DEST_SEL_MASK;
+		break;
+	case CSI_MEM2:
+		fs_proc_flow3 &= ~FS_SMFC2_DEST_SEL_MASK;
+		break;
+	case CSI_MEM3:
+		fs_proc_flow3 &= ~FS_SMFC3_DEST_SEL_MASK;
+		break;
+	case CSI_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		break;
+	case CSI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow2 &= ~FS_PP_ROT_DEST_SEL_MASK;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow2 &= ~FS_PRPENC_ROT_DEST_SEL_MASK;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	switch (dest_ch) {
+	case MEM_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_PP_MEM:
+		fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_PRP_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_ENC_MEM:
+		fs_proc_flow1 &= ~FS_PRPENC_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
+	case MEM_ROT_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
+		break;
+	case MEM_DC_SYNC:
+		fs_disp_flow1 &= ~FS_DC1_SRC_SEL_MASK;
+		break;
+	case MEM_BG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC0_SRC_SEL_MASK;
+		break;
+	case MEM_FG_SYNC:
+		fs_disp_flow1 &= ~FS_DP_SYNC1_SRC_SEL_MASK;
+		break;
+	case MEM_DC_ASYNC:
+		fs_disp_flow1 &= ~FS_DC2_SRC_SEL_MASK;
+		break;
+	case MEM_BG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC0_SRC_SEL_MASK;
+		break;
+	case MEM_FG_ASYNC0:
+		fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
+		break;
+	default:
+		retval = -EINVAL;
+		goto err;
+	}
+
+	ipu_cm_write(ipu, fs_proc_flow1, IPU_FS_PROC_FLOW1);
+	ipu_cm_write(ipu, fs_proc_flow2, IPU_FS_PROC_FLOW2);
+	ipu_cm_write(ipu, fs_proc_flow3, IPU_FS_PROC_FLOW3);
+	ipu_cm_write(ipu, fs_disp_flow1, IPU_FS_DISP_FLOW1);
+
+err:
+	_ipu_unlock(ipu, &lock_flags);
+	return retval;
+}
+EXPORT_SYMBOL(ipu_unlink_channels);
+
+/*!
+ * This function check whether a logical channel was enabled.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 1 while request channel is enabled or
+ *              0 for not enabled.
+ */
+int32_t ipu_is_channel_busy(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t in_dma;
+	uint32_t out_dma;
+
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+	if (reg & idma_mask(in_dma))
+		return 1;
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+	if (reg & idma_mask(out_dma))
+		return 1;
+	return 0;
+}
+EXPORT_SYMBOL(ipu_is_channel_busy);
+
+/*!
+ * This function enables a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t reg;
+	uint32_t ipu_conf;
+	uint32_t in_dma;
+	uint32_t out_dma;
+	uint32_t sec_dma;
+	uint32_t thrd_dma;
+	unsigned long lock_flags;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if (ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
+		dev_err(ipu->dev, "Warning: channel already enabled %d\n",
+			IPU_CHAN_ID(channel));
+		_ipu_unlock(ipu, &lock_flags);
+		return -EACCES;
+	}
+
+	/* Get input and output dma channels */
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	ipu_conf = ipu_cm_read(ipu, IPU_CONF);
+	if (ipu->di_use_count[0] > 0) {
+		ipu_conf |= IPU_CONF_DI0_EN;
+	}
+	if (ipu->di_use_count[1] > 0) {
+		ipu_conf |= IPU_CONF_DI1_EN;
+	}
+	if (ipu->dp_use_count > 0)
+		ipu_conf |= IPU_CONF_DP_EN;
+	if (ipu->dc_use_count > 0)
+		ipu_conf |= IPU_CONF_DC_EN;
+	if (ipu->dmfc_use_count > 0)
+		ipu_conf |= IPU_CONF_DMFC_EN;
+	if (ipu->ic_use_count > 0)
+		ipu_conf |= IPU_CONF_IC_EN;
+	if (ipu->vdi_use_count > 0) {
+		ipu_conf |= IPU_CONF_ISP_EN;
+		ipu_conf |= IPU_CONF_VDI_EN;
+		ipu_conf |= IPU_CONF_IC_INPUT;
+	}
+	if (ipu->rot_use_count > 0)
+		ipu_conf |= IPU_CONF_ROT_EN;
+	if (ipu->smfc_use_count > 0)
+		ipu_conf |= IPU_CONF_SMFC_EN;
+	ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+	if (idma_is_valid(in_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+	}
+	if (idma_is_valid(out_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+	}
+
+	if ((ipu->sec_chan_en[IPU_CHAN_ID(channel)]) &&
+		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM) ||
+		 (channel == MEM_VDI_PRP_VF_MEM))) {
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+	}
+	if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM))) {
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+		ipu_idmac_write(ipu, reg | idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+	} else if ((ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) &&
+		   ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))) {
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+		reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_SEP_ALPHA);
+	}
+
+	if ((channel == MEM_DC_SYNC) || (channel == MEM_BG_SYNC) ||
+	    (channel == MEM_FG_SYNC)) {
+		reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+		ipu_idmac_write(ipu, reg | idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+
+		_ipu_dp_dc_enable(ipu, channel);
+	}
+
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+		_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
+		_ipu_ic_enable_task(ipu, channel);
+
+	ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_enable_channel);
+
+/*!
+ * This function check buffer ready for a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to clear.
+ *
+ * @param       bufNum          Input parameter for which buffer number clear
+ * 				ready state.
+ *
+ */
+int32_t ipu_check_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	uint32_t dma_chan = channel_2_dma(channel, type);
+	uint32_t reg;
+
+	if (dma_chan == IDMA_CHAN_INVALID)
+		return -EINVAL;
+
+	if (bufNum == 0)
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(dma_chan));
+	else if (bufNum == 1)
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(dma_chan));
+	else
+		reg = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(dma_chan));
+
+	if (reg & idma_mask(dma_chan))
+		return 1;
+	else
+		return 0;
+}
+EXPORT_SYMBOL(ipu_check_buffer_ready);
+
+/*!
+ * This function clear buffer ready for a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to clear.
+ *
+ * @param       bufNum          Input parameter for which buffer number clear
+ * 				ready state.
+ *
+ */
+void _ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	uint32_t dma_ch = channel_2_dma(channel, type);
+
+	if (!idma_is_valid(dma_ch))
+		return;
+
+	ipu_cm_write(ipu, 0xF0300000, IPU_GPR); /* write one to clear */
+	if (bufNum == 0)
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF0_RDY(dma_ch));
+	else if (bufNum == 1)
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF1_RDY(dma_ch));
+	else
+		ipu_cm_write(ipu, idma_mask(dma_ch),
+				IPU_CHA_BUF2_RDY(dma_ch));
+	ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */
+}
+
+void ipu_clear_buffer_ready(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type,
+		uint32_t bufNum)
+{
+	unsigned long lock_flags;
+	_ipu_lock(ipu, &lock_flags);
+	_ipu_clear_buffer_ready(ipu, channel, type, bufNum);
+	_ipu_unlock(ipu, &lock_flags);
+}
+EXPORT_SYMBOL(ipu_clear_buffer_ready);
+
+/*!
+ * This function disables a logical channel.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       wait_for_stop   Flag to set whether to wait for channel end
+ *                              of frame or return immediately.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wait_for_stop)
+{
+	uint32_t reg;
+	uint32_t in_dma;
+	uint32_t out_dma;
+	uint32_t sec_dma = NO_DMA;
+	uint32_t thrd_dma = NO_DMA;
+	uint16_t fg_pos_x, fg_pos_y;
+	unsigned long lock_flags;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if ((ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+		dev_err(ipu->dev, "Channel already disabled %d\n",
+			IPU_CHAN_ID(channel));
+		_ipu_unlock(ipu, &lock_flags);
+		return -EACCES;
+	}
+
+	/* Get input and output dma channels */
+	out_dma = channel_2_dma(channel, IPU_OUTPUT_BUFFER);
+	in_dma = channel_2_dma(channel, IPU_VIDEO_IN_BUFFER);
+
+	if ((idma_is_valid(in_dma) &&
+		!idma_is_set(ipu, IDMAC_CHA_EN, in_dma))
+		&& (idma_is_valid(out_dma) &&
+		!idma_is_set(ipu, IDMAC_CHA_EN, out_dma))) {
+		_ipu_unlock(ipu, &lock_flags);
+		return -EINVAL;
+	}
+
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)])
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)]) {
+		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
+		thrd_dma = channel_2_dma(channel, IPU_ALPHA_IN_BUFFER);
+	}
+
+	_ipu_unlock(ipu, &lock_flags);
+	if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+	    (channel == MEM_DC_SYNC)) {
+		if (channel == MEM_FG_SYNC) {
+			_ipu_disp_get_window_pos(ipu, channel, &fg_pos_x, &fg_pos_y);
+			_ipu_disp_set_window_pos(ipu, channel, 0, 0);
+		}
+
+		_ipu_dp_dc_disable(ipu, channel, false);
+
+		/*
+		 * wait for BG channel EOF then disable FG-IDMAC,
+		 * it avoid FG NFB4EOF error.
+		 */
+		if (channel == MEM_FG_SYNC) {
+			int timeout = 50;
+
+			ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF),
+					IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF));
+			while ((ipu_cm_read(ipu, IPUIRQ_2_STATREG(IPU_IRQ_BG_SYNC_EOF)) &
+						IPUIRQ_2_MASK(IPU_IRQ_BG_SYNC_EOF)) == 0) {
+				msleep(10);
+				timeout -= 10;
+				if (timeout <= 0) {
+					dev_err(ipu->dev, "warning: wait for bg sync eof timeout\n");
+					break;
+				}
+			}
+		}
+	} else if (wait_for_stop) {
+		while (idma_is_set(ipu, IDMAC_CHA_BUSY, in_dma) ||
+		       idma_is_set(ipu, IDMAC_CHA_BUSY, out_dma) ||
+			(ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+			idma_is_set(ipu, IDMAC_CHA_BUSY, sec_dma)) ||
+			(ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+			idma_is_set(ipu, IDMAC_CHA_BUSY, thrd_dma))) {
+			uint32_t irq = 0xffffffff;
+			DECLARE_COMPLETION_ONSTACK(disable_comp);
+			int timeout = 50;
+
+			if (idma_is_set(ipu, IDMAC_CHA_BUSY, out_dma))
+				irq = out_dma;
+			if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] &&
+				idma_is_set(ipu, IDMAC_CHA_BUSY, sec_dma))
+				irq = sec_dma;
+			if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] &&
+				idma_is_set(ipu, IDMAC_CHA_BUSY, thrd_dma))
+				irq = thrd_dma;
+			if (idma_is_set(ipu, IDMAC_CHA_BUSY, in_dma))
+				irq = in_dma;
+
+			if (irq == 0xffffffff) {
+				dev_err(ipu->dev, "warning: no channel busy, break\n");
+				break;
+			}
+
+			dev_err(ipu->dev, "warning: channel %d busy, need wait\n", irq);
+
+			ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+					IPUIRQ_2_STATREG(irq));
+			while ((ipu_cm_read(ipu, IPUIRQ_2_STATREG(irq)) &
+						IPUIRQ_2_MASK(irq)) == 0) {
+				msleep(10);
+				timeout -= 10;
+				if (timeout <= 0) {
+					ipu_dump_registers(ipu);
+					dev_err(ipu->dev, "warning: disable ipu dma channel %d during its busy state\n", irq);
+					break;
+				}
+			}
+
+		}
+	}
+	_ipu_lock(ipu, &lock_flags);
+
+	if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC) ||
+	    (channel == MEM_DC_SYNC)) {
+		reg = ipu_idmac_read(ipu, IDMAC_WM_EN(in_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_WM_EN(in_dma));
+	}
+
+	/* Disable IC task */
+	if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
+		_ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
+		_ipu_ic_disable_task(ipu, channel);
+
+	/* Disable DMA channel(s) */
+	if (idma_is_valid(in_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(in_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_CHA_EN(in_dma));
+		ipu_cm_write(ipu, idma_mask(in_dma), IPU_CHA_CUR_BUF(in_dma));
+		ipu_cm_write(ipu, tri_cur_buf_mask(in_dma),
+					IPU_CHA_TRIPLE_CUR_BUF(in_dma));
+	}
+	if (idma_is_valid(out_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(out_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(out_dma), IDMAC_CHA_EN(out_dma));
+		ipu_cm_write(ipu, idma_mask(out_dma), IPU_CHA_CUR_BUF(out_dma));
+		ipu_cm_write(ipu, tri_cur_buf_mask(out_dma),
+					IPU_CHA_TRIPLE_CUR_BUF(out_dma));
+	}
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(sec_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
+		ipu_cm_write(ipu, idma_mask(sec_dma), IPU_CHA_CUR_BUF(sec_dma));
+	}
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+		reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(thrd_dma));
+		ipu_idmac_write(ipu, reg & ~idma_mask(thrd_dma), IDMAC_CHA_EN(thrd_dma));
+		if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC) {
+			reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+			ipu_idmac_write(ipu, reg & ~idma_mask(in_dma), IDMAC_SEP_ALPHA);
+		} else {
+			reg = ipu_idmac_read(ipu, IDMAC_SEP_ALPHA);
+			ipu_idmac_write(ipu, reg & ~idma_mask(sec_dma), IDMAC_SEP_ALPHA);
+		}
+		ipu_cm_write(ipu, idma_mask(thrd_dma), IPU_CHA_CUR_BUF(thrd_dma));
+	}
+
+	ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+	if (channel == MEM_FG_SYNC)
+		_ipu_disp_set_window_pos(ipu, channel, fg_pos_x, fg_pos_y);
+
+	/* Set channel buffers NOT to be ready */
+	if (idma_is_valid(in_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 1);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_VIDEO_IN_BUFFER, 2);
+	}
+	if (idma_is_valid(out_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_OUTPUT_BUFFER, 1);
+	}
+	if (ipu->sec_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(sec_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_GRAPH_IN_BUFFER, 1);
+	}
+	if (ipu->thrd_chan_en[IPU_CHAN_ID(channel)] && idma_is_valid(thrd_dma)) {
+		_ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 0);
+		_ipu_clear_buffer_ready(ipu, channel, IPU_ALPHA_IN_BUFFER, 1);
+	}
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disable_channel);
+
+/*!
+ * This function enables CSI.
+ *
+ * @param	ipu		ipu handler
+ * @param       csi	csi num 0 or 1
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_enable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	if (csi > 1) {
+		dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+		return -EINVAL;
+	}
+
+	_ipu_lock(ipu, &lock_flags);
+	ipu->csi_use_count[csi]++;
+
+	if (ipu->csi_use_count[csi] == 1) {
+		reg = ipu_cm_read(ipu, IPU_CONF);
+		if (csi == 0)
+			ipu_cm_write(ipu, reg | IPU_CONF_CSI0_EN, IPU_CONF);
+		else
+			ipu_cm_write(ipu, reg | IPU_CONF_CSI1_EN, IPU_CONF);
+	}
+	_ipu_unlock(ipu, &lock_flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_enable_csi);
+
+/*!
+ * This function disables CSI.
+ *
+ * @param	ipu		ipu handler
+ * @param       csi	csi num 0 or 1
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_disable_csi(struct ipu_soc *ipu, uint32_t csi)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	if (csi > 1) {
+		dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+		return -EINVAL;
+	}
+
+	_ipu_lock(ipu, &lock_flags);
+	ipu->csi_use_count[csi]--;
+	if (ipu->csi_use_count[csi] == 0) {
+		reg = ipu_cm_read(ipu, IPU_CONF);
+		if (csi == 0)
+			ipu_cm_write(ipu, reg & ~IPU_CONF_CSI0_EN, IPU_CONF);
+		else
+			ipu_cm_write(ipu, reg & ~IPU_CONF_CSI1_EN, IPU_CONF);
+	}
+	_ipu_unlock(ipu, &lock_flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disable_csi);
+
+static irqreturn_t ipu_irq_handler(int irq, void *desc)
+{
+	struct ipu_soc *ipu = desc;
+	int i;
+	uint32_t line;
+	irqreturn_t result = IRQ_NONE;
+	uint32_t int_stat;
+	const int err_reg[] = { 5, 6, 9, 10, 0 };
+	const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 };
+
+	for (i = 0;; i++) {
+		if (err_reg[i] == 0)
+			break;
+		int_stat = ipu_cm_read(ipu, IPU_INT_STAT(err_reg[i]));
+		int_stat &= ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i]));
+		if (int_stat) {
+			ipu_cm_write(ipu, int_stat, IPU_INT_STAT(err_reg[i]));
+			dev_err(ipu->dev,
+				"IPU Error - IPU_INT_STAT_%d = 0x%08X\n",
+				err_reg[i], int_stat);
+			/* Disable interrupts so we only get error once */
+			int_stat =
+			    ipu_cm_read(ipu, IPU_INT_CTRL(err_reg[i])) & ~int_stat;
+			ipu_cm_write(ipu, int_stat, IPU_INT_CTRL(err_reg[i]));
+		}
+	}
+
+	for (i = 0;; i++) {
+		if (int_reg[i] == 0)
+			break;
+		int_stat = ipu_cm_read(ipu, IPU_INT_STAT(int_reg[i]));
+		int_stat &= ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i]));
+		ipu_cm_write(ipu, int_stat, IPU_INT_STAT(int_reg[i]));
+		while ((line = ffs(int_stat)) != 0) {
+			line--;
+			int_stat &= ~(1UL << line);
+			line += (int_reg[i] - 1) * 32;
+			result |=
+			    ipu->irq_list[line].handler(line,
+						       ipu->irq_list[line].
+						       dev_id);
+		}
+	}
+
+	return result;
+}
+
+/*!
+ * This function enables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to enable interrupt for.
+ *
+ */
+void ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->spin_lock, lock_flags);
+
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg |= IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+
+	spin_unlock_irqrestore(&ipu->spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_enable_irq);
+
+/*!
+ * This function disables the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to disable interrupt for.
+ *
+ */
+void ipu_disable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+
+	spin_lock_irqsave(&ipu->spin_lock, lock_flags);
+
+	reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+	reg &= ~IPUIRQ_2_MASK(irq);
+	ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+
+	spin_unlock_irqrestore(&ipu->spin_lock, lock_flags);
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_irq);
+
+/*!
+ * This function clears the interrupt for the specified interrupt line.
+ * The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to clear interrupt for.
+ *
+ */
+void ipu_clear_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+	_ipu_get(ipu);
+
+	ipu_cm_write(ipu, IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq));
+
+	_ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_clear_irq);
+
+/*!
+ * This function returns the current interrupt status for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @return      Returns true if the interrupt is pending/asserted or false if
+ *              the interrupt is not pending.
+ */
+bool ipu_get_irq_status(struct ipu_soc *ipu, uint32_t irq)
+{
+	uint32_t reg;
+
+	_ipu_get(ipu);
+
+	reg = ipu_cm_read(ipu, IPUIRQ_2_STATREG(irq));
+
+	_ipu_put(ipu);
+
+	if (reg & IPUIRQ_2_MASK(irq))
+		return true;
+	else
+		return false;
+}
+EXPORT_SYMBOL(ipu_get_irq_status);
+
+/*!
+ * This function registers an interrupt handler function for the specified
+ * interrupt line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @param       handler         Input parameter for address of the handler
+ *                              function.
+ *
+ * @param       irq_flags       Flags for interrupt mode. Currently not used.
+ *
+ * @param       devname         Input parameter for string name of driver
+ *                              registering the handler.
+ *
+ * @param       dev_id          Input parameter for pointer of data to be
+ *                              passed to the handler.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int ipu_request_irq(struct ipu_soc *ipu, uint32_t irq,
+		    irqreturn_t(*handler) (int, void *),
+		    uint32_t irq_flags, const char *devname, void *dev_id)
+{
+	unsigned long lock_flags;
+
+	BUG_ON(irq >= IPU_IRQ_COUNT);
+
+	spin_lock_irqsave(&ipu->spin_lock, lock_flags);
+
+	if (ipu->irq_list[irq].handler != NULL) {
+		dev_err(ipu->dev,
+			"handler already installed on irq %d\n", irq);
+		spin_unlock_irqrestore(&ipu->spin_lock, lock_flags);
+		return -EINVAL;
+	}
+
+	ipu->irq_list[irq].handler = handler;
+	ipu->irq_list[irq].flags = irq_flags;
+	ipu->irq_list[irq].dev_id = dev_id;
+	ipu->irq_list[irq].name = devname;
+
+	spin_unlock_irqrestore(&ipu->spin_lock, lock_flags);
+
+	ipu_enable_irq(ipu, irq);	/* enable the interrupt */
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_request_irq);
+
+/*!
+ * This function unregisters an interrupt handler for the specified interrupt
+ * line. The interrupt lines are defined in \b ipu_irq_line enum.
+ *
+ * @param	ipu		ipu handler
+ * @param       irq             Interrupt line to get status for.
+ *
+ * @param       dev_id          Input parameter for pointer of data to be passed
+ *                              to the handler. This must match value passed to
+ *                              ipu_request_irq().
+ *
+ */
+void ipu_free_irq(struct ipu_soc *ipu, uint32_t irq, void *dev_id)
+{
+	ipu_disable_irq(ipu, irq);	/* disable the interrupt */
+
+	if (ipu->irq_list[irq].dev_id == dev_id)
+		ipu->irq_list[irq].handler = NULL;
+}
+EXPORT_SYMBOL(ipu_free_irq);
+
+uint32_t ipu_get_cur_buffer_idx(struct ipu_soc *ipu, ipu_channel_t channel, ipu_buffer_t type)
+{
+	uint32_t reg, dma_chan;
+
+	dma_chan = channel_2_dma(channel, type);
+	if (!idma_is_valid(dma_chan))
+		return -EINVAL;
+
+	reg = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(dma_chan));
+	if ((reg & idma_mask(dma_chan)) && _ipu_is_trb_chan(dma_chan)) {
+		reg = ipu_cm_read(ipu, IPU_CHA_TRIPLE_CUR_BUF(dma_chan));
+		return (reg & tri_cur_buf_mask(dma_chan)) >>
+				tri_cur_buf_shift(dma_chan);
+	} else {
+		reg = ipu_cm_read(ipu, IPU_CHA_CUR_BUF(dma_chan));
+		if (reg & idma_mask(dma_chan))
+			return 1;
+		else
+			return 0;
+	}
+}
+EXPORT_SYMBOL(ipu_get_cur_buffer_idx);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t stat = 0;
+	uint32_t task_stat_reg = ipu_cm_read(ipu, IPU_PROC_TASK_STAT);
+
+	switch (channel) {
+	case MEM_PRP_VF_MEM:
+		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+		break;
+	case MEM_ROT_VF_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_VF_ROT_MASK) >> TSTAT_VF_ROT_OFFSET;
+		break;
+	case MEM_PRP_ENC_MEM:
+		stat = (task_stat_reg & TSTAT_ENC_MASK) >> TSTAT_ENC_OFFSET;
+		break;
+	case MEM_ROT_ENC_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_ENC_ROT_MASK) >>
+		    TSTAT_ENC_ROT_OFFSET;
+		break;
+	case MEM_PP_MEM:
+		stat = (task_stat_reg & TSTAT_PP_MASK) >> TSTAT_PP_OFFSET;
+		break;
+	case MEM_ROT_PP_MEM:
+		stat =
+		    (task_stat_reg & TSTAT_PP_ROT_MASK) >> TSTAT_PP_ROT_OFFSET;
+		break;
+
+	default:
+		stat = TASK_STAT_IDLE;
+		break;
+	}
+	return stat;
+}
+
+int32_t ipu_swap_channel(struct ipu_soc *ipu, ipu_channel_t from_ch, ipu_channel_t to_ch)
+{
+	uint32_t reg;
+	unsigned long lock_flags;
+
+	int from_dma = channel_2_dma(from_ch, IPU_INPUT_BUFFER);
+	int to_dma = channel_2_dma(to_ch, IPU_INPUT_BUFFER);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	/* enable target channel */
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(to_dma));
+	ipu_idmac_write(ipu, reg | idma_mask(to_dma), IDMAC_CHA_EN(to_dma));
+
+	ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(to_ch);
+
+	/* switch dp dc */
+	_ipu_unlock(ipu, &lock_flags);
+	_ipu_dp_dc_disable(ipu, from_ch, true);
+	_ipu_lock(ipu, &lock_flags);
+
+	/* disable source channel */
+	reg = ipu_idmac_read(ipu, IDMAC_CHA_EN(from_dma));
+	ipu_idmac_write(ipu, reg & ~idma_mask(from_dma), IDMAC_CHA_EN(from_dma));
+	ipu_cm_write(ipu, idma_mask(from_dma), IPU_CHA_CUR_BUF(from_dma));
+	ipu_cm_write(ipu, tri_cur_buf_mask(from_dma),
+				IPU_CHA_TRIPLE_CUR_BUF(from_dma));
+
+	ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(from_ch));
+
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 0);
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 1);
+	_ipu_clear_buffer_ready(ipu, from_ch, IPU_VIDEO_IN_BUFFER, 2);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_swap_channel);
+
+uint32_t bytes_per_pixel(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_GENERIC:	/*generic data */
+	case IPU_PIX_FMT_RGB332:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV422P:
+		return 1;
+		break;
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+		return 2;
+		break;
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+		return 3;
+		break;
+	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;
+		break;
+	default:
+		return 1;
+		break;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(bytes_per_pixel);
+
+ipu_color_space_t format_to_colorspace(uint32_t 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_GBR24:
+	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;
+		break;
+
+	default:
+		return YCbCr;
+		break;
+	}
+	return RGB;
+}
+
+bool ipu_pixel_format_has_alpha(uint32_t fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_ABGR32:
+		return true;
+		break;
+	default:
+		return false;
+		break;
+	}
+	return false;
+}
+
+static int ipu_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	if (ipu->ipu_use_count) {
+		/* save and disable enabled channels*/
+		ipu->idma_enable_reg[0] = ipu_idmac_read(ipu, IDMAC_CHA_EN(0));
+		ipu->idma_enable_reg[1] = ipu_idmac_read(ipu, IDMAC_CHA_EN(32));
+		while ((ipu_idmac_read(ipu, IDMAC_CHA_BUSY(0))
+			& ipu->idma_enable_reg[0])
+			|| (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(32))
+			& ipu->idma_enable_reg[1])) {
+			/* disable channel not busy already */
+			uint32_t chan_should_disable, timeout = 1000, time = 0;
+
+			chan_should_disable =
+				ipu_idmac_read(ipu, IDMAC_CHA_BUSY(0))
+					^ ipu->idma_enable_reg[0];
+			ipu_idmac_write(ipu, (~chan_should_disable) &
+					ipu->idma_enable_reg[0], IDMAC_CHA_EN(0));
+			chan_should_disable =
+				ipu_idmac_read(ipu, IDMAC_CHA_BUSY(1))
+					^ ipu->idma_enable_reg[1];
+			ipu_idmac_write(ipu, (~chan_should_disable) &
+					ipu->idma_enable_reg[1], IDMAC_CHA_EN(32));
+			msleep(2);
+			time += 2;
+			if (time >= timeout)
+				return -1;
+		}
+		ipu_idmac_write(ipu, 0, IDMAC_CHA_EN(0));
+		ipu_idmac_write(ipu, 0, IDMAC_CHA_EN(32));
+
+		/* save double buffer select regs */
+		ipu->cha_db_mode_reg[0] = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(0));
+		ipu->cha_db_mode_reg[1] = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(32));
+		ipu->cha_db_mode_reg[2] =
+			ipu_cm_read(ipu, IPU_ALT_CHA_DB_MODE_SEL(0));
+		ipu->cha_db_mode_reg[3] =
+			ipu_cm_read(ipu, IPU_ALT_CHA_DB_MODE_SEL(32));
+
+		/* save triple buffer select regs */
+		ipu->cha_trb_mode_reg[0] = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(0));
+		ipu->cha_trb_mode_reg[1] = ipu_cm_read(ipu, IPU_CHA_TRB_MODE_SEL(32));
+
+		/* save idamc sub addr regs */
+		ipu->idma_sub_addr_reg[0] = ipu_idmac_read(ipu, IDMAC_SUB_ADDR_0);
+		ipu->idma_sub_addr_reg[1] = ipu_idmac_read(ipu, IDMAC_SUB_ADDR_1);
+		ipu->idma_sub_addr_reg[2] = ipu_idmac_read(ipu, IDMAC_SUB_ADDR_2);
+		ipu->idma_sub_addr_reg[3] = ipu_idmac_read(ipu, IDMAC_SUB_ADDR_3);
+		ipu->idma_sub_addr_reg[4] = ipu_idmac_read(ipu, IDMAC_SUB_ADDR_4);
+
+		/* save sub-modules status and disable all */
+		ipu->ic_conf_reg = ipu_ic_read(ipu, IC_CONF);
+		ipu_ic_write(ipu, 0, IC_CONF);
+		ipu->ipu_conf_reg = ipu_cm_read(ipu, IPU_CONF);
+		ipu_cm_write(ipu, 0, IPU_CONF);
+
+		/* save buf ready regs */
+		ipu->buf_ready_reg[0] = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(0));
+		ipu->buf_ready_reg[1] = ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(32));
+		ipu->buf_ready_reg[2] = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(0));
+		ipu->buf_ready_reg[3] = ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(32));
+		ipu->buf_ready_reg[4] = ipu_cm_read(ipu, IPU_ALT_CHA_BUF0_RDY(0));
+		ipu->buf_ready_reg[5] = ipu_cm_read(ipu, IPU_ALT_CHA_BUF0_RDY(32));
+		ipu->buf_ready_reg[6] = ipu_cm_read(ipu, IPU_ALT_CHA_BUF1_RDY(0));
+		ipu->buf_ready_reg[7] = ipu_cm_read(ipu, IPU_ALT_CHA_BUF1_RDY(32));
+		ipu->buf_ready_reg[8] = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(0));
+		ipu->buf_ready_reg[9] = ipu_cm_read(ipu, IPU_CHA_BUF2_RDY(32));
+	}
+
+	if (plat_data->pg)
+		plat_data->pg(1);
+
+	return 0;
+}
+
+static int ipu_resume(struct platform_device *pdev)
+{
+	struct imx_ipuv3_platform_data *plat_data = pdev->dev.platform_data;
+	struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+	if (plat_data->pg)
+		plat_data->pg(0);
+
+	if (ipu->ipu_use_count) {
+
+		/* restore buf ready regs */
+		ipu_cm_write(ipu, ipu->buf_ready_reg[0], IPU_CHA_BUF0_RDY(0));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[1], IPU_CHA_BUF0_RDY(32));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[2], IPU_CHA_BUF1_RDY(0));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[3], IPU_CHA_BUF1_RDY(32));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[4], IPU_ALT_CHA_BUF0_RDY(0));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[5], IPU_ALT_CHA_BUF0_RDY(32));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[6], IPU_ALT_CHA_BUF1_RDY(0));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[7], IPU_ALT_CHA_BUF1_RDY(32));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[8], IPU_CHA_BUF2_RDY(0));
+		ipu_cm_write(ipu, ipu->buf_ready_reg[9], IPU_CHA_BUF2_RDY(32));
+
+		/* re-enable sub-modules*/
+		ipu_cm_write(ipu, ipu->ipu_conf_reg, IPU_CONF);
+		ipu_ic_write(ipu, ipu->ic_conf_reg, IC_CONF);
+
+		/* restore double buffer select regs */
+		ipu_cm_write(ipu, ipu->cha_db_mode_reg[0], IPU_CHA_DB_MODE_SEL(0));
+		ipu_cm_write(ipu, ipu->cha_db_mode_reg[1], IPU_CHA_DB_MODE_SEL(32));
+		ipu_cm_write(ipu, ipu->cha_db_mode_reg[2],
+				IPU_ALT_CHA_DB_MODE_SEL(0));
+		ipu_cm_write(ipu, ipu->cha_db_mode_reg[3],
+				IPU_ALT_CHA_DB_MODE_SEL(32));
+
+		/* restore triple buffer select regs */
+		ipu_cm_write(ipu, ipu->cha_trb_mode_reg[0], IPU_CHA_TRB_MODE_SEL(0));
+		ipu_cm_write(ipu, ipu->cha_trb_mode_reg[1], IPU_CHA_TRB_MODE_SEL(32));
+
+		/* restore idamc sub addr regs */
+		ipu_idmac_write(ipu, ipu->idma_sub_addr_reg[0], IDMAC_SUB_ADDR_0);
+		ipu_idmac_write(ipu, ipu->idma_sub_addr_reg[1], IDMAC_SUB_ADDR_1);
+		ipu_idmac_write(ipu, ipu->idma_sub_addr_reg[2], IDMAC_SUB_ADDR_2);
+		ipu_idmac_write(ipu, ipu->idma_sub_addr_reg[3], IDMAC_SUB_ADDR_3);
+		ipu_idmac_write(ipu, ipu->idma_sub_addr_reg[4], IDMAC_SUB_ADDR_4);
+
+		/* restart idma channel*/
+		ipu_idmac_write(ipu, ipu->idma_enable_reg[0], IDMAC_CHA_EN(0));
+		ipu_idmac_write(ipu, ipu->idma_enable_reg[1], IDMAC_CHA_EN(32));
+	} else {
+		_ipu_get(ipu);
+		_ipu_dmfc_init(ipu, dmfc_type_setup, 1);
+		_ipu_init_dc_mappings(ipu);
+		/* Set sync refresh channels as high priority */
+		ipu_idmac_write(ipu, 0x18800001L, IDMAC_CHA_PRI(0));
+		_ipu_put(ipu);
+	}
+
+	return 0;
+}
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcipu_driver = {
+	.driver = {
+		   .name = "imx-ipuv3",
+		   },
+	.probe = ipu_probe,
+	.remove = ipu_remove,
+	.suspend = ipu_suspend,
+	.resume = ipu_resume,
+};
+
+int32_t __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);
diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c
new file mode 100644
index 0000000..c00f0df
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_device.c
@@ -0,0 +1,2109 @@
+/*
+ * Copyright 2005-2011 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
+ */
+
+/*!
+ * @file ipu_device.c
+ *
+ * @brief This file contains the IPUv3 driver device interface and fops functions.
+ *
+ * @ingroup IPU
+ */
+#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/clk.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/kthread.h>
+#include <asm/cacheflush.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+#include "ipu_param_mem.h"
+
+/* Strucutures and variables for exporting MXC IPU as device*/
+typedef enum {
+	RGB_CS,
+	YUV_CS,
+	NULL_CS
+} cs_t;
+
+typedef enum {
+	STATE_OK = 0,
+	STATE_NO_IPU,
+	STATE_NO_IRQ,
+	STATE_IRQ_FAIL,
+	STATE_IRQ_TIMEOUT,
+	STATE_INIT_CHAN_FAIL,
+	STATE_LINK_CHAN_FAIL,
+	STATE_INIT_CHAN_BUF_FAIL,
+} ipu_state_t;
+
+struct ipu_state_msg {
+	int state;
+	char *msg;
+} state_msg[] = {
+	{STATE_OK, "ok"},
+	{STATE_NO_IPU, "no ipu found"},
+	{STATE_NO_IRQ, "no irq found for task"},
+	{STATE_IRQ_FAIL, "request irq failed"},
+	{STATE_IRQ_TIMEOUT, "wait for irq timeout"},
+	{STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
+	{STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
+	{STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+};
+
+struct stripe_setting {
+	u32 iw;
+	u32 ih;
+	u32 ow;
+	u32 oh;
+	u32 outh_resize_ratio;
+	u32 outv_resize_ratio;
+	u32 i_left_pos;
+	u32 i_right_pos;
+	u32 i_top_pos;
+	u32 i_bottom_pos;
+	u32 o_left_pos;
+	u32 o_right_pos;
+	u32 o_top_pos;
+	u32 o_bottom_pos;
+};
+
+struct task_set {
+#define	NULL_MODE	0x0
+#define	IC_MODE		0x1
+#define	ROT_MODE	0x2
+#define	VDI_MODE	0x4
+	u8	mode;
+#define IC_VF	0x1
+#define IC_PP	0x2
+#define ROT_VF	0x4
+#define ROT_PP	0x8
+#define VDI_VF	0x10
+	u8	task;
+
+	ipu_channel_t ic_chan;
+	ipu_channel_t rot_chan;
+	ipu_channel_t vdi_ic_p_chan;
+	ipu_channel_t vdi_ic_n_chan;
+
+	u32 i_off;
+	u32 i_uoff;
+	u32 i_voff;
+	u32 istride;
+
+	u32 ov_off;
+	u32 ov_uoff;
+	u32 ov_voff;
+	u32 ovstride;
+
+	u32 ov_alpha_off;
+	u32 ov_alpha_stride;
+
+	u32 o_off;
+	u32 o_uoff;
+	u32 o_voff;
+	u32 ostride;
+
+	u32 r_fmt;
+	u32 r_width;
+	u32 r_height;
+	u32 r_stride;
+	dma_addr_t r_paddr;
+
+#define NO_SPLIT	0x0
+#define RL_SPLIT	0x1
+#define UD_SPLIT	0x2
+#define LEFT_STRIPE	0x1
+#define RIGHT_STRIPE	0x2
+#define UP_STRIPE	0x4
+#define DOWN_STRIPE	0x8
+	u8 split_mode;
+	struct stripe_setting sp_setting;
+};
+
+struct ipu_split_task {
+	struct ipu_task task;
+	struct ipu_task_entry *parent_task;
+	struct task_struct *thread;
+	bool could_finish;
+	wait_queue_head_t waitq;
+	int ret;
+};
+
+struct ipu_task_entry {
+	struct ipu_input input;
+	struct ipu_output output;
+
+	bool overlay_en;
+	struct ipu_overlay overlay;
+
+	u8	priority;
+	u8	task_id;
+#define DEF_TIMEOUT_MS	1000
+	int	timeout;
+
+	struct list_head node;
+	struct device *dev;
+	struct task_set set;
+	struct completion comp;
+	ipu_state_t state;
+};
+
+struct ipu_alloc_list {
+	struct list_head list;
+	dma_addr_t phy_addr;
+	void *cpu_addr;
+	u32 size;
+};
+LIST_HEAD(ipu_alloc_list);
+
+static int major;
+static struct class *ipu_class;
+static struct device *ipu_dev;
+
+int ipu_queue_sp_task(struct ipu_split_task *sp_task);
+
+static bool deinterlace_3_field(struct ipu_task_entry *t)
+{
+	return ((t->set.mode & VDI_MODE) &&
+		(t->input.deinterlace.motion != HIGH_MOTION));
+}
+
+static u32 fmt_to_bpp(u32 pixelformat)
+{
+	u32 bpp;
+
+	switch (pixelformat) {
+	case IPU_PIX_FMT_RGB565:
+	/*interleaved 422*/
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_UYVY:
+	/*non-interleaved 422*/
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YVU422P:
+		bpp = 16;
+		break;
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+		bpp = 24;
+		break;
+	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:
+		bpp = 32;
+		break;
+	/*non-interleaved 420*/
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_NV12:
+		bpp = 12;
+		break;
+	default:
+		bpp = 8;
+		break;
+	}
+	return bpp;
+}
+
+static cs_t colorspaceofpixel(int fmt)
+{
+	switch (fmt) {
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_ABGR32:
+		return RGB_CS;
+		break;
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_YUYV:
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+	case IPU_PIX_FMT_YVU420P:
+	case IPU_PIX_FMT_YVU422P:
+	case IPU_PIX_FMT_YUV422P:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_NV12:
+		return YUV_CS;
+		break;
+	default:
+		return NULL_CS;
+	}
+}
+
+static int need_csc(int ifmt, int ofmt)
+{
+	cs_t ics, ocs;
+
+	ics = colorspaceofpixel(ifmt);
+	ocs = colorspaceofpixel(ofmt);
+
+	if ((ics == NULL_CS) || (ocs == NULL_CS))
+		return -1;
+	else if (ics != ocs)
+		return 1;
+
+	return 0;
+}
+
+static int soc_max_in_width(void)
+{
+	return 4096;
+}
+
+static int soc_max_in_height(void)
+{
+	return 4096;
+}
+
+static int soc_max_out_width(void)
+{
+	/* mx51/mx53/mx6q is 1024*/
+	return 1024;
+}
+
+static int soc_max_out_height(void)
+{
+	/* mx51/mx53/mx6q is 1024*/
+	return 1024;
+}
+
+static int list_size(struct list_head *head)
+{
+	struct list_head *p, *n;
+	int size = 0;
+
+	list_for_each_safe(p, n, head)
+		size++;
+
+	return size;
+}
+
+static int get_task_size(struct ipu_soc *ipu, int id)
+{
+	struct list_head *task_list;
+
+	if (id == IPU_TASK_ID_VF)
+		task_list = &ipu->task_list[0];
+	else if (id == IPU_TASK_ID_PP)
+		task_list = &ipu->task_list[1];
+	else {
+		printk(KERN_ERR "query error task id\n");
+		return -EINVAL;
+	}
+
+	return list_size(task_list);
+}
+
+static struct ipu_soc *most_free_ipu_task(struct ipu_task_entry *t)
+{
+	unsigned int task_num[2][2] = {
+		{0xffffffff, 0xffffffff},
+		{0xffffffff, 0xffffffff} };
+	struct ipu_soc *ipu;
+	int ipu_idx, task_id;
+	int i;
+
+	/* decide task_id */
+	if (t->task_id >= IPU_TASK_ID_MAX)
+		t->task_id %= IPU_TASK_ID_MAX;
+	/* must use task_id VF for VDI task*/
+	if ((t->set.mode & VDI_MODE) &&
+		(t->task_id != IPU_TASK_ID_VF))
+		t->task_id = IPU_TASK_ID_VF;
+
+	for (i = 0; i < MXC_IPU_MAX_NUM; i++) {
+		ipu = ipu_get_soc(i);
+		if (!IS_ERR(ipu)) {
+			task_num[i][0] = get_task_size(ipu, IPU_TASK_ID_VF);
+			task_num[i][1] = get_task_size(ipu, IPU_TASK_ID_PP);
+		}
+	}
+
+	task_id = t->task_id;
+	if (t->task_id == IPU_TASK_ID_VF) {
+		if (task_num[0][0] < task_num[1][0])
+			ipu_idx = 0;
+		else
+			ipu_idx = 1;
+	} else if (t->task_id == IPU_TASK_ID_PP) {
+		if (task_num[0][1] < task_num[1][1])
+			ipu_idx = 0;
+		else
+			ipu_idx = 1;
+	} else {
+		unsigned int min;
+		ipu_idx = 0;
+		task_id = IPU_TASK_ID_VF;
+		min = task_num[0][0];
+		if (task_num[0][1] < min) {
+			min = task_num[0][1];
+			task_id = IPU_TASK_ID_PP;
+		}
+		if (task_num[1][0] < min) {
+			min = task_num[1][0];
+			ipu_idx = 1;
+			task_id = IPU_TASK_ID_VF;
+		}
+		if (task_num[1][1] < min) {
+			ipu_idx = 1;
+			task_id = IPU_TASK_ID_PP;
+		}
+	}
+
+	t->task_id = task_id;
+	ipu = ipu_get_soc(ipu_idx);
+
+	return ipu;
+}
+
+static void dump_task_info(struct ipu_task_entry *t)
+{
+	dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
+	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
+	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
+	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
+	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+			(void *)t, t->input.crop.pos.x);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+			(void *)t, t->input.crop.pos.y);
+	dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
+	dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
+	dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
+	dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
+	dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
+	if (t->input.deinterlace.enable) {
+		dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
+		if (t->input.deinterlace.motion != HIGH_MOTION) {
+			dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
+			dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
+				(void *)t, t->input.paddr_n);
+		} else
+			dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
+	}
+
+	dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
+	dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
+	dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
+	dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
+	dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+			(void *)t, t->output.crop.pos.x);
+	dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+			(void *)t, t->output.crop.pos.y);
+	dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
+	dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
+	dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
+	dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
+	dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
+	dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
+	dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
+
+	if (t->overlay_en) {
+		dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
+				(void *)t, t->overlay.format);
+		dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
+				(void *)t, t->overlay.width);
+		dev_dbg(t->dev, "[0x%p]\theight = %d\n",
+				(void *)t, t->overlay.height);
+		dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
+				(void *)t, t->overlay.crop.w);
+		dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
+				(void *)t, t->overlay.crop.h);
+		dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+				(void *)t, t->overlay.crop.pos.x);
+		dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+				(void *)t, t->overlay.crop.pos.y);
+		dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+				(void *)t, t->overlay.paddr);
+		dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
+				(void *)t, t->set.ov_off);
+		dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
+				(void *)t, t->set.ov_uoff);
+		dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
+				(void *)t, t->set.ov_voff);
+		dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
+				(void *)t, t->set.ovstride);
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+			dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
+					(void *)t);
+			dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+					(void *)t, t->overlay.alpha.loc_alp_paddr);
+			dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
+					(void *)t, t->set.ov_alpha_off);
+			dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
+					(void *)t, t->set.ov_alpha_stride);
+		} else
+			dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
+					(void *)t, t->overlay.alpha.gvalue);
+		if (t->overlay.colorkey.enable)
+			dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
+					(void *)t, t->overlay.colorkey.value);
+	}
+
+	dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
+	dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
+				(void *)t, t->set.mode);
+	dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
+	dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
+	dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
+}
+
+static void dump_check_err(struct device *dev, int err)
+{
+	switch (err) {
+	case IPU_CHECK_ERR_INPUT_CROP:
+		dev_err(dev, "input crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_OUTPUT_CROP:
+		dev_err(dev, "output crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_OVERLAY_CROP:
+		dev_err(dev, "overlay crop setting error\n");
+		break;
+	case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
+		dev_err(dev, "input over limitation\n");
+		break;
+	case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
+		dev_err(dev, "do not support overlay with deinterlace\n");
+		break;
+	case IPU_CHECK_ERR_OV_OUT_NO_FIT:
+		dev_err(dev,
+			"width/height of overlay and ic output should be same\n");
+		break;
+	case IPU_CHECK_ERR_PROC_NO_NEED:
+		dev_err(dev, "no ipu processing need\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
+		dev_err(dev, "split mode input width overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
+		dev_err(dev, "split mode input height overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
+		dev_err(dev, "split mode output width overflow\n");
+		break;
+	case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
+		dev_err(dev, "split mode output height overflow\n");
+		break;
+	default:
+		break;
+	}
+}
+
+static void dump_check_warn(struct device *dev, int warn)
+{
+	if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
+		dev_warn(dev, "input u/v offset not 8 align\n");
+	if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
+		dev_warn(dev, "output u/v offset not 8 align\n");
+	if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
+		dev_warn(dev, "overlay u/v offset not 8 align\n");
+}
+
+static int set_crop(struct ipu_crop *crop, int width, int height)
+{
+	if (crop->w || crop->h) {
+		if (((crop->w + crop->pos.x) > width)
+		|| ((crop->h + crop->pos.y) > height))
+			return -EINVAL;
+	} else {
+		crop->pos.x = 0;
+		crop->pos.y = 0;
+		crop->w = width;
+		crop->h = height;
+	}
+	crop->w -= crop->w%8;
+	crop->h -= crop->h%8;
+
+	return 0;
+}
+
+static void update_offset(unsigned int fmt,
+				unsigned int width, unsigned int height,
+				unsigned int pos_x, unsigned int pos_y,
+				int *off, int *uoff, int *voff, int *stride)
+{
+	/* NOTE: u v offset should based on start point of off*/
+	switch (fmt) {
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ ((width/2 * pos_y/2) + pos_x/2);
+		*voff = *uoff + (width/2 * height/2);
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		*off = pos_y * width + pos_x;
+		*voff = (width * (height - pos_y) - pos_x)
+			+ ((width/2 * pos_y/2) + pos_x/2);
+		*uoff = *voff + (width/2 * height/2);
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		*off = pos_y * width + pos_x;
+		*voff = (width * (height - pos_y) - pos_x)
+			+ ((width * pos_y)/2 + pos_x/2);
+		*uoff = *voff + (width * height)/2;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ (width * pos_y)/2 + pos_x/2;
+		*voff = *uoff + (width * height)/2;
+		break;
+	case IPU_PIX_FMT_NV12:
+		*off = pos_y * width + pos_x;
+		*uoff = (width * (height - pos_y) - pos_x)
+			+ width * pos_y/2 + pos_x;
+		break;
+	default:
+		*off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
+		break;
+	}
+	*stride = width * bytes_per_pixel(fmt);
+}
+
+static int update_split_setting(struct ipu_task_entry *t)
+{
+	struct stripe_param left_stripe;
+	struct stripe_param right_stripe;
+	struct stripe_param up_stripe;
+	struct stripe_param down_stripe;
+	u32 iw, ih, ow, oh;
+
+	iw = t->input.crop.w;
+	ih = t->input.crop.h;
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		ow = t->output.crop.h;
+		oh = t->output.crop.w;
+	} else {
+		ow = t->output.crop.w;
+		oh = t->output.crop.h;
+	}
+
+	if (t->set.split_mode & RL_SPLIT) {
+		ipu_calc_stripes_sizes(iw,
+				ow,
+				soc_max_out_width(),
+				(((unsigned long long)1) << 32), /* 32bit for fractional*/
+				1, /* equal stripes */
+				t->input.format,
+				t->output.format,
+				&left_stripe,
+				&right_stripe);
+		t->set.sp_setting.iw = left_stripe.input_width;
+		t->set.sp_setting.ow = left_stripe.output_width;
+		t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
+		t->set.sp_setting.i_left_pos = left_stripe.input_column;
+		t->set.sp_setting.o_left_pos = left_stripe.output_column;
+		t->set.sp_setting.i_right_pos = right_stripe.input_column;
+		t->set.sp_setting.o_right_pos = right_stripe.output_column;
+	} else {
+		t->set.sp_setting.iw = iw;
+		t->set.sp_setting.ow = ow;
+		t->set.sp_setting.outh_resize_ratio = 0;
+		t->set.sp_setting.i_left_pos = 0;
+		t->set.sp_setting.o_left_pos = 0;
+		t->set.sp_setting.i_right_pos = 0;
+		t->set.sp_setting.o_right_pos = 0;
+	}
+	if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > iw)
+		return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
+	if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
+		|| (t->set.sp_setting.ow > soc_max_out_width()))
+		return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
+
+	if (t->set.split_mode & UD_SPLIT) {
+		ipu_calc_stripes_sizes(ih,
+				oh,
+				soc_max_out_height(),
+				(((unsigned long long)1) << 32), /* 32bit for fractional*/
+				1, /* equal stripes */
+				t->input.format,
+				t->output.format,
+				&up_stripe,
+				&down_stripe);
+		t->set.sp_setting.ih = up_stripe.input_width;
+		t->set.sp_setting.oh = up_stripe.output_width;
+		t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
+		t->set.sp_setting.i_top_pos = up_stripe.input_column;
+		t->set.sp_setting.o_top_pos = up_stripe.output_column;
+		t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
+		t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
+	} else {
+		t->set.sp_setting.ih = ih;
+		t->set.sp_setting.oh = oh;
+		t->set.sp_setting.outv_resize_ratio = 0;
+		t->set.sp_setting.i_top_pos = 0;
+		t->set.sp_setting.o_top_pos = 0;
+		t->set.sp_setting.i_bottom_pos = 0;
+		t->set.sp_setting.o_bottom_pos = 0;
+	}
+	if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > ih)
+		return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+	if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
+		|| (t->set.sp_setting.oh > soc_max_out_height()))
+		return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
+
+	return IPU_CHECK_OK;
+}
+
+static int check_task(struct ipu_task_entry *t)
+{
+	int tmp;
+	int ret = IPU_CHECK_OK;
+
+	/* check input */
+	ret = set_crop(&t->input.crop, t->input.width, t->input.height);
+	if (ret < 0) {
+		ret = IPU_CHECK_ERR_INPUT_CROP;
+		goto done;
+	} else
+		update_offset(t->input.format, t->input.width, t->input.height,
+				t->input.crop.pos.x, t->input.crop.pos.y,
+				&t->set.i_off, &t->set.i_uoff,
+				&t->set.i_voff, &t->set.istride);
+
+	/* check output */
+	ret = set_crop(&t->output.crop, t->output.width, t->output.height);
+	if (ret < 0) {
+		ret = IPU_CHECK_ERR_OUTPUT_CROP;
+		goto done;
+	} else
+		update_offset(t->output.format,
+				t->output.width, t->output.height,
+				t->output.crop.pos.x, t->output.crop.pos.y,
+				&t->set.o_off, &t->set.o_uoff,
+				&t->set.o_voff, &t->set.ostride);
+
+	/* check overlay if there is */
+	if (t->overlay_en) {
+		if (t->input.deinterlace.enable) {
+			ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
+			goto done;
+		}
+		ret = set_crop(&t->overlay.crop, t->overlay.width, t->overlay.height);
+		if (ret < 0) {
+			ret = IPU_CHECK_ERR_OVERLAY_CROP;
+			goto done;
+		} else {
+			int ow = t->output.crop.w;
+			int oh = t->output.crop.h;
+
+			if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+				ow = t->output.crop.h;
+				oh = t->output.crop.w;
+			}
+			if ((t->overlay.crop.w != ow) || (t->overlay.crop.h != oh)) {
+				ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
+				goto done;
+			}
+
+			update_offset(t->overlay.format,
+					t->overlay.width, t->overlay.height,
+					t->overlay.crop.pos.x, t->overlay.crop.pos.y,
+					&t->set.ov_off, &t->set.ov_uoff,
+					&t->set.ov_voff, &t->set.ovstride);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+				t->set.ov_alpha_stride = t->overlay.width;
+				t->set.ov_alpha_off = t->overlay.crop.pos.y *
+					t->overlay.width + t->overlay.crop.pos.x;
+			}
+		}
+	}
+
+	/* input overflow? */
+	if ((t->input.crop.w > soc_max_in_width()) ||
+		(t->input.crop.h > soc_max_in_height())) {
+		ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+		goto done;
+	}
+
+	/* check task mode */
+	t->set.mode = NULL_MODE;
+	t->set.split_mode = NO_SPLIT;
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		/*output swap*/
+		tmp = t->output.crop.w;
+		t->output.crop.w = t->output.crop.h;
+		t->output.crop.h = tmp;
+	}
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+		t->set.mode |= ROT_MODE;
+
+	/*need resize or CSC?*/
+	if ((t->input.crop.w != t->output.crop.w) ||
+			(t->input.crop.h != t->output.crop.h) ||
+			need_csc(t->input.format, t->output.format))
+		t->set.mode |= IC_MODE;
+
+	/*need flip?*/
+	if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
+		t->set.mode |= IC_MODE;
+
+	/*need IDMAC do format(same color space)?*/
+	if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
+		t->set.mode |= IC_MODE;
+
+	/*overlay support*/
+	if (t->overlay_en)
+		t->set.mode |= IC_MODE;
+
+	/*deinterlace*/
+	if (t->input.deinterlace.enable) {
+		t->set.mode &= ~IC_MODE;
+		t->set.mode |= VDI_MODE;
+	}
+
+	if (t->set.mode & (IC_MODE | VDI_MODE)) {
+		if (t->output.crop.w > soc_max_out_width())
+			t->set.split_mode |= RL_SPLIT;
+		if (t->output.crop.h > soc_max_out_height())
+			t->set.split_mode |= UD_SPLIT;
+		ret = update_split_setting(t);
+		if (ret > IPU_CHECK_ERR_MIN)
+			goto done;
+	}
+
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		/*output swap*/
+		tmp = t->output.crop.w;
+		t->output.crop.w = t->output.crop.h;
+		t->output.crop.h = tmp;
+	}
+
+	if (t->set.mode == NULL_MODE) {
+		ret = IPU_CHECK_ERR_PROC_NO_NEED;
+		goto done;
+	}
+
+	if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
+		ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
+	if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
+		ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
+	if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
+		ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
+
+done:
+	/* dump msg */
+	if (ret > IPU_CHECK_ERR_MIN)
+		dump_check_err(t->dev, ret);
+	else if (ret != IPU_CHECK_OK)
+		dump_check_warn(t->dev, ret);
+
+	return ret;
+}
+
+static int prepare_task(struct ipu_task_entry *t)
+{
+	int ret = 0;
+
+	ret = check_task(t);
+	if (ret > IPU_CHECK_ERR_MIN)
+		return -EINVAL;
+
+	dump_task_info(t);
+
+	return ret;
+}
+
+/* should call from a process context */
+static int queue_task(struct ipu_task_entry *t)
+{
+	int ret = 0;
+	struct ipu_soc *ipu;
+	struct list_head *task_list = NULL;
+	struct mutex *task_lock = NULL;
+	wait_queue_head_t *waitq = NULL;
+
+	ipu = most_free_ipu_task(t);
+	t->dev = ipu->dev;
+
+	dev_dbg(t->dev, "[0x%p]Queue task: id %d\n", (void *)t, t->task_id);
+
+	init_completion(&t->comp);
+
+	t->set.task = 0;
+	switch (t->task_id) {
+	case IPU_TASK_ID_VF:
+		task_list = &ipu->task_list[0];
+		task_lock = &ipu->task_lock[0];
+		waitq = &ipu->waitq[0];
+		if (t->set.mode & IC_MODE)
+			t->set.task |= IC_VF;
+		else if (t->set.mode & VDI_MODE)
+			t->set.task |= VDI_VF;
+		if (t->set.mode & ROT_MODE)
+			t->set.task |= ROT_VF;
+		break;
+	case IPU_TASK_ID_PP:
+		task_list = &ipu->task_list[1];
+		task_lock = &ipu->task_lock[1];
+		waitq = &ipu->waitq[1];
+		if (t->set.mode & IC_MODE)
+			t->set.task |= IC_PP;
+		if (t->set.mode & ROT_MODE)
+			t->set.task |= ROT_PP;
+		break;
+	default:
+		dev_err(t->dev, "[0x%p]should never come here\n", (void *)t);
+	}
+
+	dev_dbg(t->dev, "[0x%p]choose task_id[%d] mode[0x%x]\n",
+			(void *)t, t->task_id, t->set.task);
+	dev_dbg(t->dev, "[0x%p]\tIPU_TASK_ID_VF = %d\n",
+				(void *)t, IPU_TASK_ID_VF);
+	dev_dbg(t->dev, "[0x%p]\tIPU_TASK_ID_PP = %d\n",
+				(void *)t, IPU_TASK_ID_PP);
+	dev_dbg(t->dev, "[0x%p]\tIC_VF = 0x%x\n", (void *)t, IC_VF);
+	dev_dbg(t->dev, "[0x%p]\tIC_PP = 0x%x\n", (void *)t, IC_PP);
+	dev_dbg(t->dev, "[0x%p]\tROT_VF = 0x%x\n", (void *)t, ROT_VF);
+	dev_dbg(t->dev, "[0x%p]\tROT_PP = 0x%x\n", (void *)t, ROT_PP);
+	dev_dbg(t->dev, "[0x%p]\tVDI_VF = 0x%x\n", (void *)t, VDI_VF);
+
+	/* add and wait task */
+	mutex_lock(task_lock);
+	list_add_tail(&t->node, task_list);
+	mutex_unlock(task_lock);
+
+	wake_up_interruptible(waitq);
+
+	wait_for_completion(&t->comp);
+
+	dev_dbg(t->dev, "[0x%p]Queue task finished\n", (void *)t);
+
+	if (t->state != STATE_OK) {
+		dev_err(t->dev, "[0x%p]state %d: %s\n",
+			(void *)t, t->state, state_msg[t->state].msg);
+		ret = -ECANCELED;
+	}
+
+	return ret;
+}
+
+static bool need_split(struct ipu_task_entry *t)
+{
+	return (t->set.split_mode != NO_SPLIT);
+}
+
+static int split_task_thread(void *data)
+{
+	struct ipu_split_task *t = data;
+
+	t->ret = ipu_queue_sp_task(t);
+
+	while (!kthread_should_stop())
+		wait_event_interruptible(t->waitq, t->could_finish);
+
+	return 0;
+}
+
+static int create_split_task(
+		int stripe,
+		struct ipu_split_task *sp_task)
+{
+	struct ipu_task *task = &(sp_task->task);
+	struct ipu_task_entry *t = sp_task->parent_task;
+
+	task->input = t->input;
+	task->output = t->output;
+	task->overlay_en = t->overlay_en;
+	if (task->overlay_en)
+		task->overlay = t->overlay;
+	task->priority = t->priority;
+	task->task_id = t->task_id;
+	task->timeout = t->timeout;
+
+	task->input.crop.w = t->set.sp_setting.iw;
+	task->input.crop.h = t->set.sp_setting.ih;
+	if (task->overlay_en) {
+		task->overlay.crop.w = t->set.sp_setting.ow;
+		task->overlay.crop.h = t->set.sp_setting.oh;
+	}
+	if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+		task->output.crop.w = t->set.sp_setting.oh;
+		task->output.crop.h = t->set.sp_setting.ow;
+	} else {
+		task->output.crop.w = t->set.sp_setting.ow;
+		task->output.crop.h = t->set.sp_setting.oh;
+	}
+
+	if (stripe & LEFT_STRIPE)
+		task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
+	else if (stripe & RIGHT_STRIPE)
+		task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
+	if (stripe & UP_STRIPE)
+		task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
+	else if (stripe & DOWN_STRIPE)
+		task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
+
+	if (task->overlay_en) {
+		if (stripe & LEFT_STRIPE)
+			task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+	}
+
+	switch (t->output.rotate) {
+	case IPU_ROTATE_NONE:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+		break;
+	case IPU_ROTATE_VERT_FLIP:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		break;
+	case IPU_ROTATE_HORIZ_FLIP:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+		break;
+	case IPU_ROTATE_180:
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		break;
+	case IPU_ROTATE_90_RIGHT:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+		break;
+	case IPU_ROTATE_90_RIGHT_HFLIP:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+		break;
+	case IPU_ROTATE_90_RIGHT_VFLIP:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x =
+					t->output.crop.pos.x + t->output.crop.w
+					- t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		break;
+	case IPU_ROTATE_90_LEFT:
+		if (stripe & UP_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+		else if (stripe & DOWN_STRIPE)
+			task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+		if (stripe & LEFT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+		else if (stripe & RIGHT_STRIPE)
+			task->output.crop.pos.y =
+					t->output.crop.pos.y + t->output.crop.h
+					- t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+		break;
+	default:
+		dev_err(t->dev, "should not be here\n");
+		break;
+	}
+
+	sp_task->thread = kthread_run(split_task_thread, sp_task,
+					"ipu_split_task");
+	if (IS_ERR(sp_task->thread)) {
+		dev_err(t->dev, "split thread can not create\n");
+		return PTR_ERR(sp_task->thread);
+	}
+
+	return 0;
+}
+
+static int queue_split_task(struct ipu_task_entry *t)
+{
+	struct ipu_split_task sp_task[4];
+	int i, ret = 0, size;
+
+	dev_dbg(t->dev, "Split task 0x%p\n", (void *)t);
+
+	if ((t->set.split_mode == RL_SPLIT) || (t->set.split_mode == UD_SPLIT))
+		size = 2;
+	else
+		size = 4;
+
+	for (i = 0; i < size; i++) {
+		memset(&sp_task[i], 0, sizeof(struct ipu_split_task));
+		init_waitqueue_head(&(sp_task[i].waitq));
+		sp_task[i].could_finish = false;
+		sp_task[i].parent_task = t;
+	}
+
+	if (t->set.split_mode == RL_SPLIT) {
+		create_split_task(LEFT_STRIPE, &sp_task[0]);
+		create_split_task(RIGHT_STRIPE, &sp_task[1]);
+	} else if (t->set.split_mode == UD_SPLIT) {
+		create_split_task(UP_STRIPE, &sp_task[0]);
+		create_split_task(DOWN_STRIPE, &sp_task[1]);
+	} else {
+		create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[0]);
+		create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[1]);
+		create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[2]);
+		create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[3]);
+	}
+
+	for (i = 0; i < size; i++) {
+		sp_task[i].could_finish = true;
+		wake_up_interruptible(&sp_task[i].waitq);
+		kthread_stop(sp_task[i].thread);
+		if (sp_task[i].ret < 0) {
+			ret = sp_task[i].ret;
+			dev_err(t->dev,
+				"split task %d fail with ret %d\n",
+				i, ret);
+		}
+	}
+
+	return ret;
+}
+
+static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+
+	tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
+	if (!tsk)
+		return ERR_PTR(-ENOMEM);
+
+	tsk->dev = ipu_dev;
+	tsk->input = task->input;
+	tsk->output = task->output;
+	tsk->overlay_en = task->overlay_en;
+	if (tsk->overlay_en)
+		tsk->overlay = task->overlay;
+	tsk->priority = task->priority;
+	tsk->task_id = task->task_id;
+	if (task->timeout && (task->timeout > DEF_TIMEOUT_MS))
+		tsk->timeout = task->timeout;
+	else
+		tsk->timeout = DEF_TIMEOUT_MS;
+
+	return tsk;
+}
+
+int ipu_check_task(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+	int ret = 0;
+
+	tsk = create_task_entry(task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	ret = check_task(tsk);
+
+	task->input = tsk->input;
+	task->output = tsk->output;
+	task->overlay = tsk->overlay;
+
+	kfree(tsk);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_check_task);
+
+int ipu_queue_sp_task(struct ipu_split_task *sp_task)
+{
+	struct ipu_task_entry *tsk;
+	int ret;
+
+	tsk = create_task_entry(&sp_task->task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	ret = prepare_task(tsk);
+	if (ret < 0)
+		goto done;
+
+	tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+	tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+
+	ret = queue_task(tsk);
+done:
+	kfree(tsk);
+	return ret;
+}
+
+int ipu_queue_task(struct ipu_task *task)
+{
+	struct ipu_task_entry *tsk;
+	int ret;
+
+	tsk = create_task_entry(task);
+	if (IS_ERR(tsk))
+		return PTR_ERR(tsk);
+
+	ret = prepare_task(tsk);
+	if (ret < 0)
+		goto done;
+
+	if (need_split(tsk))
+		ret = queue_split_task(tsk);
+	else
+		ret = queue_task(tsk);
+done:
+	kfree(tsk);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_queue_task);
+
+static bool only_ic(u8 mode)
+{
+	return ((mode == IC_MODE) || (mode == VDI_MODE));
+}
+
+static bool only_rot(u8 mode)
+{
+	return (mode == ROT_MODE);
+}
+
+static bool ic_and_rot(u8 mode)
+{
+	return ((mode == (IC_MODE | ROT_MODE)) ||
+		 (mode == (VDI_MODE | ROT_MODE)));
+}
+
+static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret = 0;
+	ipu_channel_params_t params;
+	dma_addr_t inbuf = 0, ovbuf = 0, ov_alp_buf = 0;
+	dma_addr_t inbuf_p = 0, inbuf_n = 0;
+	dma_addr_t outbuf = 0;
+	int out_uoff = 0, out_voff = 0, out_rot;
+	int out_w = 0, out_h = 0, out_stride;
+	int out_fmt;
+
+	memset(&params, 0, sizeof(params));
+
+	/* is it need link a rot channel */
+	if (ic_and_rot(t->set.mode)) {
+		outbuf = t->set.r_paddr;
+		out_w = t->set.r_width;
+		out_h = t->set.r_height;
+		out_stride = t->set.r_stride;
+		out_fmt = t->set.r_fmt;
+		out_uoff = 0;
+		out_voff = 0;
+		out_rot = IPU_ROTATE_NONE;
+	} else {
+		outbuf = t->output.paddr + t->set.o_off;
+		out_w = t->output.crop.w;
+		out_h = t->output.crop.h;
+		out_stride = t->set.ostride;
+		out_fmt = t->output.format;
+		out_uoff = t->set.o_uoff;
+		out_voff = t->set.o_voff;
+		out_rot = t->output.rotate;
+	}
+
+	/* settings */
+	params.mem_prp_vf_mem.in_width = t->input.crop.w;
+	params.mem_prp_vf_mem.out_width = out_w;
+	params.mem_prp_vf_mem.in_height = t->input.crop.h;
+	params.mem_prp_vf_mem.out_height = out_h;
+	params.mem_prp_vf_mem.in_pixel_fmt = t->input.format;
+	params.mem_prp_vf_mem.out_pixel_fmt = out_fmt;
+	params.mem_prp_vf_mem.motion_sel = t->input.deinterlace.motion;
+
+	params.mem_prp_vf_mem.outh_resize_ratio =
+			t->set.sp_setting.outh_resize_ratio;
+	params.mem_prp_vf_mem.outv_resize_ratio =
+			t->set.sp_setting.outv_resize_ratio;
+
+	if (t->overlay_en) {
+		params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
+		params.mem_prp_vf_mem.graphics_combine_en = 1;
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
+			params.mem_prp_vf_mem.global_alpha_en = 1;
+		else
+			params.mem_prp_vf_mem.alpha_chan_en = 1;
+		params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
+		if (t->overlay.colorkey.enable) {
+			params.mem_prp_vf_mem.key_color_en = 1;
+			params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
+		}
+	}
+
+	/* init channels */
+	ret = ipu_init_channel(ipu, t->set.ic_chan, &params);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_FAIL;
+		goto done;
+	}
+
+	if (deinterlace_3_field(t)) {
+		ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, &params);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_FAIL;
+			goto done;
+		}
+		ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, &params);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_FAIL;
+			goto done;
+		}
+	}
+
+	/* init channel bufs */
+	if (deinterlace_3_field(t)) {
+		inbuf_p = t->input.paddr + t->set.istride + t->set.i_off;
+		inbuf = t->input.paddr_n + t->set.i_off;
+		inbuf_n = t->input.paddr_n + t->set.istride + t->set.i_off;
+	} else
+		inbuf = t->input.paddr + t->set.i_off;
+
+	if (t->overlay_en) {
+		ovbuf = t->overlay.paddr + t->set.ov_off;
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+			ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+				+ t->set.ov_alpha_off;
+	}
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.ic_chan,
+			IPU_INPUT_BUFFER,
+			t->input.format,
+			t->input.crop.w,
+			t->input.crop.h,
+			t->set.istride,
+			IPU_ROTATE_NONE,
+			inbuf,
+			0,
+			0,
+			t->set.i_uoff,
+			t->set.i_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+	if (deinterlace_3_field(t)) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.vdi_ic_p_chan,
+				IPU_INPUT_BUFFER,
+				t->input.format,
+				t->input.crop.w,
+				t->input.crop.h,
+				t->set.istride,
+				IPU_ROTATE_NONE,
+				inbuf_p,
+				0,
+				0,
+				t->set.i_uoff,
+				t->set.i_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.vdi_ic_n_chan,
+				IPU_INPUT_BUFFER,
+				t->input.format,
+				t->input.crop.w,
+				t->input.crop.h,
+				t->set.istride,
+				IPU_ROTATE_NONE,
+				inbuf_n,
+				0,
+				0,
+				t->set.i_uoff,
+				t->set.i_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+	}
+
+	if (t->overlay_en) {
+		ret = ipu_init_channel_buffer(ipu,
+				t->set.ic_chan,
+				IPU_GRAPH_IN_BUFFER,
+				t->overlay.format,
+				t->overlay.crop.w,
+				t->overlay.crop.h,
+				t->set.ovstride,
+				IPU_ROTATE_NONE,
+				ovbuf,
+				0,
+				0,
+				t->set.ov_uoff,
+				t->set.ov_voff);
+		if (ret < 0) {
+			t->state = STATE_INIT_CHAN_BUF_FAIL;
+			goto done;
+		}
+
+		if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+			ret = ipu_init_channel_buffer(ipu,
+					t->set.ic_chan,
+					IPU_ALPHA_IN_BUFFER,
+					IPU_PIX_FMT_GENERIC,
+					t->overlay.crop.w,
+					t->overlay.crop.h,
+					t->set.ov_alpha_stride,
+					IPU_ROTATE_NONE,
+					ov_alp_buf,
+					0,
+					0,
+					0, 0);
+			if (ret < 0) {
+				t->state = STATE_INIT_CHAN_BUF_FAIL;
+				goto done;
+			}
+		}
+	}
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.ic_chan,
+			IPU_OUTPUT_BUFFER,
+			out_fmt,
+			out_w,
+			out_h,
+			out_stride,
+			out_rot,
+			outbuf,
+			0,
+			0,
+			out_uoff,
+			out_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
+static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	ipu_uninit_channel(ipu, t->set.ic_chan);
+	if (deinterlace_3_field(t)) {
+		ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
+		ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
+	}
+}
+
+static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	int ret = 0;
+	dma_addr_t inbuf = 0, outbuf = 0;
+	int in_uoff = 0, in_voff = 0;
+	int in_fmt, in_width, in_height, in_stride;
+
+	/* init channel */
+	ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_FAIL;
+		goto done;
+	}
+
+	/* init channel buf */
+	/* is it need link to a ic channel */
+	if (ic_and_rot(t->set.mode)) {
+		in_fmt = t->set.r_fmt;
+		in_width = t->set.r_width;
+		in_height = t->set.r_height;
+		in_stride = t->set.r_stride;
+		inbuf = t->set.r_paddr;
+		in_uoff = 0;
+		in_voff = 0;
+	} else {
+		in_fmt = t->input.format;
+		in_width = t->input.crop.w;
+		in_height = t->input.crop.h;
+		in_stride = t->set.istride;
+		inbuf = t->input.paddr + t->set.i_off;
+		in_uoff = t->set.i_uoff;
+		in_voff = t->set.i_voff;
+	}
+	outbuf = t->output.paddr + t->set.o_off;
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.rot_chan,
+			IPU_INPUT_BUFFER,
+			in_fmt,
+			in_width,
+			in_height,
+			t->set.istride,
+			t->output.rotate,
+			inbuf,
+			0,
+			0,
+			in_uoff,
+			in_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+	ret = ipu_init_channel_buffer(ipu,
+			t->set.rot_chan,
+			IPU_OUTPUT_BUFFER,
+			t->output.format,
+			t->output.crop.w,
+			t->output.crop.h,
+			t->set.ostride,
+			IPU_ROTATE_NONE,
+			outbuf,
+			0,
+			0,
+			t->set.o_uoff,
+			t->set.o_voff);
+	if (ret < 0) {
+		t->state = STATE_INIT_CHAN_BUF_FAIL;
+		goto done;
+	}
+
+done:
+	return ret;
+}
+
+static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	ipu_uninit_channel(ipu, t->set.rot_chan);
+}
+
+static int get_irq(struct ipu_task_entry *t)
+{
+	int irq;
+	ipu_channel_t chan;
+
+	if (only_ic(t->set.mode))
+		chan = t->set.ic_chan;
+	else
+		chan = t->set.rot_chan;
+
+	switch (chan) {
+	case MEM_ROT_VF_MEM:
+		irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
+		break;
+	case MEM_ROT_PP_MEM:
+		irq = IPU_IRQ_PP_ROT_OUT_EOF;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		irq = IPU_IRQ_PRP_VF_OUT_EOF;
+		break;
+	case MEM_PP_MEM:
+		irq = IPU_IRQ_PP_OUT_EOF;
+		break;
+	default:
+		irq = -EINVAL;
+	}
+
+	return irq;
+}
+
+static irqreturn_t task_irq_handler(int irq, void *dev_id)
+{
+	struct completion *comp = dev_id;
+	complete(comp);
+	return IRQ_HANDLED;
+}
+
+static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+	struct completion comp;
+	void *r_vaddr;
+	int r_size;
+	int irq;
+	int ret;
+
+	if (!ipu) {
+		t->state = STATE_NO_IPU;
+		return;
+	}
+
+	dev_dbg(ipu->dev, "[0x%p]Do task: id %d\n", (void *)t, t->task_id);
+	dump_task_info(t);
+
+	if (t->set.task & IC_PP) {
+		t->set.ic_chan = MEM_PP_MEM;
+		dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
+	} else if (t->set.task & IC_VF) {
+		t->set.ic_chan = MEM_PRP_VF_MEM;
+		dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
+	} else if (t->set.task & VDI_VF) {
+		t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
+		if (deinterlace_3_field(t)) {
+			t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
+			t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
+		}
+		dev_dbg(ipu->dev, "[0x%p]ic channel MEM_VDI_PRP_VF_MEM\n", (void *)t);
+	}
+
+	if (t->set.task & ROT_PP) {
+		t->set.rot_chan = MEM_ROT_PP_MEM;
+		dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
+	} else if (t->set.task & ROT_VF) {
+		t->set.rot_chan = MEM_ROT_VF_MEM;
+		dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
+	}
+
+	/* channel setup */
+	if (only_ic(t->set.mode)) {
+		dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
+		ret = init_ic(ipu, t);
+		if (ret < 0)
+			goto chan_done;
+	} else if (only_rot(t->set.mode)) {
+		dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
+		ret = init_rot(ipu, t);
+		if (ret < 0)
+			goto chan_done;
+	} else if (ic_and_rot(t->set.mode)) {
+		dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
+		t->set.r_fmt = t->output.format;
+		if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+			t->set.r_width = t->output.crop.h;
+			t->set.r_height = t->output.crop.w;
+		} else {
+			t->set.r_width = t->output.crop.w;
+			t->set.r_height = t->output.crop.h;
+		}
+		t->set.r_stride = t->set.r_width *
+			bytes_per_pixel(t->set.r_fmt);
+		r_size = t->set.r_width * t->set.r_height
+			* fmt_to_bpp(t->set.r_fmt)/8;
+		r_vaddr = dma_alloc_coherent(t->dev,
+					  r_size,
+					  &t->set.r_paddr,
+					  GFP_DMA | GFP_KERNEL);
+		if (r_vaddr == NULL) {
+			ret = -ENOMEM;
+			goto chan_done;
+		}
+
+		dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
+		dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
+		dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
+		dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
+		dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
+		dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
+
+		ret = init_ic(ipu, t);
+		if (ret < 0)
+			goto chan_done;
+		ret = init_rot(ipu, t);
+		if (ret < 0)
+			goto chan_done;
+		ret = ipu_link_channels(ipu, t->set.ic_chan,
+				t->set.rot_chan);
+		if (ret < 0) {
+			t->state = STATE_LINK_CHAN_FAIL;
+			goto chan_done;
+		}
+	} else {
+		dev_err(t->dev, "[0x%p]do_task: should not be here\n", (void *)t);
+		return;
+	}
+
+	/* irq setup */
+	irq = get_irq(t);
+	if (irq < 0) {
+		t->state = STATE_NO_IRQ;
+		goto chan_done;
+	}
+
+	dev_dbg(t->dev, "[0x%p]task irq is %d\n", (void *)t, irq);
+
+	init_completion(&comp);
+	ipu_clear_irq(ipu, irq);
+	ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, &comp);
+	if (ret < 0) {
+		t->state = STATE_IRQ_FAIL;
+		goto chan_done;
+	}
+
+	/* enable/start channel */
+	if (only_ic(t->set.mode)) {
+		ipu_enable_channel(ipu, t->set.ic_chan);
+		if (deinterlace_3_field(t)) {
+			ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+			ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+		}
+
+		ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0);
+		if (t->overlay_en) {
+			ipu_select_buffer(ipu, t->set.ic_chan, IPU_GRAPH_IN_BUFFER, 0);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+				ipu_select_buffer(ipu, t->set.ic_chan, IPU_ALPHA_IN_BUFFER, 0);
+		}
+		if (deinterlace_3_field(t))
+			ipu_select_multi_vdi_buffer(ipu, 0);
+		else
+			ipu_select_buffer(ipu, t->set.ic_chan, IPU_INPUT_BUFFER, 0);
+	} else if (only_rot(t->set.mode)) {
+		ipu_enable_channel(ipu, t->set.rot_chan);
+		ipu_select_buffer(ipu, t->set.rot_chan, IPU_OUTPUT_BUFFER, 0);
+		ipu_select_buffer(ipu, t->set.rot_chan, IPU_INPUT_BUFFER, 0);
+	} else if (ic_and_rot(t->set.mode)) {
+		ipu_enable_channel(ipu, t->set.rot_chan);
+		ipu_enable_channel(ipu, t->set.ic_chan);
+		if (deinterlace_3_field(t)) {
+			ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+			ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+		}
+
+		ipu_select_buffer(ipu, t->set.rot_chan, IPU_OUTPUT_BUFFER, 0);
+		if (t->overlay_en) {
+			ipu_select_buffer(ipu, t->set.ic_chan, IPU_GRAPH_IN_BUFFER, 0);
+			if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+				ipu_select_buffer(ipu, t->set.ic_chan, IPU_ALPHA_IN_BUFFER, 0);
+		}
+		if (deinterlace_3_field(t))
+			ipu_select_multi_vdi_buffer(ipu, 0);
+		else
+			ipu_select_buffer(ipu, t->set.ic_chan, IPU_INPUT_BUFFER, 0);
+		ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0);
+	}
+
+	ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(t->timeout));
+	if (ret == 0)
+		t->state = STATE_IRQ_TIMEOUT;
+
+	ipu_free_irq(ipu, irq, &comp);
+	if (t->set.task & IC_VF) {
+		ipu_clear_irq(ipu, IPU_IRQ_PRP_IN_EOF);
+		ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+	} else if (t->set.task & IC_PP) {
+		ipu_clear_irq(ipu, IPU_IRQ_PP_IN_EOF);
+		ipu_clear_irq(ipu, IPU_IRQ_PP_OUT_EOF);
+	} else if (t->set.task & VDI_VF) {
+		ipu_clear_irq(ipu, IPU_IRQ_VDI_C_IN_EOF);
+		if (deinterlace_3_field(t)) {
+			ipu_clear_irq(ipu, IPU_IRQ_VDI_P_IN_EOF);
+			ipu_clear_irq(ipu, IPU_IRQ_VDI_N_IN_EOF);
+		}
+		ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+	}
+	if (t->set.task & ROT_VF) {
+		ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_ROT_IN_EOF);
+		ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
+	} else if (t->set.task & ROT_PP) {
+		ipu_clear_irq(ipu, IPU_IRQ_PP_ROT_IN_EOF);
+		ipu_clear_irq(ipu, IPU_IRQ_PP_ROT_OUT_EOF);
+	}
+
+	if (only_ic(t->set.mode)) {
+		ipu_disable_channel(ipu, t->set.ic_chan, true);
+		if (deinterlace_3_field(t)) {
+			ipu_disable_channel(ipu, t->set.vdi_ic_p_chan, true);
+			ipu_disable_channel(ipu, t->set.vdi_ic_n_chan, true);
+		}
+	} else if (only_rot(t->set.mode))
+		ipu_disable_channel(ipu, t->set.rot_chan, true);
+	else if (ic_and_rot(t->set.mode)) {
+		ipu_disable_channel(ipu, t->set.ic_chan, true);
+		if (deinterlace_3_field(t)) {
+			ipu_disable_channel(ipu, t->set.vdi_ic_p_chan, true);
+			ipu_disable_channel(ipu, t->set.vdi_ic_n_chan, true);
+		}
+		ipu_disable_channel(ipu, t->set.rot_chan, true);
+	}
+
+chan_done:
+	if (only_ic(t->set.mode))
+		uninit_ic(ipu, t);
+	else if (only_rot(t->set.mode))
+		uninit_rot(ipu, t);
+	else if (ic_and_rot(t->set.mode)) {
+		ipu_unlink_channels(ipu, t->set.ic_chan,
+			t->set.rot_chan);
+		uninit_ic(ipu, t);
+		uninit_rot(ipu, t);
+		if (r_vaddr)
+			dma_free_coherent(t->dev,
+					r_size,
+					r_vaddr,
+					t->set.r_paddr);
+	}
+	return;
+}
+
+static int thread_loop(struct ipu_soc *ipu, int id)
+{
+	struct ipu_task_entry *tsk;
+	struct list_head *task_list = &ipu->task_list[id];
+	struct mutex *task_lock = &ipu->task_lock[id];
+	int ret;
+
+	while (!kthread_should_stop()) {
+		int found = 0;
+
+		ret = wait_event_interruptible(ipu->waitq[id], !list_empty(task_list));
+		if (0 != ret)
+			continue;
+
+		mutex_lock(task_lock);
+
+		list_for_each_entry(tsk, task_list, node) {
+			if (tsk->priority == IPU_TASK_PRIORITY_HIGH) {
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found)
+			tsk = list_first_entry(task_list, struct ipu_task_entry, node);
+
+		mutex_unlock(task_lock);
+
+		do_task(ipu, tsk);
+
+		mutex_lock(task_lock);
+		list_del(&tsk->node);
+		mutex_unlock(task_lock);
+
+		complete(&tsk->comp);
+	}
+
+	return 0;
+}
+
+static int task_vf_thread(void *data)
+{
+	struct ipu_soc *ipu = data;
+
+	thread_loop(ipu, 0);
+
+	return 0;
+}
+
+static int task_pp_thread(void *data)
+{
+	struct ipu_soc *ipu = data;
+
+	thread_loop(ipu, 1);
+
+	return 0;
+}
+
+static int mxc_ipu_open(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static long mxc_ipu_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int __user *argp = (void __user *)arg;
+	int ret = 0;
+
+	switch (cmd) {
+	case IPU_CHECK_TASK:
+		{
+			struct ipu_task task;
+
+			if (copy_from_user
+					(&task, (struct ipu_task *) arg,
+					 sizeof(struct ipu_task)))
+				return -EFAULT;
+			ret = ipu_check_task(&task);
+			if (copy_to_user((struct ipu_task *) arg,
+				&task, sizeof(struct ipu_task)))
+				return -EFAULT;
+			break;
+		}
+	case IPU_QUEUE_TASK:
+		{
+			struct ipu_task task;
+
+			if (copy_from_user
+					(&task, (struct ipu_task *) arg,
+					 sizeof(struct ipu_task)))
+				return -EFAULT;
+			ret = ipu_queue_task(&task);
+			break;
+		}
+	case IPU_ALLOC:
+		{
+			int size;
+			struct ipu_alloc_list *mem;
+
+			mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+			if (mem == NULL)
+				return -ENOMEM;
+
+			if (get_user(size, argp))
+				return -EFAULT;
+
+			mem->size = PAGE_ALIGN(size);
+
+			mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
+							   &mem->phy_addr,
+							   GFP_DMA);
+			if (mem->cpu_addr == NULL) {
+				kfree(mem);
+				return -ENOMEM;
+			}
+
+			list_add(&mem->list, &ipu_alloc_list);
+
+			dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
+				mem->size, mem->phy_addr);
+
+			if (put_user(mem->phy_addr, argp))
+				return -EFAULT;
+
+			break;
+		}
+	case IPU_FREE:
+		{
+			unsigned long offset;
+			struct ipu_alloc_list *mem;
+
+			if (get_user(offset, argp))
+				return -EFAULT;
+
+			ret = -EINVAL;
+			list_for_each_entry(mem, &ipu_alloc_list, list) {
+				if (mem->phy_addr == offset) {
+					list_del(&mem->list);
+					dma_free_coherent(ipu_dev,
+							  mem->size,
+							  mem->cpu_addr,
+							  mem->phy_addr);
+					kfree(mem);
+					ret = 0;
+					break;
+				}
+			}
+
+			break;
+		}
+	default:
+		break;
+	}
+	return ret;
+}
+
+static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	bool found = false;
+	u32 len;
+	unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+	struct ipu_alloc_list *mem;
+
+	list_for_each_entry(mem, &ipu_alloc_list, list) {
+		if (offset == mem->phy_addr) {
+			found = true;
+			len = mem->size;
+			break;
+		}
+	}
+	if (!found)
+		return -EINVAL;
+
+	if (vma->vm_end - vma->vm_start > len)
+		return -EINVAL;
+
+	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+
+	if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+				vma->vm_end - vma->vm_start,
+				vma->vm_page_prot)) {
+		printk(KERN_ERR
+				"mmap failed!\n");
+		return -ENOBUFS;
+	}
+	return 0;
+}
+
+static int mxc_ipu_release(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static struct file_operations mxc_ipu_fops = {
+	.owner = THIS_MODULE,
+	.open = mxc_ipu_open,
+	.mmap = mxc_ipu_mmap,
+	.release = mxc_ipu_release,
+	.unlocked_ioctl = mxc_ipu_ioctl,
+};
+
+int register_ipu_device(struct ipu_soc *ipu, int id)
+{
+	int ret = 0;
+
+	if (!major) {
+		major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
+		if (major < 0) {
+			printk(KERN_ERR "Unable to register mxc_ipu as a char device\n");
+			ret = major;
+			goto register_cdev_fail;
+		}
+
+		ipu_class = class_create(THIS_MODULE, "mxc_ipu");
+		if (IS_ERR(ipu_class)) {
+			ret = PTR_ERR(ipu_class);
+			goto ipu_class_fail;
+		}
+
+		ipu_dev = device_create(ipu_class, NULL, MKDEV(major, 0),
+				NULL, "mxc_ipu");
+		if (IS_ERR(ipu_dev)) {
+			ret = PTR_ERR(ipu_dev);
+			goto dev_create_fail;
+		}
+		ipu_dev->dma_mask = kmalloc(sizeof(*ipu_dev->dma_mask), GFP_KERNEL);
+		*ipu_dev->dma_mask = DMA_BIT_MASK(32);
+		ipu_dev->coherent_dma_mask = DMA_BIT_MASK(32);
+	}
+
+	INIT_LIST_HEAD(&ipu->task_list[0]);
+	INIT_LIST_HEAD(&ipu->task_list[1]);
+	init_waitqueue_head(&ipu->waitq[0]);
+	init_waitqueue_head(&ipu->waitq[1]);
+	mutex_init(&ipu->task_lock[0]);
+	mutex_init(&ipu->task_lock[1]);
+	ipu->thread[0] = kthread_run(task_vf_thread, ipu,
+					"ipu%d_process-vf", id);
+	if (IS_ERR(ipu->thread[0])) {
+		ret = PTR_ERR(ipu->thread[0]);
+		goto kthread0_fail;
+	}
+
+	ipu->thread[1] = kthread_run(task_pp_thread, ipu,
+				"ipu%d_process-pp", id);
+	if (IS_ERR(ipu->thread[1])) {
+		ret = PTR_ERR(ipu->thread[1]);
+		goto kthread1_fail;
+	}
+
+	return ret;
+
+kthread1_fail:
+	kthread_stop(ipu->thread[0]);
+kthread0_fail:
+	if (id == 0)
+		device_destroy(ipu_class, MKDEV(major, 0));
+dev_create_fail:
+	if (id == 0) {
+		class_destroy(ipu_class);
+		unregister_chrdev(major, "mxc_ipu");
+	}
+ipu_class_fail:
+	if (id == 0)
+		unregister_chrdev(major, "mxc_ipu");
+register_cdev_fail:
+	return ret;
+}
+
+void unregister_ipu_device(struct ipu_soc *ipu, int id)
+{
+	kthread_stop(ipu->thread[0]);
+	kthread_stop(ipu->thread[1]);
+	if (major) {
+		device_destroy(ipu_class, MKDEV(major, 0));
+		class_destroy(ipu_class);
+		unregister_chrdev(major, "mxc_ipu");
+		major = 0;
+	}
+}
diff --git a/drivers/mxc/ipu3/ipu_disp.c b/drivers/mxc/ipu3/ipu_disp.c
new file mode 100644
index 0000000..9867d57
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_disp.c
@@ -0,0 +1,2063 @@
+/*
+ * Copyright 2005-2011 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
+ */
+
+/*!
+ * @file ipu_disp.c
+ *
+ * @brief IPU display submodule API functions
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/atomic.h>
+#include <mach/clock.h>
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+#include "ipu_param_mem.h"
+
+struct dp_csc_param_t {
+	int mode;
+	void *coeff;
+};
+
+#define SYNC_WAVE 0
+#define ASYNC_SER_WAVE 6
+
+/* DC display ID assignments */
+#define DC_DISP_ID_SYNC(di)	(di)
+#define DC_DISP_ID_SERIAL	2
+#define DC_DISP_ID_ASYNC	3
+
+static inline struct ipu_soc *pixelclk2ipu(struct clk *clk)
+{
+	struct ipu_soc *ipu;
+	struct clk *base = clk - clk->id;
+
+	ipu = container_of(base, struct ipu_soc, pixel_clk[0]);
+
+	return ipu;
+}
+
+static unsigned long _ipu_pixel_clk_get_rate(struct clk *clk)
+{
+	struct ipu_soc *ipu = pixelclk2ipu(clk);
+	u32 div = ipu_di_read(ipu, clk->id, DI_BS_CLKGEN0);
+	if (div == 0)
+		return 0;
+	return  (clk_get_rate(clk->parent) * 16) / div;
+}
+
+static unsigned long _ipu_pixel_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	u32 div, div1;
+	u32 parent_rate = clk_get_rate(clk->parent) * 16;
+	/*
+	 * Calculate divider
+	 * Fractional part is 4 bits,
+	 * so simply multiply by 2^4 to get fractional part.
+	 */
+	div = parent_rate / rate;
+
+	if (div < 0x10)            /* Min DI disp clock divider is 1 */
+		div = 0x10;
+	if (div & ~0xFEF)
+		div &= 0xFF8;
+	else {
+		div1 = div & 0xFE0;
+		if ((parent_rate / div1 - parent_rate / div) < rate / 4)
+			div = div1;
+		else
+			div &= 0xFF8;
+	}
+	return parent_rate / div;
+}
+
+static int _ipu_pixel_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	struct ipu_soc *ipu = pixelclk2ipu(clk);
+	u32 div = (clk_get_rate(clk->parent) * 16) / rate;
+
+	ipu_di_write(ipu, clk->id, div, DI_BS_CLKGEN0);
+
+	/* Setup pixel clock timing */
+	/* FIXME: needs to be more flexible */
+	/* Down time is half of period */
+	ipu_di_write(ipu, clk->id, (div / 16) << 16, DI_BS_CLKGEN1);
+
+	return 0;
+}
+
+static int _ipu_pixel_clk_enable(struct clk *clk)
+{
+	struct ipu_soc *ipu = pixelclk2ipu(clk);
+	u32 disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen |= clk->id ? DI1_COUNTER_RELEASE : DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+	return 0;
+}
+
+static void _ipu_pixel_clk_disable(struct clk *clk)
+{
+	struct ipu_soc *ipu = pixelclk2ipu(clk);
+
+	u32 disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+	disp_gen &= clk->id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+	ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+}
+
+static int _ipu_pixel_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	struct ipu_soc *ipu = pixelclk2ipu(clk);
+	u32 di_gen;
+
+	di_gen = ipu_di_read(ipu, clk->id, DI_GENERAL);
+	if (parent == ipu->ipu_clk)
+		di_gen &= ~DI_GEN_DI_CLK_EXT;
+	else if (!IS_ERR(ipu->di_clk[clk->id]) && parent == ipu->di_clk[clk->id])
+		di_gen |= DI_GEN_DI_CLK_EXT;
+	else {
+		return -EINVAL;
+	}
+
+	ipu_di_write(ipu, clk->id, di_gen, DI_GENERAL);
+	return 0;
+}
+
+#ifdef CONFIG_CLK_DEBUG
+#define __INIT_CLK_DEBUG(n)    .name = #n,
+#else
+#define __INIT_CLK_DEBUG(n)
+#endif
+struct clk ipu_pixel_clk[] = {
+	{
+		__INIT_CLK_DEBUG(pixel_clk_0)
+			.id = 0,
+		.get_rate = _ipu_pixel_clk_get_rate,
+		.set_rate = _ipu_pixel_clk_set_rate,
+		.round_rate = _ipu_pixel_clk_round_rate,
+		.set_parent = _ipu_pixel_clk_set_parent,
+		.enable = _ipu_pixel_clk_enable,
+		.disable = _ipu_pixel_clk_disable,
+	},
+	{
+		__INIT_CLK_DEBUG(pixel_clk_1)
+			.id = 1,
+		.get_rate = _ipu_pixel_clk_get_rate,
+		.set_rate = _ipu_pixel_clk_set_rate,
+		.round_rate = _ipu_pixel_clk_round_rate,
+		.set_parent = _ipu_pixel_clk_set_parent,
+		.enable = _ipu_pixel_clk_enable,
+		.disable = _ipu_pixel_clk_disable,
+	},
+};
+
+struct clk_lookup ipu_lookups[] = {
+	{
+		.dev_id = NULL,
+		.con_id = "pixel_clk_0",
+	},
+	{
+		.dev_id = NULL,
+		.con_id = "pixel_clk_1",
+	},
+};
+
+int dmfc_type_setup;
+
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first)
+{
+	u32 dmfc_wr_chan, dmfc_dp_chan;
+
+	if (first) {
+		if (dmfc_type_setup > dmfc_type)
+			dmfc_type = dmfc_type_setup;
+		else
+			dmfc_type_setup = dmfc_type;
+
+		/* disable DMFC-IC channel*/
+		ipu_dmfc_write(ipu, 0x2, DMFC_IC_CTRL);
+	} else if (dmfc_type_setup >= DMFC_HIGH_RESOLUTION_DC) {
+		dev_dbg(ipu->dev, "DMFC high resolution has set, will not change\n");
+		return;
+	} else
+		dmfc_type_setup = dmfc_type;
+
+	if (dmfc_type == DMFC_HIGH_RESOLUTION_DC) {
+		/* 1 - segment 0~3;
+		 * 5B - segement 4, 5;
+		 * 5F - segement 6, 7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC DC HIGH RESOLUTION: 1(0~3), 5B(4,5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000088;
+		dmfc_dp_chan = 0x00009694;
+		ipu->dmfc_size_28 = 256*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 128*4;
+	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_DP) {
+		/* 1 - segment 0, 1;
+		 * 5B - segement 2~5;
+		 * 5F - segement 6,7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC DP HIGH RESOLUTION: 1(0,1), 5B(2~5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000090;
+		dmfc_dp_chan = 0x0000968a;
+		ipu->dmfc_size_28 = 128*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 256*4;
+	} else if (dmfc_type == DMFC_HIGH_RESOLUTION_ONLY_DP) {
+		/* 5B - segement 0~3;
+		 * 5F - segement 4~7;
+		 * 1, 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC ONLY-DP HIGH RESOLUTION: 5B(0~3), 5F(4~7)\n");
+		dmfc_wr_chan = 0x00000000;
+		dmfc_dp_chan = 0x00008c88;
+		ipu->dmfc_size_28 = 0;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 256*4;
+		ipu->dmfc_size_23 = 256*4;
+	} else {
+		/* 1 - segment 0, 1;
+		 * 5B - segement 4, 5;
+		 * 5F - segement 6, 7;
+		 * 1C, 2C and 6B, 6F unused;
+		 */
+		dev_info(ipu->dev, "IPU DMFC NORMAL mode: 1(0~1), 5B(4,5), 5F(6,7)\n");
+		dmfc_wr_chan = 0x00000090;
+		dmfc_dp_chan = 0x00009694;
+		ipu->dmfc_size_28 = 128*4;
+		ipu->dmfc_size_29 = 0;
+		ipu->dmfc_size_24 = 0;
+		ipu->dmfc_size_27 = 128*4;
+		ipu->dmfc_size_23 = 128*4;
+	}
+	ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+	ipu_dmfc_write(ipu, 0x202020F6, DMFC_WR_CHAN_DEF);
+	ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+	/* Enable chan 5 watermark set at 5 bursts and clear at 7 bursts */
+	ipu_dmfc_write(ipu, 0x2020F6F6, DMFC_DP_CHAN_DEF);
+}
+
+static int __init dmfc_setup(char *options)
+{
+	get_option(&options, &dmfc_type_setup);
+	if (dmfc_type_setup > DMFC_HIGH_RESOLUTION_ONLY_DP)
+		dmfc_type_setup = DMFC_HIGH_RESOLUTION_ONLY_DP;
+	return 1;
+}
+__setup("dmfc=", dmfc_setup);
+
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width)
+{
+	u32 dmfc_gen1 = ipu_dmfc_read(ipu, DMFC_GENERAL1);
+
+	if (width >= HIGH_RESOLUTION_WIDTH) {
+		if (dma_chan == 23)
+			_ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DP, 0);
+		else if (dma_chan == 28)
+			_ipu_dmfc_init(ipu, DMFC_HIGH_RESOLUTION_DC, 0);
+	}
+
+	if (dma_chan == 23) { /*5B*/
+		if (ipu->dmfc_size_23/width > 3)
+			dmfc_gen1 |= 1UL << 20;
+		else
+			dmfc_gen1 &= ~(1UL << 20);
+	} else if (dma_chan == 24) { /*6B*/
+		if (ipu->dmfc_size_24/width > 1)
+			dmfc_gen1 |= 1UL << 22;
+		else
+			dmfc_gen1 &= ~(1UL << 22);
+	} else if (dma_chan == 27) { /*5F*/
+		if (ipu->dmfc_size_27/width > 2)
+			dmfc_gen1 |= 1UL << 21;
+		else
+			dmfc_gen1 &= ~(1UL << 21);
+	} else if (dma_chan == 28) { /*1*/
+		if (ipu->dmfc_size_28/width > 2)
+			dmfc_gen1 |= 1UL << 16;
+		else
+			dmfc_gen1 &= ~(1UL << 16);
+	} else if (dma_chan == 29) { /*6F*/
+		if (ipu->dmfc_size_29/width > 1)
+			dmfc_gen1 |= 1UL << 23;
+		else
+			dmfc_gen1 &= ~(1UL << 23);
+	}
+
+	ipu_dmfc_write(ipu, dmfc_gen1, DMFC_GENERAL1);
+}
+
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size)
+{
+	u32 dmfc_wr_chan = ipu_dmfc_read(ipu, DMFC_WR_CHAN);
+	u32 dmfc_dp_chan = ipu_dmfc_read(ipu, DMFC_DP_CHAN);
+	int dmfc_bs = 0;
+
+	switch (burst_size) {
+	case 64:
+		dmfc_bs = 0x40;
+		break;
+	case 32:
+	case 20:
+		dmfc_bs = 0x80;
+		break;
+	case 16:
+		dmfc_bs = 0xc0;
+		break;
+	default:
+		dev_err(ipu->dev, "Unsupported burst size %d\n",
+			burst_size);
+		return;
+	}
+
+	if (dma_chan == 23) { /*5B*/
+		dmfc_dp_chan &= ~(0xc0);
+		dmfc_dp_chan |= dmfc_bs;
+	} else if (dma_chan == 27) { /*5F*/
+		dmfc_dp_chan &= ~(0xc000);
+		dmfc_dp_chan |= (dmfc_bs << 8);
+	} else if (dma_chan == 28) { /*1*/
+		dmfc_wr_chan &= ~(0xc0);
+		dmfc_wr_chan |= dmfc_bs;
+	}
+
+	ipu_dmfc_write(ipu, dmfc_wr_chan, DMFC_WR_CHAN);
+	ipu_dmfc_write(ipu, dmfc_dp_chan, DMFC_DP_CHAN);
+}
+
+static void _ipu_di_data_wave_config(struct ipu_soc *ipu,
+				int 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(ipu, di, reg, DI_DW_GEN(wave_gen));
+}
+
+static void _ipu_di_data_pin_config(struct ipu_soc *ipu,
+			int di, int wave_gen, int di_pin, int set,
+			int up, int down)
+{
+	u32 reg;
+
+	reg = ipu_di_read(ipu, di, DI_DW_GEN(wave_gen));
+	reg &= ~(0x3 << (di_pin * 2));
+	reg |= set << (di_pin * 2);
+	ipu_di_write(ipu, di, reg, DI_DW_GEN(wave_gen));
+
+	ipu_di_write(ipu, di, (down << 16) | up, DI_DW_SET(wave_gen, set));
+}
+
+static void _ipu_di_sync_config(struct ipu_soc *ipu,
+				int di, int wave_gen,
+				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)
+{
+	u32 reg;
+
+	if ((run_count >= 0x1000) || (offset_count >= 0x1000) || (repeat_count >= 0x1000) ||
+		(cnt_up >= 0x400) || (cnt_down >= 0x400)) {
+		dev_err(ipu->dev, "DI%d counters out of range.\n", di);
+		return;
+	}
+
+	reg = (run_count << 19) | (++run_src << 16) |
+	    (offset_count << 3) | ++offset_src;
+	ipu_di_write(ipu, di, reg, DI_SW_GEN0(wave_gen));
+	reg = (cnt_polarity_gen_en << 29) | (++cnt_clr_src << 25) |
+	    (++cnt_polarity_trigger_src << 12) | (++cnt_polarity_clr_src << 9);
+	reg |= (cnt_down << 16) | cnt_up;
+	if (repeat_count == 0) {
+		/* Enable auto reload */
+		reg |= 0x10000000;
+	}
+	ipu_di_write(ipu, di, reg, DI_SW_GEN1(wave_gen));
+	reg = ipu_di_read(ipu, di, DI_STP_REP(wave_gen));
+	reg &= ~(0xFFFF << (16 * ((wave_gen - 1) & 0x1)));
+	reg |= repeat_count << (16 * ((wave_gen - 1) & 0x1));
+	ipu_di_write(ipu, di, reg, DI_STP_REP(wave_gen));
+}
+
+static void _ipu_dc_map_link(struct ipu_soc *ipu,
+		int current_map,
+		int base_map_0, int buf_num_0,
+		int base_map_1, int buf_num_1,
+		int base_map_2, int buf_num_2)
+{
+	int ptr_0 = base_map_0 * 3 + buf_num_0;
+	int ptr_1 = base_map_1 * 3 + buf_num_1;
+	int ptr_2 = base_map_2 * 3 + buf_num_2;
+	int ptr;
+	u32 reg;
+	ptr = (ptr_2 << 10) +  (ptr_1 << 5) + ptr_0;
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(current_map));
+	reg &= ~(0x1F << ((16 * (current_map & 0x1))));
+	reg |= ptr << ((16 * (current_map & 0x1)));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(current_map));
+}
+
+static void _ipu_dc_map_config(struct ipu_soc *ipu,
+		int map, int byte_num, int offset, int mask)
+{
+	int ptr = map * 3 + byte_num;
+	u32 reg;
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_VAL(ptr));
+	reg &= ~(0xFFFF << (16 * (ptr & 0x1)));
+	reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_VAL(ptr));
+
+	reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+	reg &= ~(0x1F << ((16 * (map & 0x1)) + (5 * byte_num)));
+	reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num));
+	ipu_dc_write(ipu, reg, DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_map_clear(struct ipu_soc *ipu, int map)
+{
+	u32 reg = ipu_dc_read(ipu, DC_MAP_CONF_PTR(map));
+	ipu_dc_write(ipu, reg & ~(0xFFFF << (16 * (map & 0x1))),
+		     DC_MAP_CONF_PTR(map));
+}
+
+static void _ipu_dc_write_tmpl(struct ipu_soc *ipu,
+			int word, u32 opcode, u32 operand, int map,
+			int wave, int glue, int sync, int stop)
+{
+	u32 reg;
+
+	if (opcode == WRG) {
+		reg = sync;
+		reg |= (glue << 4);
+		reg |= (++wave << 11);
+		reg |= ((operand & 0x1FFFF) << 15);
+		ipu_dc_tmpl_write(ipu, reg, word * 2);
+
+		reg = (operand >> 17);
+		reg |= opcode << 7;
+		reg |= (stop << 9);
+		ipu_dc_tmpl_write(ipu, reg, word * 2 + 1);
+	} else {
+		reg = sync;
+		reg |= (glue << 4);
+		reg |= (++wave << 11);
+		reg |= (++map << 15);
+		reg |= (operand << 20) & 0xFFF00000;
+		ipu_dc_tmpl_write(ipu, reg, word * 2);
+
+		reg = (operand >> 12);
+		reg |= opcode << 4;
+		reg |= (stop << 9);
+		ipu_dc_tmpl_write(ipu, reg, word * 2 + 1);
+	}
+}
+
+static void _ipu_dc_link_event(struct ipu_soc *ipu,
+		int chan, int event, int addr, int priority)
+{
+	u32 reg;
+	u32 address_shift;
+	if (event < DC_EVEN_UGDE0) {
+		reg = ipu_dc_read(ipu, DC_RL_CH(chan, event));
+		reg &= ~(0xFFFF << (16 * (event & 0x1)));
+		reg |= ((addr << 8) | priority) << (16 * (event & 0x1));
+		ipu_dc_write(ipu, reg, DC_RL_CH(chan, event));
+	} else {
+		reg = ipu_dc_read(ipu, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+		if ((event - DC_EVEN_UGDE0) & 0x1) {
+			reg &= ~(0x2FF << 16);
+			reg |= (addr << 16);
+			reg |= priority ? (2 << 24) : 0x0;
+		} else {
+			reg &= ~0xFC00FFFF;
+			if (priority)
+				chan = (chan >> 1) +
+					((((chan & 0x1) + ((chan & 0x2) >> 1))) | (chan >> 3));
+			else
+				chan = 0x7;
+			address_shift = ((event - DC_EVEN_UGDE0) >> 1) ? 7 : 8;
+			reg |= (addr << address_shift) | (priority << 3) | chan;
+		}
+		ipu_dc_write(ipu, reg, DC_UGDE_0((event - DC_EVEN_UGDE0) / 2));
+	}
+}
+
+/*     Y = R *  1.200 + G *  2.343 + B *  .453 + 0.250;
+       U = R * -.672 + G * -1.328 + B *  2.000 + 512.250.;
+       V = R *  2.000 + G * -1.672 + B * -.328 + 512.250.;*/
+static const int rgb2ycbcr_coeff[5][3] = {
+	{0x4D, 0x96, 0x1D},
+	{-0x2B, -0x55, 0x80},
+	{0x80, -0x6B, -0x15},
+	{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 */
+};
+
+#define mask_a(a) ((u32)(a) & 0x3FF)
+#define mask_b(b) ((u32)(b) & 0x3FFF)
+
+/* Pls keep S0, S1 and S2 as 0x2 by using this convertion */
+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;
+}
+
+/*
+ * 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} }
+};
+
+void __ipu_dp_csc_setup(struct ipu_soc *ipu,
+		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 = ipu_dp_read(ipu, DP_COM_CONF(dp));
+		reg &= ~DP_COM_CONF_CSC_DEF_MASK;
+		reg |= dp_csc_param.mode;
+		ipu_dp_write(ipu, reg, DP_COM_CONF(dp));
+	}
+
+	coeff = dp_csc_param.coeff;
+
+	if (coeff) {
+		ipu_dp_write(ipu, mask_a((*coeff)[0][0]) |
+				(mask_a((*coeff)[0][1]) << 16), DP_CSC_A_0(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[0][2]) |
+				(mask_a((*coeff)[1][0]) << 16), DP_CSC_A_1(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[1][1]) |
+				(mask_a((*coeff)[1][2]) << 16), DP_CSC_A_2(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[2][0]) |
+				(mask_a((*coeff)[2][1]) << 16), DP_CSC_A_3(dp));
+		ipu_dp_write(ipu, mask_a((*coeff)[2][2]) |
+				(mask_b((*coeff)[3][0]) << 16) |
+				((*coeff)[4][0] << 30), DP_CSC_0(dp));
+		ipu_dp_write(ipu, 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, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+}
+
+int _ipu_dp_init(struct ipu_soc *ipu,
+		ipu_channel_t channel, uint32_t in_pixel_fmt,
+		uint32_t out_pixel_fmt)
+{
+	int in_fmt, out_fmt;
+	int dp;
+	int partial = false;
+	uint32_t reg;
+
+	if (channel == MEM_FG_SYNC) {
+		dp = DP_SYNC;
+		partial = true;
+	} else if (channel == MEM_BG_SYNC) {
+		dp = DP_SYNC;
+		partial = false;
+	} else if (channel == MEM_BG_ASYNC0) {
+		dp = DP_ASYNC0;
+		partial = false;
+	} else {
+		return -EINVAL;
+	}
+
+	in_fmt = format_to_colorspace(in_pixel_fmt);
+	out_fmt = format_to_colorspace(out_pixel_fmt);
+
+	if (partial) {
+		if (in_fmt == RGB) {
+			if (out_fmt == RGB)
+				ipu->fg_csc_type = RGB2RGB;
+			else
+				ipu->fg_csc_type = RGB2YUV;
+		} else {
+			if (out_fmt == RGB)
+				ipu->fg_csc_type = YUV2RGB;
+			else
+				ipu->fg_csc_type = YUV2YUV;
+		}
+	} else {
+		if (in_fmt == RGB) {
+			if (out_fmt == RGB)
+				ipu->bg_csc_type = RGB2RGB;
+			else
+				ipu->bg_csc_type = RGB2YUV;
+		} else {
+			if (out_fmt == RGB)
+				ipu->bg_csc_type = YUV2RGB;
+			else
+				ipu->bg_csc_type = YUV2YUV;
+		}
+	}
+
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	reg = ipu_dp_read(ipu, DP_COM_CONF(dp));
+	if (ipu->color_key_4rgb && (reg & DP_COM_CONF_GWCKE) &&
+			(((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			 ((ipu->fg_csc_type == YUV2RGB) && (ipu->bg_csc_type == YUV2RGB)))) {
+		int red, green, blue;
+		int y, u, v;
+		uint32_t color_key = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 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 = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(dp)) & 0xFF000000L;
+		ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(dp));
+		ipu->color_key_4rgb = false;
+
+		dev_dbg(ipu->dev, "_ipu_dp_init color key change to yuv fmt 0x%x!\n", color_key);
+	}
+
+	__ipu_dp_csc_setup(ipu, dp, dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type], true);
+
+	return 0;
+}
+
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	int dp;
+	int partial = false;
+
+	if (channel == MEM_FG_SYNC) {
+		dp = DP_SYNC;
+		partial = true;
+	} else if (channel == MEM_BG_SYNC) {
+		dp = DP_SYNC;
+		partial = false;
+	} else if (channel == MEM_BG_ASYNC0) {
+		dp = DP_ASYNC0;
+		partial = false;
+	} else {
+		return;
+	}
+
+	if (partial)
+		ipu->fg_csc_type = CSC_NONE;
+	else
+		ipu->bg_csc_type = CSC_NONE;
+
+	__ipu_dp_csc_setup(ipu, dp, dp_csc_array[ipu->bg_csc_type][ipu->fg_csc_type], false);
+}
+
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt)
+{
+	u32 reg = 0;
+
+	if ((dc_chan == 1) || (dc_chan == 5)) {
+		if (interlaced) {
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 3);
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 2);
+			_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 1);
+		} else {
+			if (di) {
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 2, 3);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 3, 2);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 4, 1);
+				if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+					_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 9, 5);
+					_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 8, 5);
+				}
+			} else {
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 5, 3);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 6, 2);
+				_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 7, 1);
+				if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+					_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 10, 5);
+					_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 11, 5);
+				}
+			}
+		}
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+
+		reg = 0x2;
+		reg |= DC_DISP_ID_SYNC(di) << DC_WR_CH_CONF_PROG_DISP_ID_OFFSET;
+		reg |= di << 2;
+		if (interlaced)
+			reg |= DC_WR_CH_CONF_FIELD_MODE;
+	} else if ((dc_chan == 8) || (dc_chan == 9)) {
+		/* async channels */
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0x64, 1);
+		_ipu_dc_link_event(ipu, 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;
+	}
+	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+	ipu_dc_write(ipu, 0x00000000, DC_WR_CH_ADDR(dc_chan));
+
+	ipu_dc_write(ipu, 0x00000084, DC_GEN);
+}
+
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan)
+{
+	if ((dc_chan == 1) || (dc_chan == 5)) {
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NL, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOL, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOF, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_EOFIELD, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_ODD_UGDE1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVEN_UGDE1, 0, 0);
+	} else if ((dc_chan == 8) || (dc_chan == 9)) {
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_W_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_ADDR_R_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_CHAN_R_1, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_0, 0, 0);
+		_ipu_dc_link_event(ipu, dc_chan, DC_EVT_NEW_DATA_R_1, 0, 0);
+	}
+}
+
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	if (channel == MEM_DC_SYNC)
+		return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_1) &
+			  DC_WR_CH_CONF_FIELD_MODE);
+	else if ((channel == MEM_BG_SYNC) || (channel == MEM_FG_SYNC))
+		return !!(ipu_dc_read(ipu, DC_WR_CH_CONF_5) &
+			  DC_WR_CH_CONF_FIELD_MODE);
+	return 0;
+}
+
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	int di;
+	uint32_t reg;
+	uint32_t dc_chan;
+	int irq = 0;
+
+	if (channel == MEM_FG_SYNC)
+		irq = IPU_IRQ_DP_SF_END;
+	else if (channel == MEM_DC_SYNC)
+		dc_chan = 1;
+	else if (channel == MEM_BG_SYNC)
+		dc_chan = 5;
+	else
+		return;
+
+	if (channel == MEM_FG_SYNC) {
+		/* Enable FG channel */
+		reg = ipu_dp_read(ipu, DP_COM_CONF(DP_SYNC));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_FG_EN, DP_COM_CONF(DP_SYNC));
+
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+		return;
+	}
+
+	di = ipu->dc_di_assignment[dc_chan];
+
+	/* Make sure other DC sync channel is not assigned same DI */
+	reg = ipu_dc_read(ipu, 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;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+	}
+
+	reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+	reg |= 4 << DC_WR_CH_CONF_PROG_TYPE_OFFSET;
+	ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+	clk_enable(&ipu->pixel_clk[di]);
+}
+
+static irqreturn_t dc_irq_handler(int irq, void *dev_id)
+{
+	struct ipu_soc *ipu = dev_id;
+	struct completion *comp = &ipu->dc_comp;
+	uint32_t reg;
+	uint32_t dc_chan;
+
+	if (irq == IPU_IRQ_DC_FC_1)
+		dc_chan = 1;
+	else
+		dc_chan = 5;
+
+	if (!ipu->dc_swap) {
+		reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+
+		reg = ipu_cm_read(ipu, IPU_DISP_GEN);
+		if (ipu->dc_di_assignment[dc_chan])
+			reg &= ~DI1_COUNTER_RELEASE;
+		else
+			reg &= ~DI0_COUNTER_RELEASE;
+		ipu_cm_write(ipu, reg, IPU_DISP_GEN);
+	}
+
+	complete(comp);
+	return IRQ_HANDLED;
+}
+
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap)
+{
+	int ret;
+	uint32_t reg;
+	uint32_t csc;
+	uint32_t dc_chan;
+	int irq = 0;
+	int timeout = 50;
+
+	ipu->dc_swap = swap;
+
+	if (channel == MEM_DC_SYNC) {
+		dc_chan = 1;
+		irq = IPU_IRQ_DC_FC_1;
+	} else if (channel == MEM_BG_SYNC) {
+		dc_chan = 5;
+		irq = IPU_IRQ_DP_SF_END;
+	} else if (channel == MEM_FG_SYNC) {
+		/* Disable FG channel */
+		dc_chan = 5;
+
+		reg = ipu_dp_read(ipu, 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(ipu, reg, DP_COM_CONF(DP_SYNC));
+
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+		ipu_cm_write(ipu, IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END),
+			     IPUIRQ_2_STATREG(IPU_IRQ_DP_SF_END));
+		while ((ipu_cm_read(ipu, IPUIRQ_2_STATREG(IPU_IRQ_DP_SF_END)) &
+			IPUIRQ_2_MASK(IPU_IRQ_DP_SF_END)) == 0) {
+			msleep(2);
+			timeout -= 2;
+			if (timeout <= 0)
+				break;
+		}
+		return;
+	} else {
+		return;
+	}
+
+	init_completion(&ipu->dc_comp);
+	ipu_clear_irq(ipu, irq);
+	ret = ipu_request_irq(ipu, irq, dc_irq_handler, 0, NULL, ipu);
+	if (ret < 0) {
+		dev_err(ipu->dev, "DC irq %d in use\n", irq);
+		return;
+	}
+	ret = wait_for_completion_timeout(&ipu->dc_comp, msecs_to_jiffies(50));
+	ipu_free_irq(ipu, irq, ipu);
+	dev_dbg(ipu->dev, "DC stop timeout - %d * 10ms\n", 5 - ret);
+
+	if (ipu->dc_swap) {
+		/* Swap DC channel 1 and 5 settings, and disable old dc chan */
+		reg = ipu_dc_read(ipu, DC_WR_CH_CONF(dc_chan));
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(6 - dc_chan));
+		reg &= ~DC_WR_CH_CONF_PROG_TYPE_MASK;
+		reg ^= DC_WR_CH_CONF_PROG_DI_ID;
+		ipu_dc_write(ipu, reg, DC_WR_CH_CONF(dc_chan));
+	} else
+		/* Clock is already off because it must be done quickly, but
+		   we need to fix the ref count */
+		clk_disable(&ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]);
+}
+
+void _ipu_init_dc_mappings(struct ipu_soc *ipu)
+{
+	/* IPU_PIX_FMT_RGB24 */
+	_ipu_dc_map_clear(ipu, 0);
+	_ipu_dc_map_config(ipu, 0, 0, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 0, 1, 15, 0xFF);
+	_ipu_dc_map_config(ipu, 0, 2, 23, 0xFF);
+
+	/* IPU_PIX_FMT_RGB666 */
+	_ipu_dc_map_clear(ipu, 1);
+	_ipu_dc_map_config(ipu, 1, 0, 5, 0xFC);
+	_ipu_dc_map_config(ipu, 1, 1, 11, 0xFC);
+	_ipu_dc_map_config(ipu, 1, 2, 17, 0xFC);
+
+	/* IPU_PIX_FMT_YUV444 */
+	_ipu_dc_map_clear(ipu, 2);
+	_ipu_dc_map_config(ipu, 2, 0, 15, 0xFF);
+	_ipu_dc_map_config(ipu, 2, 1, 23, 0xFF);
+	_ipu_dc_map_config(ipu, 2, 2, 7, 0xFF);
+
+	/* IPU_PIX_FMT_RGB565 */
+	_ipu_dc_map_clear(ipu, 3);
+	_ipu_dc_map_config(ipu, 3, 0, 4, 0xF8);
+	_ipu_dc_map_config(ipu, 3, 1, 10, 0xFC);
+	_ipu_dc_map_config(ipu, 3, 2, 15, 0xF8);
+
+	/* IPU_PIX_FMT_LVDS666 */
+	_ipu_dc_map_clear(ipu, 4);
+	_ipu_dc_map_config(ipu, 4, 0, 5, 0xFC);
+	_ipu_dc_map_config(ipu, 4, 1, 13, 0xFC);
+	_ipu_dc_map_config(ipu, 4, 2, 21, 0xFC);
+
+	/* IPU_PIX_FMT_VYUY 16bit width */
+	_ipu_dc_map_clear(ipu, 5);
+	_ipu_dc_map_config(ipu, 5, 0, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 5, 1, 0, 0x0);
+	_ipu_dc_map_config(ipu, 5, 2, 15, 0xFF);
+	_ipu_dc_map_clear(ipu, 6);
+	_ipu_dc_map_config(ipu, 6, 0, 0, 0x0);
+	_ipu_dc_map_config(ipu, 6, 1, 7, 0xFF);
+	_ipu_dc_map_config(ipu, 6, 2, 15, 0xFF);
+
+	/* IPU_PIX_FMT_UYUV 16bit width */
+	_ipu_dc_map_clear(ipu, 7);
+	_ipu_dc_map_link(ipu, 7, 6, 0, 6, 1, 6, 2);
+	_ipu_dc_map_clear(ipu, 8);
+	_ipu_dc_map_link(ipu, 8, 5, 0, 5, 1, 5, 2);
+
+	/* IPU_PIX_FMT_YUYV 16bit width */
+	_ipu_dc_map_clear(ipu, 9);
+	_ipu_dc_map_link(ipu, 9, 5, 2, 5, 1, 5, 0);
+	_ipu_dc_map_clear(ipu, 10);
+	_ipu_dc_map_link(ipu, 10, 5, 1, 5, 2, 5, 0);
+
+	/* IPU_PIX_FMT_YVYU 16bit width */
+	_ipu_dc_map_clear(ipu, 11);
+	_ipu_dc_map_link(ipu, 11, 5, 1, 5, 2, 5, 0);
+	_ipu_dc_map_clear(ipu, 12);
+	_ipu_dc_map_link(ipu, 12, 5, 2, 5, 1, 5, 0);
+
+	/* IPU_PIX_FMT_GBR24 */
+	/* IPU_PIX_FMT_VYU444 */
+	_ipu_dc_map_clear(ipu, 13);
+	_ipu_dc_map_link(ipu, 13, 0, 2, 0, 0, 0, 1);
+
+	/* IPU_PIX_FMT_BGR24 */
+	_ipu_dc_map_clear(ipu, 14);
+	_ipu_dc_map_link(ipu, 14, 0, 2, 0, 1, 0, 0);
+}
+
+int _ipu_pixfmt_to_map(uint32_t 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;
+	case IPU_PIX_FMT_VYUY:
+		return 6;
+	case IPU_PIX_FMT_UYVY:
+		return 8;
+	case IPU_PIX_FMT_YUYV:
+		return 10;
+	case IPU_PIX_FMT_YVYU:
+		return 12;
+	case IPU_PIX_FMT_GBR24:
+	case IPU_PIX_FMT_VYU444:
+		return 13;
+	case IPU_PIX_FMT_BGR24:
+		return 14;
+	}
+
+	return -1;
+}
+
+/*!
+ * This function sets the colorspace for of dp.
+ * modes.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       param         	If it's not NULL, update the csc table
+ *                              with this parameter.
+ *
+ * @return      N/A
+ */
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+	int dp;
+	struct dp_csc_param_t dp_csc_param;
+
+	if (channel == MEM_FG_SYNC)
+		dp = DP_SYNC;
+	else if (channel == MEM_BG_SYNC)
+		dp = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0)
+		dp = DP_ASYNC0;
+	else
+		return;
+
+	dp_csc_param.mode = -1;
+	dp_csc_param.coeff = param;
+	__ipu_dp_csc_setup(ipu, dp, dp_csc_param, true);
+}
+
+void ipu_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3])
+{
+	_ipu_dp_set_csc_coefficients(ipu, channel, param);
+}
+EXPORT_SYMBOL(ipu_set_csc_coefficients);
+
+/*!
+ * This function is called to adapt synchronous LCD panel to IPU restriction.
+ *
+ */
+void adapt_panel_to_ipu_restricitions(struct ipu_soc *ipu, uint16_t *v_start_width,
+					uint16_t *v_sync_width,
+					uint16_t *v_end_width)
+{
+	if (*v_end_width < 2) {
+		uint16_t diff = 2 - *v_end_width;
+		if (*v_start_width >= diff) {
+			*v_end_width = 2;
+			*v_start_width = *v_start_width - diff;
+		} else if (*v_sync_width > diff) {
+			*v_end_width = 2;
+			*v_sync_width = *v_sync_width - diff;
+		} else
+			dev_err(ipu->dev, "WARNING: try to adapt timming, but failed\n");
+		dev_err(ipu->dev, "WARNING: adapt panel end blank lines\n");
+	}
+}
+
+/*!
+ * This function is called to initialize a synchronous LCD panel.
+ *
+ * @param	ipu		ipu handler
+ * @param       disp            The DI the panel is attached to.
+ *
+ * @param       pixel_clk       Desired pixel clock frequency in Hz.
+ *
+ * @param       pixel_fmt       Input parameter for pixel format of buffer.
+ *                              Pixel format is a FOURCC ASCII code.
+ *
+ * @param       width           The width of panel in pixels.
+ *
+ * @param       height          The height of panel in pixels.
+ *
+ * @param       hStartWidth     The number of pixel clocks between the HSYNC
+ *                              signal pulse and the start of valid data.
+ *
+ * @param       hSyncWidth      The width of the HSYNC signal in units of pixel
+ *                              clocks.
+ *
+ * @param       hEndWidth       The number of pixel clocks between the end of
+ *                              valid data and the HSYNC signal for next line.
+ *
+ * @param       vStartWidth     The number of lines between the VSYNC
+ *                              signal pulse and the start of valid data.
+ *
+ * @param       vSyncWidth      The width of the VSYNC signal in units of lines
+ *
+ * @param       vEndWidth       The number of lines between the end of valid
+ *                              data and the VSYNC signal for next frame.
+ *
+ * @param       sig             Bitfield of signal polarities for LCD interface.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_init_sync_panel(struct ipu_soc *ipu, int disp, uint32_t pixel_clk,
+			    uint16_t width, uint16_t height,
+			    uint32_t pixel_fmt,
+			    uint16_t h_start_width, uint16_t h_sync_width,
+			    uint16_t h_end_width, uint16_t v_start_width,
+			    uint16_t v_sync_width, uint16_t v_end_width,
+			    uint32_t v_to_h_sync, ipu_di_signal_cfg_t sig)
+{
+	uint32_t field0_offset = 0;
+	uint32_t field1_offset;
+	uint32_t reg;
+	uint32_t di_gen, vsync_cnt;
+	uint32_t div, rounded_pixel_clk, rounded_parent_clk;
+	uint32_t h_total, v_total;
+	int map;
+	struct clk *di_parent;
+	unsigned long lock_flags;
+
+	dev_dbg(ipu->dev, "panel size = %d x %d\n", width, height);
+
+	if ((v_sync_width == 0) || (h_sync_width == 0))
+		return EINVAL;
+
+	adapt_panel_to_ipu_restricitions(ipu, &v_start_width, &v_sync_width, &v_end_width);
+	h_total = width + h_sync_width + h_start_width + h_end_width;
+	v_total = height + v_sync_width + v_start_width + v_end_width;
+
+	/* Init clocking */
+	dev_dbg(ipu->dev, "pixel clk = %d\n", pixel_clk);
+
+	di_parent = clk_get_parent(ipu->di_clk[disp]);
+	if (clk_get(NULL, "tve_clk") == di_parent ||
+		clk_get(NULL, "ldb_di0_clk") == di_parent ||
+		clk_get(NULL, "ldb_di1_clk") == di_parent) {
+		/* if di clk parent is tve/ldb, then keep it;*/
+		dev_dbg(ipu->dev, "use special clk parent\n");
+		clk_set_parent(&ipu->pixel_clk[disp], ipu->di_clk[disp]);
+	} else {
+		/* try ipu clk first*/
+		dev_dbg(ipu->dev, "try ipu internal clk\n");
+		clk_set_parent(&ipu->pixel_clk[disp], ipu->ipu_clk);
+		rounded_pixel_clk = clk_round_rate(&ipu->pixel_clk[disp], pixel_clk);
+		/*
+		 * we will only use 1/2 fraction for ipu clk,
+		 * so if the clk rate is not fit, try ext clk.
+		 */
+		if (!sig.int_clk &&
+			((rounded_pixel_clk >= pixel_clk + pixel_clk/200) ||
+			(rounded_pixel_clk <= pixel_clk - pixel_clk/200))) {
+			dev_dbg(ipu->dev, "try ipu ext di clk\n");
+			if (clk_get_usecount(di_parent))
+				dev_warn(ipu->dev,
+					"ext di clk already in use, go back to internal clk\n");
+			else {
+				rounded_pixel_clk = pixel_clk * 2;
+				rounded_parent_clk = clk_round_rate(di_parent,
+							rounded_pixel_clk);
+				while (rounded_pixel_clk < rounded_parent_clk) {
+					/* the max divider from parent to di is 8 */
+					if (rounded_parent_clk / pixel_clk < 8)
+						rounded_pixel_clk += pixel_clk * 2;
+					else
+						rounded_pixel_clk *= 2;
+				}
+				clk_set_rate(di_parent, rounded_pixel_clk);
+				rounded_pixel_clk =
+					clk_round_rate(ipu->di_clk[disp], pixel_clk);
+				clk_set_rate(ipu->di_clk[disp], rounded_pixel_clk);
+				clk_set_parent(&ipu->pixel_clk[disp], ipu->di_clk[disp]);
+			}
+		}
+	}
+	rounded_pixel_clk = clk_round_rate(&ipu->pixel_clk[disp], pixel_clk);
+	clk_set_rate(&ipu->pixel_clk[disp], rounded_pixel_clk);
+	msleep(5);
+	/* Get integer portion of divider */
+	div = clk_get_rate(clk_get_parent(&ipu->pixel_clk[disp])) / rounded_pixel_clk;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	_ipu_di_data_wave_config(ipu, disp, SYNC_WAVE, div - 1, div - 1);
+	_ipu_di_data_pin_config(ipu, disp, SYNC_WAVE, DI_PIN15, 3, 0, div * 2);
+
+	map = _ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0) {
+		dev_dbg(ipu->dev, "IPU_DISP: No MAP\n");
+		_ipu_unlock(ipu, &lock_flags);
+		return -EINVAL;
+	}
+
+	/*clear DI*/
+	di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+	ipu_di_write(ipu, disp,
+		di_gen & (0x3 << 20), DI_GENERAL);
+
+	if (sig.interlaced) {
+		if (g_ipu_hw_rev >= 2) {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					1, 		/* counter */
+					h_total/2 - 1, 	/* run count */
+					DI_SYNC_CLK,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					2, 		/* counter */
+					h_total - 1, 	/* run count */
+					DI_SYNC_CLK,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					3, 		/* counter */
+					v_total*2 - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					1, 			/* offset */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					4, 		/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					v_start_width, 	/*  offset */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 		/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Active Line */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					5, 		/* counter */
+					0, 		/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 		/*  offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					height/2, 	/* repeat count */
+					4, 		/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					6, 		/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution */
+					0, 		/* offset */
+					DI_SYNC_NONE, 	/* offset resolution */
+					0, 		/* repeat count */
+					DI_SYNC_NONE, 	/* CNT_CLR_SEL  */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					7, 		/* counter */
+					v_total/2 - 1, 	/* run count */
+					DI_SYNC_HSYNC,	/* run_resolution  */
+					9, 		/* offset  */
+					DI_SYNC_HSYNC, 	/* offset resolution */
+					2, 		/* repeat count */
+					DI_SYNC_VSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					0		/* COUNT DOWN */
+					);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					8, 		/* counter */
+					0, 		/* run count  */
+					DI_SYNC_CLK,	/* run_resolution */
+					h_start_width, 	/* offset  */
+					DI_SYNC_CLK, 	/* offset resolution */
+					width, 		/* repeat count  */
+					5, 		/* CNT_CLR_SEL  */
+					0, 		/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL  */
+					0, 		/* COUNT UP  */
+					0		/* COUNT DOWN */
+					);
+
+			/* Second VSYNC */
+			_ipu_di_sync_config(ipu,
+					disp, 		/* display */
+					9, 		/* counter */
+					v_total - 1, 	/* run count */
+					DI_SYNC_INT_HSYNC,	/* run_resolution */
+					v_total/2, 		/* offset  */
+					DI_SYNC_INT_HSYNC, 	/* offset resolution  */
+					0, 		/* repeat count */
+					DI_SYNC_HSYNC, 	/* CNT_CLR_SEL */
+					0, 		/* CNT_POLARITY_GEN_EN  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_CLR_SEL  */
+					DI_SYNC_NONE, 	/* CNT_POLARITY_TRIGGER_SEL */
+					0, 		/* COUNT UP */
+					2*div		/* COUNT DOWN */
+					);
+
+			/* set gentime select and tag sel */
+			reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+			reg &= 0x1FFFFFFF;
+			reg |= (3-1)<<29 | 0x00008000;
+			ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+			ipu_di_write(ipu, disp, v_total / 2 - 1, DI_SCR_CONF);
+
+			/* set y_sel = 1 */
+			di_gen |= 0x10000000;
+			di_gen |= DI_GEN_POLARITY_5;
+			di_gen |= DI_GEN_POLARITY_8;
+		} else {
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			field1_offset = v_sync_width + v_start_width + height / 2 +
+				v_end_width;
+			if (sig.odd_field_first) {
+				field0_offset = field1_offset - 1;
+				field1_offset = 0;
+			}
+			v_total += v_start_width + v_end_width;
+
+			/* Field 1 VSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 2, v_total - 1, 1,
+					field0_offset,
+					field0_offset ? 1 : DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Setup internal HSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 3, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0,
+					DI_SYNC_NONE, DI_SYNC_NONE, 0, 4);
+
+			/* Active Field ? */
+			_ipu_di_sync_config(ipu, disp, 4,
+					field0_offset ?
+					field0_offset : field1_offset - 2,
+					1, v_start_width + v_sync_width, 1, 2, 2,
+					0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* Active Line */
+			_ipu_di_sync_config(ipu, disp, 5, 0, 1,
+					0, DI_SYNC_NONE,
+					height / 2, 4, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* Field 0 VSYNC waveform */
+			_ipu_di_sync_config(ipu, disp, 6, v_total - 1, 1,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			/* DC VSYNC waveform */
+			vsync_cnt = 7;
+			_ipu_di_sync_config(ipu, disp, 7, 0, 1,
+					field1_offset,
+					field1_offset ? 1 : DI_SYNC_NONE,
+					1, 2, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0, 0);
+
+			/* active pixel waveform */
+			_ipu_di_sync_config(ipu, disp, 8, 0, DI_SYNC_CLK,
+					h_sync_width + h_start_width, DI_SYNC_CLK,
+					width, 5, 0, DI_SYNC_NONE, DI_SYNC_NONE,
+					0, 0);
+
+			/* ??? */
+			_ipu_di_sync_config(ipu, disp, 9, v_total - 1, 2,
+					0, DI_SYNC_NONE,
+					0, DI_SYNC_NONE, 6, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+			reg = ipu_di_read(ipu, disp, DI_SW_GEN1(9));
+			reg |= 0x8000;
+			ipu_di_write(ipu, disp, reg, DI_SW_GEN1(9));
+
+			ipu_di_write(ipu, disp, v_sync_width + v_start_width +
+					v_end_width + height / 2 - 1, DI_SCR_CONF);
+		}
+
+		/* Init template microcode */
+		_ipu_dc_write_tmpl(ipu, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8, 1);
+
+		if (sig.Hsync_pol)
+			di_gen |= DI_GEN_POLARITY_3;
+		if (sig.Vsync_pol)
+			di_gen |= DI_GEN_POLARITY_2;
+	} else {
+		/* Setup internal HSYNC waveform */
+		_ipu_di_sync_config(ipu, disp, 1, h_total - 1, DI_SYNC_CLK,
+					0, DI_SYNC_NONE, 0, DI_SYNC_NONE, 0, DI_SYNC_NONE,
+					DI_SYNC_NONE, 0, 0);
+
+		/* Setup external (delayed) HSYNC waveform */
+		_ipu_di_sync_config(ipu, disp, DI_SYNC_HSYNC, h_total - 1,
+				    DI_SYNC_CLK, div * v_to_h_sync, DI_SYNC_CLK,
+				    0, DI_SYNC_NONE, 1, DI_SYNC_NONE,
+				    DI_SYNC_CLK, 0, h_sync_width * 2);
+		/* Setup VSYNC waveform */
+		vsync_cnt = DI_SYNC_VSYNC;
+		_ipu_di_sync_config(ipu, disp, DI_SYNC_VSYNC, v_total - 1,
+				    DI_SYNC_INT_HSYNC, 0, DI_SYNC_NONE, 0,
+				    DI_SYNC_NONE, 1, DI_SYNC_NONE,
+				    DI_SYNC_INT_HSYNC, 0, v_sync_width * 2);
+		ipu_di_write(ipu, disp, v_total - 1, DI_SCR_CONF);
+
+		/* Setup active data waveform to sync with DC */
+		_ipu_di_sync_config(ipu, disp, 4, 0, DI_SYNC_HSYNC,
+				    v_sync_width + v_start_width, DI_SYNC_HSYNC, height,
+				    DI_SYNC_VSYNC, 0, DI_SYNC_NONE,
+				    DI_SYNC_NONE, 0, 0);
+		_ipu_di_sync_config(ipu, disp, 5, 0, DI_SYNC_CLK,
+				    h_sync_width + h_start_width, DI_SYNC_CLK,
+				    width, 4, 0, DI_SYNC_NONE, DI_SYNC_NONE, 0,
+				    0);
+
+		/* set VGA delayed hsync/vsync no matter VGA enabled */
+		if (disp) {
+			/* couter 7 for VGA delay HSYNC */
+			_ipu_di_sync_config(ipu, disp, 7,
+					h_total - 1, DI_SYNC_CLK,
+					18, DI_SYNC_CLK,
+					0, DI_SYNC_NONE,
+					1, DI_SYNC_NONE, DI_SYNC_CLK,
+					0, h_sync_width * 2);
+
+			/* couter 8 for VGA delay VSYNC */
+			_ipu_di_sync_config(ipu, disp, 8,
+					v_total - 1, DI_SYNC_INT_HSYNC,
+					1, DI_SYNC_INT_HSYNC,
+					0, DI_SYNC_NONE,
+					1, DI_SYNC_NONE, DI_SYNC_INT_HSYNC,
+					0, v_sync_width * 2);
+		}
+
+		/* reset all unused counters */
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN0(6));
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN1(6));
+		if (!disp) {
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN0(7));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN1(7));
+			ipu_di_write(ipu, disp, 0, DI_STP_REP(7));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN0(8));
+			ipu_di_write(ipu, disp, 0, DI_SW_GEN1(8));
+			ipu_di_write(ipu, disp, 0, DI_STP_REP(8));
+		}
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN0(9));
+		ipu_di_write(ipu, disp, 0, DI_SW_GEN1(9));
+		ipu_di_write(ipu, disp, 0, DI_STP_REP(9));
+
+		reg = ipu_di_read(ipu, disp, DI_STP_REP(6));
+		reg &= 0x0000FFFF;
+		ipu_di_write(ipu, disp, reg, DI_STP_REP(6));
+
+		/* Init template microcode */
+		if (disp) {
+			if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+				_ipu_dc_write_tmpl(ipu, 8, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+				_ipu_dc_write_tmpl(ipu, 9, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+				/* configure user events according to DISP NUM */
+				ipu_dc_write(ipu, (width - 1), DC_UGDE_3(disp));
+			}
+			_ipu_dc_write_tmpl(ipu, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+			_ipu_dc_write_tmpl(ipu, 3, WRG, 0, map, SYNC_WAVE, 4, 5, 1);
+			_ipu_dc_write_tmpl(ipu, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+		} else {
+			if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+				(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+				(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+				(pixel_fmt == IPU_PIX_FMT_VYUY)) {
+				_ipu_dc_write_tmpl(ipu, 10, WROD(0), 0, (map - 1), SYNC_WAVE, 0, 5, 1);
+				_ipu_dc_write_tmpl(ipu, 11, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+				/* configure user events according to DISP NUM */
+				ipu_dc_write(ipu, width - 1, DC_UGDE_3(disp));
+			}
+		   _ipu_dc_write_tmpl(ipu, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5, 1);
+		   _ipu_dc_write_tmpl(ipu, 6, WRG, 0, map, SYNC_WAVE, 4, 5, 1);
+		   _ipu_dc_write_tmpl(ipu, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5, 1);
+		}
+
+		if (sig.Hsync_pol) {
+			di_gen |= DI_GEN_POLARITY_2;
+			if (disp)
+				di_gen |= DI_GEN_POLARITY_7;
+		}
+		if (sig.Vsync_pol) {
+			di_gen |= DI_GEN_POLARITY_3;
+			if (disp)
+				di_gen |= DI_GEN_POLARITY_8;
+		}
+	}
+	/* changinc DISP_CLK polarity: it can be wrong for some applications */
+	if ((pixel_fmt == IPU_PIX_FMT_YUYV) ||
+		(pixel_fmt == IPU_PIX_FMT_UYVY) ||
+		(pixel_fmt == IPU_PIX_FMT_YVYU) ||
+		(pixel_fmt == IPU_PIX_FMT_VYUY))
+			di_gen |= 0x00020000;
+
+	if (!sig.clk_pol)
+		di_gen |= DI_GEN_POLARITY_DISP_CLK;
+
+	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+	ipu_di_write(ipu, disp, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) |
+			0x00000002, DI_SYNC_AS_GEN);
+	reg = ipu_di_read(ipu, disp, 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(ipu, disp, reg, DI_POL);
+
+	ipu_dc_write(ipu, width, DC_DISP_CONF2(DC_DISP_ID_SYNC(disp)));
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_sync_panel);
+
+void ipu_uninit_sync_panel(struct ipu_soc *ipu, int disp)
+{
+	uint32_t reg;
+	uint32_t di_gen;
+	unsigned long lock_flags;
+
+	if ((disp != 0) || (disp != 1))
+		return;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+	di_gen |= 0x3ff | DI_GEN_POLARITY_DISP_CLK;
+	ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+	reg = ipu_di_read(ipu, disp, DI_POL);
+	reg |= 0x3ffffff;
+	ipu_di_write(ipu, disp, reg, DI_POL);
+
+	_ipu_unlock(ipu, &lock_flags);
+}
+EXPORT_SYMBOL(ipu_uninit_sync_panel);
+
+int ipu_init_async_panel(struct ipu_soc *ipu, int disp, int type, uint32_t cycle_time,
+			 uint32_t pixel_fmt, ipu_adc_sig_cfg_t sig)
+{
+	int map;
+	u32 ser_conf = 0;
+	u32 div;
+	u32 di_clk = clk_get_rate(ipu->ipu_clk);
+	unsigned long lock_flags;
+
+	/* round up cycle_time, then calcalate the divider using scaled math */
+	cycle_time += (1000000000UL / di_clk) - 1;
+	div = (cycle_time * (di_clk / 256UL)) / (1000000000UL / 256UL);
+
+	map = _ipu_pixfmt_to_map(pixel_fmt);
+	if (map < 0)
+		return -EINVAL;
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if (type == IPU_PANEL_SERIAL) {
+		ipu_di_write(ipu, disp, (div << 24) | ((sig.ifc_width - 1) << 4),
+			     DI_DW_GEN(ASYNC_SER_WAVE));
+
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_CS,
+					0, 0, (div * 2) + 1);
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_CLK,
+					1, div, div * 2);
+		_ipu_di_data_pin_config(ipu, disp, ASYNC_SER_WAVE, DI_PIN_SER_RS,
+					2, 0, 0);
+
+		_ipu_dc_write_tmpl(ipu, 0x64, WROD(0), 0, map, ASYNC_SER_WAVE, 0, 0, 1);
+
+		/* Configure DC for serial panel */
+		ipu_dc_write(ipu, 0x14, DC_DISP_CONF1(DC_DISP_ID_SERIAL));
+
+		if (sig.clk_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_CLK_POL;
+		if (sig.data_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_DATA_POL;
+		if (sig.rs_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_RS_POL;
+		if (sig.cs_pol)
+			ser_conf |= DI_SER_CONF_SERIAL_CS_POL;
+		ipu_di_write(ipu, disp, ser_conf, DI_SER_CONF);
+	}
+
+	_ipu_unlock(ipu, &lock_flags);
+	return 0;
+}
+EXPORT_SYMBOL(ipu_init_async_panel);
+
+/*!
+ * This function sets the foreground and background plane global alpha blending
+ * modes. This function also sets the DP graphic plane according to the
+ * parameter of IPUv3 DP channel.
+ *
+ * @param	ipu		ipu handler
+ * @param	channel		IPUv3 DP channel
+ *
+ * @param       enable          Boolean to enable or disable global alpha
+ *                              blending. If disabled, local blending is used.
+ *
+ * @param       alpha           Global alpha value.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_global_alpha(struct ipu_soc *ipu, ipu_channel_t channel,
+				bool enable, uint8_t alpha)
+{
+	uint32_t reg;
+	uint32_t flow;
+	bool bg_chan;
+	unsigned long lock_flags;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_BG_ASYNC0 ||
+	    channel == MEM_BG_ASYNC1)
+		bg_chan = true;
+	else
+		bg_chan = false;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	if (bg_chan) {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWSEL, DP_COM_CONF(flow));
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0x00FFFFFFL;
+		ipu_dp_write(ipu, reg | ((uint32_t) alpha << 24),
+			     DP_GRAPH_WIND_CTRL(flow));
+
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWAM, DP_COM_CONF(flow));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_global_alpha);
+
+/*!
+ * This function sets the transparent color key for SDC graphic plane.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       enable          Boolean to enable or disable color key
+ *
+ * @param       colorKey        24-bit RGB color for transparent color key.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_color_key(struct ipu_soc *ipu, ipu_channel_t channel,
+				bool enable, uint32_t color_key)
+{
+	uint32_t reg, flow;
+	int y, u, v;
+	int red, green, blue;
+	unsigned long lock_flags;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	ipu->color_key_4rgb = true;
+	/* Transform color key from rgb to yuv if CSC is enabled */
+	if (((ipu->fg_csc_type == RGB2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == RGB2YUV)) ||
+			((ipu->fg_csc_type == YUV2YUV) && (ipu->bg_csc_type == YUV2YUV)) ||
+			((ipu->fg_csc_type == YUV2RGB) && (ipu->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;
+
+		ipu->color_key_4rgb = false;
+
+		dev_dbg(ipu->dev, "color key change to yuv fmt 0x%x\n", color_key);
+	}
+
+	if (enable) {
+		reg = ipu_dp_read(ipu, DP_GRAPH_WIND_CTRL(flow)) & 0xFF000000L;
+		ipu_dp_write(ipu, reg | color_key, DP_GRAPH_WIND_CTRL(flow));
+
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+	} else {
+		reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GWCKE, DP_COM_CONF(flow));
+	}
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_color_key);
+
+/*!
+ * This function sets the gamma correction for DP output.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       enable          Boolean to enable or disable gamma correction.
+ *
+ * @param       constk        	Gamma piecewise linear approximation constk coeff.
+ *
+ * @param       slopek        	Gamma piecewise linear approximation slopek coeff.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_disp_set_gamma_correction(struct ipu_soc *ipu, ipu_channel_t channel, bool enable, int constk[], int slopek[])
+{
+	uint32_t reg, flow, i;
+	unsigned long lock_flags;
+
+	if (channel == MEM_BG_SYNC || channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_BG_ASYNC0 || channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_BG_ASYNC1 || channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	_ipu_get(ipu);
+
+	_ipu_lock(ipu, &lock_flags);
+
+	for (i = 0; i < 8; i++)
+		ipu_dp_write(ipu, (constk[2*i] & 0x1ff) | ((constk[2*i+1] & 0x1ff) << 16), DP_GAMMA_C(flow, i));
+	for (i = 0; i < 4; i++)
+		ipu_dp_write(ipu, (slopek[4*i] & 0xff) | ((slopek[4*i+1] & 0xff) << 8) |
+			((slopek[4*i+2] & 0xff) << 16) | ((slopek[4*i+3] & 0xff) << 24), DP_GAMMA_S(flow, i));
+
+	reg = ipu_dp_read(ipu, DP_COM_CONF(flow));
+	if (enable) {
+		if ((ipu->bg_csc_type == RGB2YUV) || (ipu->bg_csc_type == YUV2YUV))
+			reg |= DP_COM_CONF_GAMMA_YUV_EN;
+		else
+			reg &= ~DP_COM_CONF_GAMMA_YUV_EN;
+		ipu_dp_write(ipu, reg | DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+	} else
+		ipu_dp_write(ipu, reg & ~DP_COM_CONF_GAMMA_EN, DP_COM_CONF(flow));
+
+	reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+	ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+
+	_ipu_unlock(ipu, &lock_flags);
+
+	_ipu_put(ipu);
+
+	return 0;
+}
+EXPORT_SYMBOL(ipu_disp_set_gamma_correction);
+
+/*!
+ * This function sets the window position of the foreground or background plane.
+ * modes.
+ *
+ * @param	ipu		ipu handler
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       x_pos           The X coordinate position to place window at.
+ *                              The position is relative to the top left corner.
+ *
+ * @param       y_pos           The Y coordinate position to place window at.
+ *                              The position is relative to the top left corner.
+ *
+ * @return      Returns 0 on success or negative error code on fail
+ */
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t x_pos, int16_t y_pos)
+{
+	u32 reg;
+	uint32_t flow = 0;
+	uint32_t dp_srm_shift;
+
+	if ((channel == MEM_FG_SYNC) || (channel == MEM_BG_SYNC)) {
+		flow = DP_SYNC;
+		dp_srm_shift = 3;
+	} else if (channel == MEM_FG_ASYNC0) {
+		flow = DP_ASYNC0;
+		dp_srm_shift = 5;
+	} else if (channel == MEM_FG_ASYNC1) {
+		flow = DP_ASYNC1;
+		dp_srm_shift = 7;
+	} else
+		return -EINVAL;
+
+	ipu_dp_write(ipu, (x_pos << 16) | y_pos, DP_FG_POS(flow));
+
+	if (ipu_is_channel_busy(ipu, channel)) {
+		/* controled by FSU if channel enabled */
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+		reg |= (0x1 << dp_srm_shift);
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	} else {
+		/* disable auto swap, controled by MCU if channel disabled */
+		reg = ipu_cm_read(ipu, IPU_SRM_PRI2) & (~(0x3 << dp_srm_shift));
+		ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+	}
+
+	return 0;
+}
+
+int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t x_pos, int16_t y_pos)
+{
+	int ret;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+	_ipu_lock(ipu, &lock_flags);
+	ret = _ipu_disp_set_window_pos(ipu, channel, x_pos, y_pos);
+	_ipu_unlock(ipu, &lock_flags);
+	_ipu_put(ipu);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_disp_set_window_pos);
+
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t *x_pos, int16_t *y_pos)
+{
+	u32 reg;
+	uint32_t flow = 0;
+
+	if (channel == MEM_FG_SYNC)
+		flow = DP_SYNC;
+	else if (channel == MEM_FG_ASYNC0)
+		flow = DP_ASYNC0;
+	else if (channel == MEM_FG_ASYNC1)
+		flow = DP_ASYNC1;
+	else
+		return -EINVAL;
+
+	reg = ipu_dp_read(ipu, DP_FG_POS(flow));
+
+	*x_pos = (reg >> 16) & 0x7FF;
+	*y_pos = reg & 0x7FF;
+
+	return 0;
+}
+int32_t ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+				int16_t *x_pos, int16_t *y_pos)
+{
+	int ret;
+	unsigned long lock_flags;
+
+	_ipu_get(ipu);
+	_ipu_lock(ipu, &lock_flags);
+	ret = _ipu_disp_get_window_pos(ipu, channel, x_pos, y_pos);
+	_ipu_unlock(ipu, &lock_flags);
+	_ipu_put(ipu);
+	return ret;
+}
+EXPORT_SYMBOL(ipu_disp_get_window_pos);
+
+void ipu_disp_direct_write(struct ipu_soc *ipu, ipu_channel_t channel, u32 value, u32 offset)
+{
+	if (channel == DIRECT_ASYNC0)
+		writel(value, ipu->disp_base[0] + offset);
+	else if (channel == DIRECT_ASYNC1)
+		writel(value, ipu->disp_base[1] + offset);
+}
+EXPORT_SYMBOL(ipu_disp_direct_write);
+
+void ipu_reset_disp_panel(struct ipu_soc *ipu)
+{
+	uint32_t tmp;
+
+	tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+	ipu_di_write(ipu, 1, tmp | 0x08, DI_GENERAL);
+	msleep(10); /* tRES >= 100us */
+	tmp = ipu_di_read(ipu, 1, DI_GENERAL);
+	ipu_di_write(ipu, 1, tmp & ~0x08, DI_GENERAL);
+	msleep(60);
+
+	return;
+}
+EXPORT_SYMBOL(ipu_reset_disp_panel);
+
+void __devinit ipu_disp_init(struct ipu_soc *ipu)
+{
+	ipu->fg_csc_type = ipu->bg_csc_type = CSC_NONE;
+	ipu->color_key_4rgb = true;
+	_ipu_init_dc_mappings(ipu);
+	_ipu_dmfc_init(ipu, DMFC_NORMAL, 1);
+}
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
new file mode 100644
index 0000000..7a31da2
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright 2005-2011 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
+ */
+
+/*
+ * @file ipu_ic.c
+ *
+ * @brief IPU IC functions
+ *
+ * @ingroup IPU
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/videodev2.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+#include "ipu_param_mem.h"
+
+enum {
+	IC_TASK_VIEWFINDER,
+	IC_TASK_ENCODER,
+	IC_TASK_POST_PROCESSOR
+};
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+		      ipu_color_space_t out_format, int csc_index);
+static bool _calc_resize_coeffs(struct ipu_soc *ipu,
+				uint32_t inSize, uint32_t outSize,
+				uint32_t *resizeCoeff,
+				uint32_t *downsizeCoeff);
+
+void _ipu_vdi_set_top_field_man(struct ipu_soc *ipu, bool top_field_0)
+{
+	uint32_t reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	if (top_field_0)
+		reg &= ~VDI_C_TOP_FIELD_MAN_1;
+	else
+		reg |= VDI_C_TOP_FIELD_MAN_1;
+	ipu_vdi_write(ipu, reg, VDI_C);
+}
+
+void _ipu_vdi_set_motion(struct ipu_soc *ipu, ipu_motion_sel motion_sel)
+{
+	uint32_t reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
+	if (motion_sel == HIGH_MOTION)
+		reg |= VDI_C_MOT_SEL_FULL;
+	else if (motion_sel == MED_MOTION)
+		reg |= VDI_C_MOT_SEL_MED;
+	else
+		reg |= VDI_C_MOT_SEL_LOW;
+
+	ipu_vdi_write(ipu, reg, VDI_C);
+}
+
+void ic_dump_register(struct ipu_soc *ipu)
+{
+	printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", ipu_ic_read(ipu, IC_CONF));
+	printk(KERN_DEBUG "IC_PRP_ENC_RSC = \t0x%08X\n",
+	       ipu_ic_read(ipu, IC_PRP_ENC_RSC));
+	printk(KERN_DEBUG "IC_PRP_VF_RSC = \t0x%08X\n",
+	       ipu_ic_read(ipu, IC_PRP_VF_RSC));
+	printk(KERN_DEBUG "IC_PP_RSC = \t0x%08X\n", ipu_ic_read(ipu, IC_PP_RSC));
+	printk(KERN_DEBUG "IC_IDMAC_1 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_1));
+	printk(KERN_DEBUG "IC_IDMAC_2 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_2));
+	printk(KERN_DEBUG "IC_IDMAC_3 = \t0x%08X\n", ipu_ic_read(ipu, IC_IDMAC_3));
+}
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t ic_conf;
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+	switch (channel) {
+	case CSI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN;
+		break;
+	case MEM_ROT_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_ROT_EN;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case MEM_PRP_ENC_MEM:
+		ic_conf |= IC_CONF_PRPENC_EN;
+		break;
+	case MEM_ROT_ENC_MEM:
+		ic_conf |= IC_CONF_PRPENC_ROT_EN;
+		break;
+	case MEM_PP_MEM:
+		ic_conf |= IC_CONF_PP_EN;
+		break;
+	case MEM_ROT_PP_MEM:
+		ic_conf |= IC_CONF_PP_ROT_EN;
+		break;
+	default:
+		break;
+	}
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+	uint32_t ic_conf;
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+	switch (channel) {
+	case CSI_PRP_VF_MEM:
+	case MEM_PRP_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_EN;
+		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_EN;
+		break;
+	case MEM_ROT_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
+		break;
+	case CSI_PRP_ENC_MEM:
+	case MEM_PRP_ENC_MEM:
+		ic_conf &= ~IC_CONF_PRPENC_EN;
+		break;
+	case MEM_ROT_ENC_MEM:
+		ic_conf &= ~IC_CONF_PRPENC_ROT_EN;
+		break;
+	case MEM_PP_MEM:
+		ic_conf &= ~IC_CONF_PP_EN;
+		break;
+	case MEM_ROT_PP_MEM:
+		ic_conf &= ~IC_CONF_PP_ROT_EN;
+		break;
+	default:
+		break;
+	}
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params)
+{
+	uint32_t reg;
+	uint32_t pixel_fmt;
+
+	reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
+	  (params->mem_prp_vf_mem.in_width-1);
+	ipu_vdi_write(ipu, reg, VDI_FSIZE);
+
+	/* Full motion, only vertical filter is used
+	   Burst size is 4 accesses */
+	if (params->mem_prp_vf_mem.in_pixel_fmt ==
+	     IPU_PIX_FMT_UYVY ||
+	     params->mem_prp_vf_mem.in_pixel_fmt ==
+	     IPU_PIX_FMT_YUYV)
+		pixel_fmt = VDI_C_CH_422;
+	else
+		pixel_fmt = VDI_C_CH_420;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	reg |= pixel_fmt;
+	switch (channel) {
+	case MEM_VDI_PRP_VF_MEM:
+		reg |= VDI_C_BURST_SIZE2_4;
+		break;
+	case MEM_VDI_PRP_VF_MEM_P:
+		reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
+		break;
+	case MEM_VDI_PRP_VF_MEM_N:
+		reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
+		break;
+	default:
+		break;
+	}
+	ipu_vdi_write(ipu, reg, VDI_C);
+
+	if (params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_TB)
+		_ipu_vdi_set_top_field_man(ipu, false);
+	else if (params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_BT)
+		_ipu_vdi_set_top_field_man(ipu, true);
+
+	_ipu_vdi_set_motion(ipu, params->mem_prp_vf_mem.motion_sel);
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_RWS_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_vdi_uninit(struct ipu_soc *ipu)
+{
+	ipu_vdi_write(ipu, 0, VDI_FSIZE);
+	ipu_vdi_write(ipu, 0, VDI_C);
+}
+
+void _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params, bool src_is_csi)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+
+	/* Setup vertical resizing */
+	if (!(params->mem_prp_vf_mem.outv_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_height,
+				params->mem_prp_vf_mem.out_height,
+				&resizeCoeff, &downsizeCoeff);
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else
+		reg = (params->mem_prp_vf_mem.outv_resize_ratio) << 16;
+
+	/* Setup horizontal resizing */
+	/* Upadeted for IC split case */
+	if (!(params->mem_prp_vf_mem.outh_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_prp_vf_mem.in_width,
+				params->mem_prp_vf_mem.out_width,
+				&resizeCoeff, &downsizeCoeff);
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else
+		reg |= params->mem_prp_vf_mem.outh_resize_ratio;
+
+	ipu_ic_write(ipu, reg, IC_PRP_VF_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (params->mem_prp_vf_mem.graphics_combine_en) {
+		ic_conf |= IC_CONF_PRPVF_CMB;
+
+		if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
+			/* need transparent CSC1 conversion */
+			_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, RGB, 1);
+			ic_conf |= IC_CONF_PRPVF_CSC1;  /* Enable RGB->RGB CSC */
+		}
+		in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
+		out_fmt = format_to_colorspace(params->mem_prp_vf_mem.out_pixel_fmt);
+		if (in_fmt == RGB) {
+			if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+				/* Enable RGB->YCBCR CSC2 */
+				_init_csc(ipu, IC_TASK_VIEWFINDER, RGB, out_fmt, 2);
+				ic_conf |= IC_CONF_PRPVF_CSC2;
+			}
+		}
+		if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+			if (out_fmt == RGB) {
+				/* Enable YCBCR->RGB CSC2 */
+				_init_csc(ipu, IC_TASK_VIEWFINDER, YCbCr, RGB, 2);
+				ic_conf |= IC_CONF_PRPVF_CSC2;
+			} else {
+				/* TODO: Support YUV<->YCbCr conversion? */
+			}
+		}
+
+		if (params->mem_prp_vf_mem.global_alpha_en) {
+			ic_conf |= IC_CONF_IC_GLB_LOC_A;
+			reg = ipu_ic_read(ipu, IC_CMBP_1);
+			reg &= ~(0xff);
+			reg |= params->mem_prp_vf_mem.alpha;
+			ipu_ic_write(ipu, reg, IC_CMBP_1);
+		} else
+			ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+		if (params->mem_prp_vf_mem.key_color_en) {
+			ic_conf |= IC_CONF_KEY_COLOR_EN;
+			ipu_ic_write(ipu, params->mem_prp_vf_mem.key_color,
+					IC_CMBP_2);
+		} else
+			ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+	} else {
+		ic_conf &= ~IC_CONF_PRPVF_CMB;
+	}
+
+	if (src_is_csi)
+		ic_conf &= ~IC_CONF_RWS_EN;
+	else
+		ic_conf |= IC_CONF_RWS_EN;
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPVF_EN | IC_CONF_PRPVF_CMB |
+		 IC_CONF_PRPVF_CSC2 | IC_CONF_PRPVF_CSC1);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_PRPVF_ROT_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params, bool src_is_csi)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+
+	/* Setup vertical resizing */
+	if (!(params->mem_prp_enc_mem.outv_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_height,
+				params->mem_prp_enc_mem.out_height,
+				&resizeCoeff, &downsizeCoeff);
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else
+		reg = (params->mem_prp_enc_mem.outv_resize_ratio) << 16;
+
+	/* Setup horizontal resizing */
+	/* Upadeted for IC split case */
+	if (!(params->mem_prp_enc_mem.outh_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_prp_enc_mem.in_width,
+				params->mem_prp_enc_mem.out_width,
+				&resizeCoeff, &downsizeCoeff);
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else
+		reg |= params->mem_prp_enc_mem.outh_resize_ratio;
+
+	ipu_ic_write(ipu, reg, IC_PRP_ENC_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_prp_enc_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_prp_enc_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_ENCODER, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PRPENC_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_ENCODER, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PRPENC_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (src_is_csi)
+		ic_conf &= ~IC_CONF_RWS_EN;
+	else
+		ic_conf |= IC_CONF_RWS_EN;
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPENC_EN | IC_CONF_PRPENC_CSC1);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PRPENC_ROT_EN);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+	uint32_t reg, ic_conf;
+	uint32_t downsizeCoeff, resizeCoeff;
+	ipu_color_space_t in_fmt, out_fmt;
+
+	/* Setup vertical resizing */
+	if (!(params->mem_pp_mem.outv_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_pp_mem.in_height,
+			    params->mem_pp_mem.out_height,
+			    &resizeCoeff, &downsizeCoeff);
+		reg = (downsizeCoeff << 30) | (resizeCoeff << 16);
+	} else {
+		reg = (params->mem_pp_mem.outv_resize_ratio) << 16;
+	}
+
+	/* Setup horizontal resizing */
+	/* Upadeted for IC split case */
+	if (!(params->mem_pp_mem.outh_resize_ratio)) {
+		_calc_resize_coeffs(ipu, params->mem_pp_mem.in_width,
+							params->mem_pp_mem.out_width,
+							&resizeCoeff, &downsizeCoeff);
+		reg |= (downsizeCoeff << 14) | resizeCoeff;
+	} else {
+		reg |= params->mem_pp_mem.outh_resize_ratio;
+	}
+
+	ipu_ic_write(ipu, reg, IC_PP_RSC);
+
+	ic_conf = ipu_ic_read(ipu, IC_CONF);
+
+	/* Setup color space conversion */
+	in_fmt = format_to_colorspace(params->mem_pp_mem.in_pixel_fmt);
+	out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+	if (in_fmt == RGB) {
+		if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+			/* Enable RGB->YCBCR CSC1 */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 1);
+			ic_conf |= IC_CONF_PP_CSC1;
+		}
+	}
+	if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+		if (out_fmt == RGB) {
+			/* Enable YCBCR->RGB CSC1 */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 1);
+			ic_conf |= IC_CONF_PP_CSC1;
+		} else {
+			/* TODO: Support YUV<->YCbCr conversion? */
+		}
+	}
+
+	if (params->mem_pp_mem.graphics_combine_en) {
+		ic_conf |= IC_CONF_PP_CMB;
+
+		if (!(ic_conf & IC_CONF_PP_CSC1)) {
+			/* need transparent CSC1 conversion */
+			_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
+			ic_conf |= IC_CONF_PP_CSC1;  /* Enable RGB->RGB CSC */
+		}
+
+		in_fmt = format_to_colorspace(params->mem_pp_mem.in_g_pixel_fmt);
+		out_fmt = format_to_colorspace(params->mem_pp_mem.out_pixel_fmt);
+		if (in_fmt == RGB) {
+			if ((out_fmt == YCbCr) || (out_fmt == YUV)) {
+				/* Enable RGB->YCBCR CSC2 */
+				_init_csc(ipu, IC_TASK_POST_PROCESSOR, RGB, out_fmt, 2);
+				ic_conf |= IC_CONF_PP_CSC2;
+			}
+		}
+		if ((in_fmt == YCbCr) || (in_fmt == YUV)) {
+			if (out_fmt == RGB) {
+				/* Enable YCBCR->RGB CSC2 */
+				_init_csc(ipu, IC_TASK_POST_PROCESSOR, YCbCr, RGB, 2);
+				ic_conf |= IC_CONF_PP_CSC2;
+			} else {
+				/* TODO: Support YUV<->YCbCr conversion? */
+			}
+		}
+
+		if (params->mem_pp_mem.global_alpha_en) {
+			ic_conf |= IC_CONF_IC_GLB_LOC_A;
+			reg = ipu_ic_read(ipu, IC_CMBP_1);
+			reg &= ~(0xff00);
+			reg |= (params->mem_pp_mem.alpha << 8);
+			ipu_ic_write(ipu, reg, IC_CMBP_1);
+		} else
+			ic_conf &= ~IC_CONF_IC_GLB_LOC_A;
+
+		if (params->mem_pp_mem.key_color_en) {
+			ic_conf |= IC_CONF_KEY_COLOR_EN;
+			ipu_ic_write(ipu, params->mem_pp_mem.key_color,
+					IC_CMBP_2);
+		} else
+			ic_conf &= ~IC_CONF_KEY_COLOR_EN;
+	} else {
+		ic_conf &= ~IC_CONF_PP_CMB;
+	}
+
+	ipu_ic_write(ipu, ic_conf, IC_CONF);
+}
+
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~(IC_CONF_PP_EN | IC_CONF_PP_CSC1 | IC_CONF_PP_CSC2 |
+		 IC_CONF_PP_CMB);
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params)
+{
+}
+
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	reg = ipu_ic_read(ipu, IC_CONF);
+	reg &= ~IC_CONF_PP_ROT_EN;
+	ipu_ic_write(ipu, reg, IC_CONF);
+}
+
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
+		uint16_t width, uint16_t height,
+		int burst_size, ipu_rotate_mode_t rot)
+{
+	u32 ic_idmac_1, ic_idmac_2, ic_idmac_3;
+	u32 temp_rot = bitrev8(rot) >> 5;
+	bool need_hor_flip = false;
+
+	if ((burst_size != 8) && (burst_size != 16)) {
+		dev_dbg(ipu->dev, "Illegal burst length for IC\n");
+		return -EINVAL;
+	}
+
+	width--;
+	height--;
+
+	if (temp_rot & 0x2)	/* Need horizontal flip */
+		need_hor_flip = true;
+
+	ic_idmac_1 = ipu_ic_read(ipu, IC_IDMAC_1);
+	ic_idmac_2 = ipu_ic_read(ipu, IC_IDMAC_2);
+	ic_idmac_3 = ipu_ic_read(ipu, IC_IDMAC_3);
+	if (dma_chan == 22) {	/* PP output - CB2 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB2_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB2_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PP_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PP_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PP_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PP_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PP_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PP_WIDTH_OFFSET;
+	} else if (dma_chan == 11) {	/* PP Input - CB5 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB5_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB5_BURST_16;
+	} else if (dma_chan == 47) {	/* PP Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PP_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PP_ROT_OFFSET;
+	}
+
+	if (dma_chan == 12) {	/* PRP Input - CB6 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB6_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB6_BURST_16;
+	}
+
+	if (dma_chan == 20) {	/* PRP ENC output - CB0 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB0_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB0_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPENC_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPENC_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPENC_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPENC_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPENC_WIDTH_OFFSET;
+
+	} else if (dma_chan == 45) {	/* PRP ENC Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPENC_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPENC_ROT_OFFSET;
+	}
+
+	if (dma_chan == 21) {	/* PRP VF output - CB1 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB1_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB1_BURST_16;
+
+		if (need_hor_flip)
+			ic_idmac_1 |= IC_IDMAC_1_PRPVF_FLIP_RS;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_FLIP_RS;
+
+		ic_idmac_2 &= ~IC_IDMAC_2_PRPVF_HEIGHT_MASK;
+		ic_idmac_2 |= height << IC_IDMAC_2_PRPVF_HEIGHT_OFFSET;
+
+		ic_idmac_3 &= ~IC_IDMAC_3_PRPVF_WIDTH_MASK;
+		ic_idmac_3 |= width << IC_IDMAC_3_PRPVF_WIDTH_OFFSET;
+
+	} else if (dma_chan == 46) {	/* PRP VF Rot input */
+		ic_idmac_1 &= ~IC_IDMAC_1_PRPVF_ROT_MASK;
+		ic_idmac_1 |= temp_rot << IC_IDMAC_1_PRPVF_ROT_OFFSET;
+	}
+
+	if (dma_chan == 14) {	/* PRP VF graphics combining input - CB3 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB3_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB3_BURST_16;
+	} else if (dma_chan == 15) {	/* PP graphics combining input - CB4 */
+		if (burst_size == 16)
+			ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
+		else
+			ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+	}
+
+	ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
+	ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
+	ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
+
+	return 0;
+}
+
+static void _init_csc(struct ipu_soc *ipu, uint8_t ic_task, ipu_color_space_t in_format,
+		      ipu_color_space_t out_format, int csc_index)
+{
+
+/*     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 uint32_t rgb2ycbcr_coeff[4][3] = {
+		{0x004D, 0x0096, 0x001D},
+		{0x01D5, 0x01AB, 0x0080},
+		{0x0080, 0x0195, 0x01EB},
+		{0x0000, 0x0200, 0x0200},	/* A0, A1, A2 */
+	};
+
+	/* transparent RGB->RGB matrix for combining
+	 */
+	static const uint32_t rgb2rgb_coeff[4][3] = {
+		{0x0080, 0x0000, 0x0000},
+		{0x0000, 0x0080, 0x0000},
+		{0x0000, 0x0000, 0x0080},
+		{0x0000, 0x0000, 0x0000},	/* A0, A1, A2 */
+	};
+
+/*     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 uint32_t ycbcr2rgb_coeff[4][3] = {
+		{149, 0, 204},
+		{149, 462, 408},
+		{149, 255, 0},
+		{8192 - 446, 266, 8192 - 554},	/* A0, A1, A2 */
+	};
+
+	uint32_t param;
+	uint32_t *base = NULL;
+
+	if (ic_task == IC_TASK_ENCODER) {
+		base = ipu->tpmem_base + 0x2008 / 4;
+	} else if (ic_task == IC_TASK_VIEWFINDER) {
+		if (csc_index == 1)
+			base = ipu->tpmem_base + 0x4028 / 4;
+		else
+			base = ipu->tpmem_base + 0x4040 / 4;
+	} else if (ic_task == IC_TASK_POST_PROCESSOR) {
+		if (csc_index == 1)
+			base = ipu->tpmem_base + 0x6060 / 4;
+		else
+			base = ipu->tpmem_base + 0x6078 / 4;
+	} else {
+		BUG();
+	}
+
+	if ((in_format == YCbCr) && (out_format == RGB)) {
+		/* Init CSC (YCbCr->RGB) */
+		param = (ycbcr2rgb_coeff[3][0] << 27) |
+			(ycbcr2rgb_coeff[0][0] << 18) |
+			(ycbcr2rgb_coeff[1][1] << 9) | ycbcr2rgb_coeff[2][2];
+		writel(param, base++);
+		/* scale = 2, sat = 0 */
+		param = (ycbcr2rgb_coeff[3][0] >> 5) | (2L << (40 - 32));
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][1] << 27) |
+			(ycbcr2rgb_coeff[0][1] << 18) |
+			(ycbcr2rgb_coeff[1][0] << 9) | ycbcr2rgb_coeff[2][0];
+		writel(param, base++);
+		param = (ycbcr2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (ycbcr2rgb_coeff[3][2] << 27) |
+			(ycbcr2rgb_coeff[0][2] << 18) |
+			(ycbcr2rgb_coeff[1][2] << 9) | ycbcr2rgb_coeff[2][1];
+		writel(param, base++);
+		param = (ycbcr2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if ((in_format == RGB) && (out_format == YCbCr)) {
+		/* Init CSC (RGB->YCbCr) */
+		param = (rgb2ycbcr_coeff[3][0] << 27) |
+			(rgb2ycbcr_coeff[0][0] << 18) |
+			(rgb2ycbcr_coeff[1][1] << 9) | rgb2ycbcr_coeff[2][2];
+		writel(param, base++);
+		/* scale = 1, sat = 0 */
+		param = (rgb2ycbcr_coeff[3][0] >> 5) | (1UL << 8);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][1] << 27) |
+			(rgb2ycbcr_coeff[0][1] << 18) |
+			(rgb2ycbcr_coeff[1][0] << 9) | rgb2ycbcr_coeff[2][0];
+		writel(param, base++);
+		param = (rgb2ycbcr_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param = (rgb2ycbcr_coeff[3][2] << 27) |
+			(rgb2ycbcr_coeff[0][2] << 18) |
+			(rgb2ycbcr_coeff[1][2] << 9) | rgb2ycbcr_coeff[2][1];
+		writel(param, base++);
+		param = (rgb2ycbcr_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else if ((in_format == RGB) && (out_format == RGB)) {
+		/* Init CSC */
+		param =
+		    (rgb2rgb_coeff[3][0] << 27) | (rgb2rgb_coeff[0][0] << 18) |
+		    (rgb2rgb_coeff[1][1] << 9) | rgb2rgb_coeff[2][2];
+		writel(param, base++);
+		/* scale = 2, sat = 0 */
+		param = (rgb2rgb_coeff[3][0] >> 5) | (2UL << 8);
+		writel(param, base++);
+
+		param =
+		    (rgb2rgb_coeff[3][1] << 27) | (rgb2rgb_coeff[0][1] << 18) |
+		    (rgb2rgb_coeff[1][0] << 9) | rgb2rgb_coeff[2][0];
+		writel(param, base++);
+		param = (rgb2rgb_coeff[3][1] >> 5);
+		writel(param, base++);
+
+		param =
+		    (rgb2rgb_coeff[3][2] << 27) | (rgb2rgb_coeff[0][2] << 18) |
+		    (rgb2rgb_coeff[1][2] << 9) | rgb2rgb_coeff[2][1];
+		writel(param, base++);
+		param = (rgb2rgb_coeff[3][2] >> 5);
+		writel(param, base++);
+	} else {
+		dev_err(ipu->dev, "Unsupported color space conversion\n");
+	}
+}
+
+static bool _calc_resize_coeffs(struct ipu_soc *ipu,
+				uint32_t inSize, uint32_t outSize,
+				uint32_t *resizeCoeff,
+				uint32_t *downsizeCoeff)
+{
+	uint32_t tempSize;
+	uint32_t tempDownsize;
+
+	/* Input size cannot be more than 4096 */
+	/* Output size cannot be more than 1024 */
+	if ((inSize > 4096) || (outSize > 1024))
+		return false;
+
+	/* Cannot downsize more than 8:1 */
+	if ((outSize << 3) < inSize)
+		return false;
+
+	/* Compute downsizing coefficient */
+	/* Output of downsizing unit cannot be more than 1024 */
+	tempDownsize = 0;
+	tempSize = inSize;
+	while (((tempSize > 1024) || (tempSize >= outSize * 2)) &&
+	       (tempDownsize < 2)) {
+		tempSize >>= 1;
+		tempDownsize++;
+	}
+	*downsizeCoeff = tempDownsize;
+
+	/* compute resizing coefficient using the following equation:
+	   resizeCoeff = M*(SI -1)/(SO - 1)
+	   where M = 2^13, SI - input size, SO - output size    */
+	*resizeCoeff = (8192L * (tempSize - 1)) / (outSize - 1);
+	if (*resizeCoeff >= 16384L) {
+		dev_err(ipu->dev, "Warning! Overflow on resize coeff.\n");
+		*resizeCoeff = 0x3FFF;
+	}
+
+	dev_dbg(ipu->dev, "resizing from %u -> %u pixels, "
+		"downsize=%u, resize=%u.%lu (reg=%u)\n", inSize, outSize,
+		*downsizeCoeff, (*resizeCoeff >= 8192L) ? 1 : 0,
+		((*resizeCoeff & 0x1FFF) * 10000L) / 8192L, *resizeCoeff);
+
+	return true;
+}
+
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu)
+{
+	uint32_t reg;
+	uint32_t mask_reg;
+
+	reg = ipu_vdi_read(ipu, VDI_C);
+	mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
+	if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
+		reg &= ~VDI_C_TOP_FIELD_MAN_1;
+	else
+		reg |= VDI_C_TOP_FIELD_MAN_1;
+
+	ipu_vdi_write(ipu, reg, VDI_C);
+}
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
new file mode 100644
index 0000000..d2ad269
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -0,0 +1,798 @@
+/*
+ * Copyright 2005-2011 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
+ */
+#ifndef __INCLUDE_IPU_PARAM_MEM_H__
+#define __INCLUDE_IPU_PARAM_MEM_H__
+
+#include <linux/types.h>
+#include <linux/bitrev.h>
+
+extern u32 *ipu_cpmem_base;
+
+struct ipu_ch_param_word {
+	uint32_t data[5];
+	uint32_t res[3];
+};
+
+struct ipu_ch_param {
+	struct ipu_ch_param_word word[2];
+};
+
+#define ipu_ch_param_addr(ipu, ch) (((struct ipu_ch_param *)ipu->cpmem_base) + (ch))
+
+#define _param_word(base, w) \
+	(((struct ipu_ch_param *)(base))->word[(w)].data)
+
+#define ipu_ch_param_set_field(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	_param_word(base, w)[i] |= (v) << off; \
+	if (((bit)+(size)-1)/32 > i) { \
+		_param_word(base, w)[i + 1] |= (v) >> (off ? (32 - off) : 0); \
+	} \
+}
+
+#define ipu_ch_param_set_field_io(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	unsigned reg_offset; \
+	u32 temp; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
+	reg_offset += i; \
+	temp = readl((u32 *)base + reg_offset); \
+	temp |= (v) << off; \
+	writel(temp, (u32 *)base + reg_offset); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp = readl((u32 *)base + reg_offset); \
+		temp |= (v) >> (off ? (32 - off) : 0); \
+		writel(temp, (u32 *)base + reg_offset); \
+	} \
+}
+
+#define ipu_ch_param_mod_field(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << size) - 1; \
+	u32 temp = _param_word(base, w)[i]; \
+	temp &= ~(mask << off); \
+	_param_word(base, w)[i] = temp | (v) << off; \
+	if (((bit)+(size)-1)/32 > i) { \
+		temp = _param_word(base, w)[i + 1]; \
+		temp &= ~(mask >> (32 - off)); \
+		_param_word(base, w)[i + 1] = \
+			temp | ((v) >> (off ? (32 - off) : 0)); \
+	} \
+}
+
+#define ipu_ch_param_mod_field_io(base, w, bit, size, v) { \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << size) - 1; \
+	unsigned reg_offset; \
+	u32 temp; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
+	reg_offset += i; \
+	temp = readl((u32 *)base + reg_offset); \
+	temp &= ~(mask << off); \
+	temp |= (v) << off; \
+	writel(temp, (u32 *)base + reg_offset); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp = readl((u32 *)base + reg_offset); \
+		temp &= ~(mask >> (32 - off)); \
+		temp |= ((v) >> (off ? (32 - off) : 0)); \
+		writel(temp, (u32 *)base + reg_offset); \
+	} \
+}
+
+#define ipu_ch_param_read_field(base, w, bit, size) ({ \
+	u32 temp2; \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << size) - 1; \
+	u32 temp1 = _param_word(base, w)[i]; \
+	temp1 = mask & (temp1 >> off); \
+	if (((bit)+(size)-1)/32 > i) { \
+		temp2 = _param_word(base, w)[i + 1]; \
+		temp2 &= mask >> (off ? (32 - off) : 0); \
+		temp1 |= temp2 << (off ? (32 - off) : 0); \
+	} \
+	temp1; \
+})
+
+#define ipu_ch_param_read_field_io(base, w, bit, size) ({ \
+	u32 temp1, temp2; \
+	int i = (bit) / 32; \
+	int off = (bit) % 32; \
+	u32 mask = (1UL << size) - 1; \
+	unsigned reg_offset; \
+	reg_offset = sizeof(struct ipu_ch_param_word) * w / 4; \
+	reg_offset += i; \
+	temp1 = readl((u32 *)base + reg_offset); \
+	temp1 = mask & (temp1 >> off); \
+	if (((bit)+(size)-1)/32 > i) { \
+		reg_offset++; \
+		temp2 = readl((u32 *)base + reg_offset); \
+		temp2 &= mask >> (off ? (32 - off) : 0); \
+		temp1 |= temp2 << (off ? (32 - off) : 0); \
+	} \
+	temp1; \
+})
+
+static inline int __ipu_ch_get_third_buf_cpmem_num(int ch)
+{
+	switch (ch) {
+	case 8:
+		return 64;
+	case 9:
+		return 65;
+	case 10:
+		return 66;
+	case 13:
+		return 67;
+	case 21:
+		return 68;
+	case 23:
+		return 69;
+	case 27:
+		return 70;
+	case 28:
+		return 71;
+	default:
+		return -EINVAL;
+	}
+	return 0;
+}
+
+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, 1, 116, 3, red_width - 1);
+	ipu_ch_param_set_field(p, 1, 128, 5, red_offset);
+	/* Setup green width and offset */
+	ipu_ch_param_set_field(p, 1, 119, 3, green_width - 1);
+	ipu_ch_param_set_field(p, 1, 133, 5, green_offset);
+	/* Setup blue width and offset */
+	ipu_ch_param_set_field(p, 1, 122, 3, blue_width - 1);
+	ipu_ch_param_set_field(p, 1, 138, 5, blue_offset);
+	/* Setup alpha width and offset */
+	ipu_ch_param_set_field(p, 1, 125, 3, alpha_width - 1);
+	ipu_ch_param_set_field(p, 1, 143, 5, 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, ch);
+	dev_dbg(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->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->dev, "PFS 0x%x, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 85, 4));
+	dev_dbg(ipu->dev, "BPP 0x%x, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3));
+	dev_dbg(ipu->dev, "NPB 0x%x\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7));
+
+	dev_dbg(ipu->dev, "FW %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
+	dev_dbg(ipu->dev, "FH %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
+	dev_dbg(ipu->dev, "Stride %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
+
+	dev_dbg(ipu->dev, "Width0 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
+	dev_dbg(ipu->dev, "Width1 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 119, 3));
+	dev_dbg(ipu->dev, "Width2 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 122, 3));
+	dev_dbg(ipu->dev, "Width3 %d+1, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3));
+	dev_dbg(ipu->dev, "Offset0 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 5));
+	dev_dbg(ipu->dev, "Offset1 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 133, 5));
+	dev_dbg(ipu->dev, "Offset2 %d, ",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 138, 5));
+	dev_dbg(ipu->dev, "Offset3 %d\n",
+		 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 143, 5));
+}
+
+static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
+				      uint32_t pixel_fmt, uint32_t width,
+				      uint32_t height, uint32_t stride,
+				      uint32_t u, uint32_t v,
+				      uint32_t uv_stride, dma_addr_t addr0,
+				      dma_addr_t addr1, dma_addr_t addr2)
+{
+	uint32_t u_offset = 0;
+	uint32_t v_offset = 0;
+	int32_t sub_ch = 0;
+	struct ipu_ch_param params;
+
+	memset(&params, 0, sizeof(params));
+
+	ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
+
+	if ((ch == 8) || (ch == 9) || (ch == 10)) {
+		ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+	} else {
+		ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+	}
+
+	/* EBA is 8-byte aligned */
+	ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
+	ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
+	if (addr0%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's EBA0 is not 8-byte aligned\n", ch);
+	if (addr1%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's EBA1 is not 8-byte aligned\n", ch);
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+		/*Represents 8-bit Generic data */
+		ipu_ch_param_set_field(&params, 0, 107, 3, 5);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 6);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* 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, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 19);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 16, 8, 8, 8, 0, 8, 24);
+		break;
+	case IPU_PIX_FMT_VYU444:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 1);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 19);	/* burst size */
+
+		_ipu_ch_params_set_packing(&params, 8, 8, 8, 0, 8, 16, 8, 24);
+		break;
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 0, 107, 3, 0);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
+
+		_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, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 0xA);	/* pix format */
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YUYV:
+		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 0x8);	/* pix format */
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		ipu_ch_param_set_field(&params, 1, 85, 4, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		ipu_ch_param_set_field(&params, 1, 85, 4, 2);	/* pix format */
+
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = stride * height;
+		u_offset = v_offset + (uv_stride * height / 2);
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+		}
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		/* BPP & pixel format */
+		ipu_ch_param_set_field(&params, 1, 85, 4, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 1, 85, 4, 1);	/* pix format */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 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, 1, 85, 4, 4);	/* pix format */
+		uv_stride = stride;
+		u_offset = (u == 0) ? stride * height : u;
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		}
+		break;
+	default:
+		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+		break;
+	}
+	/*set burst size to 16*/
+
+
+	if (uv_stride)
+		ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
+
+	/* Get the uv offset from user when need cropping */
+	if (u || v) {
+		u_offset = u;
+		v_offset = v;
+	}
+
+	/* UBO and VBO are 22-bit and 8-byte aligned */
+	if (u_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's U offset exceeds IPU limitation\n", ch);
+	if (v_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's V offset exceeds IPU limitation\n", ch);
+	if (u_offset%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's U offset is not 8-byte aligned\n", ch);
+	if (v_offset%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+	ipu_ch_param_set_field(&params, 0, 46, 22, u_offset / 8);
+	ipu_ch_param_set_field(&params, 0, 68, 22, v_offset / 8);
+
+	dev_dbg(ipu->dev, "initializing idma ch %d @ %p\n", ch, ipu_ch_param_addr(ipu, ch));
+	memcpy(ipu_ch_param_addr(ipu, ch), &params, sizeof(params));
+	if (addr2) {
+		ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
+		ipu_ch_param_set_field(&params, 1, 29, 29, 0);
+
+		sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+		if (sub_ch <= 0)
+			return;
+
+		dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
+					ipu_ch_param_addr(ipu, sub_ch));
+		memcpy(ipu_ch_param_addr(ipu, sub_ch), &params, sizeof(params));
+	}
+};
+
+static inline void _ipu_ch_param_set_burst_size(struct ipu_soc *ipu,
+						uint32_t ch,
+						uint16_t burst_pixels)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7,
+			       burst_pixels - 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 78, 7,
+			       burst_pixels - 1);
+};
+
+static inline int _ipu_ch_param_get_burst_size(struct ipu_soc *ipu, uint32_t ch)
+{
+	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 78, 7) + 1;
+};
+
+static inline int _ipu_ch_param_get_bpp(struct ipu_soc *ipu, uint32_t ch)
+{
+	return ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 107, 3);
+};
+
+static inline void _ipu_ch_param_set_buffer(struct ipu_soc *ipu, uint32_t ch,
+					int bufNum, dma_addr_t phyaddr)
+{
+	if (bufNum == 2) {
+		ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+		if (ch <= 0)
+			return;
+		bufNum = 0;
+	}
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 29 * bufNum, 29,
+			       phyaddr / 8);
+};
+
+static inline void _ipu_ch_param_set_rotation(struct ipu_soc *ipu, uint32_t ch,
+					      ipu_rotate_mode_t rot)
+{
+	u32 temp_rot = bitrev8(rot) >> 5;
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 119, 3, temp_rot);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 119, 3, temp_rot);
+};
+
+static inline void _ipu_ch_param_set_block_mode(struct ipu_soc *ipu, uint32_t ch)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 117, 2, 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 117, 2, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_use_separate_channel(struct ipu_soc *ipu,
+								uint32_t ch,
+								bool option)
+{
+	int32_t sub_ch = 0;
+
+	if (option) {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 1);
+	} else {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 89, 1, 0);
+	}
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+
+	if (option) {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 1);
+	} else {
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 89, 1, 0);
+	}
+};
+
+static inline void _ipu_ch_param_set_alpha_condition_read(struct ipu_soc *ipu, uint32_t ch)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 149, 1, 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 149, 1, 1);
+};
+
+static inline void _ipu_ch_param_set_alpha_buffer_memory(struct ipu_soc *ipu, uint32_t ch)
+{
+	int alp_mem_idx;
+	int32_t sub_ch = 0;
+
+	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 correlative channel of local "
+			"alpha channel\n");
+		return;
+	}
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 90, 3, alp_mem_idx);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 90, 3, alp_mem_idx);
+};
+
+static inline void _ipu_ch_param_set_interlaced_scan(struct ipu_soc *ipu, uint32_t ch)
+{
+	u32 stride;
+	int32_t sub_ch = 0;
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1, 1);
+	if (sub_ch > 0)
+		ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 113, 1, 1);
+	stride = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14) + 1;
+	/* ILO is 20-bit and 8-byte aligned */
+	if (stride/8 > 0xfffff)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's ILO exceeds IPU limitation\n", ch);
+	if (stride%8)
+		dev_warn(ipu->dev,
+			 "IDMAC%d's ILO is not 8-byte aligned\n", ch);
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 58, 20, stride / 8);
+	if (sub_ch > 0)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 58, 20,
+				       stride / 8);
+	stride *= 2;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14, stride - 1);
+	if (sub_ch > 0)
+		ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 102, 14,
+				       stride - 1);
+};
+
+static inline void _ipu_ch_param_set_axi_id(struct ipu_soc *ipu, uint32_t ch, uint32_t id)
+{
+	int32_t sub_ch = 0;
+
+	id %= 4;
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 1, 93, 2, id);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 93, 2, id);
+};
+
+/* IDMAC U/V offset changing support */
+/* U and V input is not affected, */
+/* the update is done by new calculation according to */
+/* vertical_offset and horizontal_offset */
+static inline void _ipu_ch_offset_update(struct ipu_soc *ipu,
+					int ch,
+					uint32_t pixel_fmt,
+					uint32_t width,
+					uint32_t height,
+					uint32_t stride,
+					uint32_t u,
+					uint32_t v,
+					uint32_t uv_stride,
+					uint32_t vertical_offset,
+					uint32_t horizontal_offset)
+{
+	uint32_t u_offset = 0;
+	uint32_t v_offset = 0;
+	uint32_t u_fix = 0;
+	uint32_t v_fix = 0;
+	int32_t sub_ch = 0;
+
+	switch (pixel_fmt) {
+	case IPU_PIX_FMT_GENERIC:
+	case IPU_PIX_FMT_GENERIC_32:
+	case IPU_PIX_FMT_RGB565:
+	case IPU_PIX_FMT_BGR24:
+	case IPU_PIX_FMT_RGB24:
+	case IPU_PIX_FMT_YUV444:
+	case IPU_PIX_FMT_BGRA32:
+	case IPU_PIX_FMT_BGR32:
+	case IPU_PIX_FMT_RGBA32:
+	case IPU_PIX_FMT_RGB32:
+	case IPU_PIX_FMT_ABGR32:
+	case IPU_PIX_FMT_UYVY:
+	case IPU_PIX_FMT_YUYV:
+		break;
+
+	case IPU_PIX_FMT_YUV420P2:
+	case IPU_PIX_FMT_YUV420P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset / 2;
+		v_offset = u_offset + (uv_stride * height / 2);
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					v_offset;
+
+		break;
+	case IPU_PIX_FMT_YVU420P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset / 2;
+		u_offset = v_offset + (uv_stride * height / 2);
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset / 2) +
+					(horizontal_offset / 2) -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					v_offset;
+
+		break;
+	case IPU_PIX_FMT_YVU422P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		v_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset) +
+					horizontal_offset / 2;
+		u_offset = v_offset + uv_stride * height;
+		u_fix = u ? (u + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					v_offset;
+		break;
+	case IPU_PIX_FMT_YUV422P:
+		if (uv_stride < stride / 2)
+			uv_stride = stride / 2;
+
+		u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset) +
+					horizontal_offset / 2;
+		v_offset = u_offset + uv_stride * height;
+		u_fix = u ? (u + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					u_offset;
+		v_fix = v ? (v + (uv_stride * vertical_offset) +
+					horizontal_offset / 2 -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					v_offset;
+		break;
+
+	case IPU_PIX_FMT_NV12:
+		uv_stride = stride;
+		u_offset = stride * (height - vertical_offset - 1) +
+					(stride - horizontal_offset) +
+					(uv_stride * vertical_offset / 2) +
+					horizontal_offset;
+		u_fix = u ? (u + (uv_stride * vertical_offset / 2) +
+					horizontal_offset -
+					(stride * vertical_offset) - (horizontal_offset)) :
+					u_offset;
+
+		break;
+	default:
+		dev_err(ipu->dev, "mxc ipu: unimplemented pixel format\n");
+		break;
+	}
+
+
+
+	if (u_fix > u_offset)
+		u_offset = u_fix;
+
+	if (v_fix > v_offset)
+		v_offset = v_fix;
+
+	/* UBO and VBO are 22-bit and 8-byte aligned */
+	if (u_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			"IDMAC%d's U offset exceeds IPU limitation\n", ch);
+	if (v_offset/8 > 0x3fffff)
+		dev_warn(ipu->dev,
+			"IDMAC%d's V offset exceeds IPU limitation\n", ch);
+	if (u_offset%8)
+		dev_warn(ipu->dev,
+			"IDMAC%d's U offset is not 8-byte aligned\n", ch);
+	if (v_offset%8)
+		dev_warn(ipu->dev,
+			"IDMAC%d's V offset is not 8-byte aligned\n", ch);
+
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22, v_offset / 8);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
+	ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22, v_offset / 8);
+};
+
+static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t ch, int alpha_width)
+{
+	int32_t sub_ch = 0;
+
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch), 1, 125, 3, alpha_width - 1);
+
+	sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+	if (sub_ch <= 0)
+		return;
+	ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
+};
+
+#endif
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
new file mode 100644
index 0000000..0114cc1
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2005-2011 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
+ */
+#ifndef __INCLUDE_IPU_PRV_H__
+#define __INCLUDE_IPU_PRV_H__
+
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/clkdev.h>
+#include <linux/interrupt.h>
+#include <linux/fsl_devices.h>
+#include <mach/clock.h>
+#include <mach/ipu-v3.h>
+
+#ifdef CONFIG_MXC_IPU_V3H
+#define MXC_IPU_MAX_NUM	2
+#else
+#define MXC_IPU_MAX_NUM	1
+#endif
+
+/* Globals */
+extern int dmfc_type_setup;
+extern struct clk ipu_pixel_clk[];
+extern struct clk_lookup ipu_lookups[];
+
+#define IDMA_CHAN_INVALID	0xFF
+#define HIGH_RESOLUTION_WIDTH	1024
+
+struct ipu_irq_node {
+	irqreturn_t(*handler) (int, void *);	/*!< the ISR */
+	const char *name;	/*!< device associated with the interrupt */
+	void *dev_id;		/*!< some unique information for the ISR */
+	__u32 flags;		/*!< not used */
+};
+
+enum csc_type_t {
+	RGB2YUV = 0,
+	YUV2RGB,
+	RGB2RGB,
+	YUV2YUV,
+	CSC_NONE,
+	CSC_NUM
+};
+
+struct ipu_soc {
+	/*clk*/
+	struct clk *ipu_clk;
+	struct clk *di_clk[2];
+	struct clk *csi_clk[2];
+	struct clk pixel_clk[2];
+
+	/*irq*/
+	int irq_sync;
+	int irq_err;
+	struct ipu_irq_node irq_list[IPU_IRQ_COUNT];
+
+	/*reg*/
+	u32 *cm_reg;
+	u32 *idmac_reg;
+	u32 *dp_reg;
+	u32 *ic_reg;
+	u32 *dc_reg;
+	u32 *dc_tmpl_reg;
+	u32 *dmfc_reg;
+	u32 *di_reg[2];
+	u32 *smfc_reg;
+	u32 *csi_reg[2];
+	u32 *cpmem_base;
+	u32 *tpmem_base;
+	u32 *disp_base[2];
+	u32 *vdi_reg;
+
+	struct device *dev;
+
+	ipu_channel_t csi_channel[2];
+	ipu_channel_t using_ic_dirct_ch;
+	unsigned char dc_di_assignment[10];
+	bool sec_chan_en[24];
+	bool thrd_chan_en[24];
+	bool chan_is_interlaced[52];
+	uint32_t channel_init_mask;
+	uint32_t channel_enable_mask;
+
+	/*use count*/
+	int ipu_use_count;
+	int dc_use_count;
+	int dp_use_count;
+	int dmfc_use_count;
+	int smfc_use_count;
+	int ic_use_count;
+	int rot_use_count;
+	int vdi_use_count;
+	int di_use_count[2];
+	int csi_use_count[2];
+
+	struct mutex mutex_lock;
+	spinlock_t spin_lock;
+
+	int dmfc_size_28;
+	int dmfc_size_29;
+	int dmfc_size_24;
+	int dmfc_size_27;
+	int dmfc_size_23;
+
+	enum csc_type_t fg_csc_type;
+	enum csc_type_t bg_csc_type;
+	bool color_key_4rgb;
+	bool dc_swap;
+	struct completion dc_comp;
+
+	/* for power gating */
+	u32 ipu_conf_reg;
+	u32 ic_conf_reg;
+	u32 cha_db_mode_reg[4];
+	u32 cha_trb_mode_reg[2];
+	u32 idma_sub_addr_reg[5];
+	u32 idma_enable_reg[2];
+	u32 buf_ready_reg[10];
+
+	/*ipu processing driver*/
+	struct list_head task_list[2];
+	struct mutex task_lock[2];
+	wait_queue_head_t waitq[2];
+	struct task_struct *thread[2];
+};
+
+struct ipu_channel {
+	u8 video_in_dma;
+	u8 alpha_in_dma;
+	u8 graph_in_dma;
+	u8 out_dma;
+};
+
+enum ipu_dmfc_type {
+	DMFC_NORMAL = 0,
+	DMFC_HIGH_RESOLUTION_DC,
+	DMFC_HIGH_RESOLUTION_DP,
+	DMFC_HIGH_RESOLUTION_ONLY_DP,
+};
+
+static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->cm_reg + offset);
+}
+
+static inline void ipu_cm_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->cm_reg + offset);
+}
+
+static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->idmac_reg + offset);
+}
+
+static inline void ipu_idmac_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->idmac_reg + offset);
+}
+
+static inline u32 ipu_dc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dc_reg + offset);
+}
+
+static inline void ipu_dc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dc_reg + offset);
+}
+
+static inline u32 ipu_dc_tmpl_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dc_tmpl_reg + offset);
+}
+
+static inline void ipu_dc_tmpl_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dc_tmpl_reg + offset);
+}
+
+static inline u32 ipu_dmfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dmfc_reg + offset);
+}
+
+static inline void ipu_dmfc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dmfc_reg + offset);
+}
+
+static inline u32 ipu_dp_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->dp_reg + offset);
+}
+
+static inline void ipu_dp_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->dp_reg + offset);
+}
+
+static inline u32 ipu_di_read(struct ipu_soc *ipu, int di, unsigned offset)
+{
+	return readl(ipu->di_reg[di] + offset);
+}
+
+static inline void ipu_di_write(struct ipu_soc *ipu, int di,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->di_reg[di] + offset);
+}
+
+static inline u32 ipu_csi_read(struct ipu_soc *ipu, int csi, unsigned offset)
+{
+	return readl(ipu->csi_reg[csi] + offset);
+}
+
+static inline void ipu_csi_write(struct ipu_soc *ipu, int csi,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->csi_reg[csi] + offset);
+}
+
+static inline u32 ipu_smfc_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->smfc_reg + offset);
+}
+
+static inline void ipu_smfc_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->smfc_reg + offset);
+}
+
+static inline u32 ipu_vdi_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->vdi_reg + offset);
+}
+
+static inline void ipu_vdi_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->vdi_reg + offset);
+}
+
+static inline u32 ipu_ic_read(struct ipu_soc *ipu, unsigned offset)
+{
+	return readl(ipu->ic_reg + offset);
+}
+
+static inline void ipu_ic_write(struct ipu_soc *ipu,
+		u32 value, unsigned offset)
+{
+	writel(value, ipu->ic_reg + offset);
+}
+
+int register_ipu_device(struct ipu_soc *ipu, int id);
+void unregister_ipu_device(struct ipu_soc *ipu, int id);
+ipu_color_space_t format_to_colorspace(uint32_t fmt);
+bool ipu_pixel_format_has_alpha(uint32_t fmt);
+
+void ipu_dump_registers(struct ipu_soc *ipu);
+
+uint32_t _ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void ipu_disp_init(struct ipu_soc *ipu);
+void _ipu_init_dc_mappings(struct ipu_soc *ipu);
+int _ipu_dp_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t in_pixel_fmt,
+		 uint32_t out_pixel_fmt);
+void _ipu_dp_uninit(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dc_init(struct ipu_soc *ipu, int dc_chan, int di, bool interlaced, uint32_t pixel_fmt);
+void _ipu_dc_uninit(struct ipu_soc *ipu, int dc_chan);
+void _ipu_dp_dc_enable(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_dp_dc_disable(struct ipu_soc *ipu, ipu_channel_t channel, bool swap);
+void _ipu_dmfc_init(struct ipu_soc *ipu, int dmfc_type, int first);
+void _ipu_dmfc_set_wait4eot(struct ipu_soc *ipu, int dma_chan, int width);
+void _ipu_dmfc_set_burst_size(struct ipu_soc *ipu, int dma_chan, int burst_size);
+int _ipu_disp_chan_is_interlaced(struct ipu_soc *ipu, ipu_channel_t channel);
+
+void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel);
+void _ipu_ic_init_prpvf(struct ipu_soc *ipu, ipu_channel_params_t *params, bool src_is_csi);
+void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_params_t *params);
+void _ipu_vdi_uninit(struct ipu_soc *ipu);
+void _ipu_ic_uninit_prpvf(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_vf(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_vf(struct ipu_soc *ipu);
+void _ipu_ic_init_csi(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_csi(struct ipu_soc *ipu);
+void _ipu_ic_init_prpenc(struct ipu_soc *ipu, ipu_channel_params_t *params, bool src_is_csi);
+void _ipu_ic_uninit_prpenc(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_enc(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_enc(struct ipu_soc *ipu);
+void _ipu_ic_init_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_pp(struct ipu_soc *ipu);
+void _ipu_ic_init_rotate_pp(struct ipu_soc *ipu, ipu_channel_params_t *params);
+void _ipu_ic_uninit_rotate_pp(struct ipu_soc *ipu);
+int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan, uint16_t width, uint16_t height,
+		      int burst_size, ipu_rotate_mode_t rot);
+void _ipu_vdi_toggle_top_field_man(struct ipu_soc *ipu);
+int _ipu_csi_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t csi);
+void ipu_csi_set_test_generator(struct ipu_soc *ipu, bool active, uint32_t r_value,
+		uint32_t g_value, uint32_t b_value,
+		uint32_t pix_clk, uint32_t csi);
+void _ipu_csi_ccir_err_detection_enable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_csi_ccir_err_detection_disable(struct ipu_soc *ipu, uint32_t csi);
+void _ipu_smfc_init(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t mipi_id, uint32_t csi);
+void _ipu_smfc_set_burst_size(struct ipu_soc *ipu, ipu_channel_t channel, uint32_t bs);
+void _ipu_dp_set_csc_coefficients(struct ipu_soc *ipu, ipu_channel_t channel, int32_t param[][3]);
+int32_t _ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+		int16_t x_pos, int16_t y_pos);
+int32_t _ipu_disp_get_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
+		int16_t *x_pos, int16_t *y_pos);
+void _ipu_get(struct ipu_soc *ipu);
+void _ipu_put(struct ipu_soc *ipu);
+void _ipu_lock(struct ipu_soc *ipu, unsigned long *flags);
+void _ipu_unlock(struct ipu_soc *ipu, unsigned long *flags);
+#endif				/* __INCLUDE_IPU_PRV_H__ */
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
new file mode 100644
index 0000000..c63c932
--- /dev/null
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -0,0 +1,697 @@
+/*
+ * Copyright (C) 2005-2011 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
+ */
+
+/*
+ * @file ipu_regs.h
+ *
+ * @brief IPU Register definitions
+ *
+ * @ingroup IPU
+ */
+#ifndef __IPU_REGS_INCLUDED__
+#define __IPU_REGS_INCLUDED__
+
+/*
+ * hw_rev 2: IPUV3DEX
+ * hw_rev 3: IPUV3M
+ * hw_rev 4: IPUV3H
+ */
+extern int g_ipu_hw_rev;
+
+#define IPU_DISP0_BASE		0x00000000
+#define IPU_MCU_T_DEFAULT	8
+#define IPU_DISP1_BASE		({g_ipu_hw_rev < 4 ? \
+				(IPU_MCU_T_DEFAULT << 25) : \
+				(0x00000000); })
+#define IPUV3DEX_REG_BASE	0x1E000000
+#define IPUV3M_REG_BASE		0x06000000
+#define IPUV3H_REG_BASE		0x00200000
+
+#define IPU_CM_REG_BASE		0x00000000
+#define IPU_IDMAC_REG_BASE	0x00008000
+#define IPU_ISP_REG_BASE	0x00010000
+#define IPU_DP_REG_BASE		0x00018000
+#define IPU_IC_REG_BASE		0x00020000
+#define IPU_IRT_REG_BASE	0x00028000
+#define IPU_CSI0_REG_BASE	0x00030000
+#define IPU_CSI1_REG_BASE	0x00038000
+#define IPU_DI0_REG_BASE	0x00040000
+#define IPU_DI1_REG_BASE	0x00048000
+#define IPU_SMFC_REG_BASE	0x00050000
+#define IPU_DC_REG_BASE		0x00058000
+#define IPU_DMFC_REG_BASE	0x00060000
+#define IPU_VDI_REG_BASE	0x00068000
+#define IPU_CPMEM_REG_BASE 	({g_ipu_hw_rev >= 4 ? \
+				   (0x00100000) : \
+				   (0x01000000); })
+#define IPU_LUT_REG_BASE	0x01020000
+#define IPU_SRM_REG_BASE 	({g_ipu_hw_rev >= 4 ? \
+				   (0x00140000) : \
+				   (0x01040000); })
+#define IPU_TPM_REG_BASE 	({g_ipu_hw_rev >= 4 ? \
+				   (0x00160000) : \
+				   (0x01060000); })
+#define IPU_DC_TMPL_REG_BASE 	({g_ipu_hw_rev >= 4 ? \
+				   (0x00180000) : \
+				   (0x01080000); })
+#define IPU_ISP_TBPR_REG_BASE	0x010C0000
+
+/* Register addresses */
+/* IPU Common registers */
+#define IPU_CONF		(0)
+
+#define IPU_SRM_PRI1		(0x00A0/4)
+#define IPU_SRM_PRI2		(0x00A4/4)
+#define IPU_FS_PROC_FLOW1	(0x00A8/4)
+#define IPU_FS_PROC_FLOW2	(0x00AC/4)
+#define IPU_FS_PROC_FLOW3	(0x00B0/4)
+#define IPU_FS_DISP_FLOW1	(0x00B4/4)
+#define IPU_FS_DISP_FLOW2	(0x00B8/4)
+#define IPU_SKIP		(0x00BC/4)
+#define IPU_DISP_ALT_CONF	(0x00C0/4)
+#define IPU_DISP_GEN		(0x00C4/4)
+#define IPU_DISP_ALT1		(0x00C8/4)
+#define IPU_DISP_ALT2		(0x00CC/4)
+#define IPU_DISP_ALT3		(0x00D0/4)
+#define IPU_DISP_ALT4		(0x00D4/4)
+#define IPU_SNOOP		(0x00D8/4)
+#define IPU_MEM_RST		(0x00DC/4)
+#define IPU_PM			(0x00E0/4)
+#define IPU_GPR			(0x00E4/4)
+#define IPU_CHA_DB_MODE_SEL(ch)	(0x0150/4 + (ch / 32))
+#define IPU_ALT_CHA_DB_MODE_SEL(ch) (0x0168/4 + (ch / 32))
+/*
+ * IPUv3D doesn't support triple buffer, so point
+ * IPU_CHA_TRB_MODE_SEL, IPU_CHA_TRIPLE_CUR_BUF and
+ * IPU_CHA_BUF2_RDY to readonly
+ * IPU_ALT_CUR_BUF0 for IPUv3D.
+ */
+#define IPU_CHA_TRB_MODE_SEL(ch) ({g_ipu_hw_rev >= 2 ? \
+				   (0x0178/4 + (ch / 32)) : \
+				   (0x012C/4); })
+#define IPU_CHA_TRIPLE_CUR_BUF(ch) ({g_ipu_hw_rev >= 2 ? \
+				     (0x0258/4 + ((ch*2) / 32)) : \
+				     (0x012C/4); })
+#define IPU_CHA_BUF2_RDY(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x0288/4 + (ch / 32)) : \
+				  (0x012C/4); })
+#define IPU_CHA_CUR_BUF(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x023C/4 + (ch / 32)) : \
+				  (0x0124/4 + (ch / 32)); })
+#define IPU_ALT_CUR_BUF0	({g_ipu_hw_rev >= 2 ? \
+				  (0x0244/4) : \
+				  (0x012C/4); })
+#define IPU_ALT_CUR_BUF1	({g_ipu_hw_rev >= 2 ? \
+				  (0x0248/4) : \
+				  (0x0130/4); })
+#define IPU_SRM_STAT		({g_ipu_hw_rev >= 2 ? \
+				  (0x024C/4) : \
+				  (0x0134/4); })
+#define IPU_PROC_TASK_STAT	({g_ipu_hw_rev >= 2 ? \
+				  (0x0250/4) : \
+				  (0x0138/4); })
+#define IPU_DISP_TASK_STAT	({g_ipu_hw_rev >= 2 ? \
+				  (0x0254/4) : \
+				  (0x013C/4); })
+#define IPU_CHA_BUF0_RDY(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x0268/4 + (ch / 32)) : \
+				  (0x0140/4 + (ch / 32)); })
+#define IPU_CHA_BUF1_RDY(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x0270/4 + (ch / 32)) : \
+				  (0x0148/4 + (ch / 32)); })
+#define IPU_ALT_CHA_BUF0_RDY(ch) ({g_ipu_hw_rev >= 2 ? \
+				   (0x0278/4 + (ch / 32)) : \
+				   (0x0158/4 + (ch / 32)); })
+#define IPU_ALT_CHA_BUF1_RDY(ch) ({g_ipu_hw_rev >= 2 ? \
+				   (0x0280/4 + (ch / 32)) : \
+				   (0x0160/4 + (ch / 32)); })
+
+#define IPU_INT_CTRL(n)		(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)		({g_ipu_hw_rev >= 2 ? \
+				  (0x0200/4 + ((n) - 1)) : \
+				  (0x00E8/4 + ((n) - 1)); })
+
+#define IPUIRQ_2_STATREG(irq)	(IPU_INT_STAT(1) + ((irq) / 32))
+#define IPUIRQ_2_CTRLREG(irq)	(IPU_INT_CTRL(1) + ((irq) / 32))
+#define IPUIRQ_2_MASK(irq)	(1UL << ((irq) & 0x1F))
+
+#define VDI_FSIZE (0)
+#define VDI_C (0x0004/4)
+
+/* CMOS Sensor Interface Registers */
+#define CSI_SENS_CONF		(0)
+#define CSI_SENS_FRM_SIZE	(0x0004/4)
+#define CSI_ACT_FRM_SIZE	(0x0008/4)
+#define CSI_OUT_FRM_CTRL	(0x000C/4)
+#define CSI_TST_CTRL		(0x0010/4)
+#define CSI_CCIR_CODE_1		(0x0014/4)
+#define CSI_CCIR_CODE_2		(0x0018/4)
+#define CSI_CCIR_CODE_3		(0x001C/4)
+#define CSI_MIPI_DI		(0x0020/4)
+#define CSI_SKIP		(0x0024/4)
+#define CSI_CPD_CTRL		(0x0028/4)
+#define CSI_CPD_RC(n)		(0x002C/4 + n)
+#define CSI_CPD_RS(n)		(0x004C/4 + n)
+#define CSI_CPD_GRC(n)		(0x005C/4 + n)
+#define CSI_CPD_GRS(n)		(0x007C/4 + n)
+#define CSI_CPD_GBC(n)		(0x008C/4 + n)
+#define CSI_CPD_GBS(n)		(0x00AC/4 + n)
+#define CSI_CPD_BC(n)		(0x00BC/4 + n)
+#define CSI_CPD_BS(n)		(0x00DC/4 + n)
+#define CSI_CPD_OFFSET1		(0x00EC/4)
+#define CSI_CPD_OFFSET2		(0x00F0/4)
+
+/*SMFC Registers */
+#define SMFC_MAP	(0)
+#define SMFC_WMC	(0x0004/4)
+#define SMFC_BS		(0x0008/4)
+
+/* Image Converter Registers */
+#define IC_CONF			0
+#define IC_PRP_ENC_RSC		(0x0004/4)
+#define IC_PRP_VF_RSC		(0x0008/4)
+#define IC_PP_RSC		(0x000C/4)
+#define IC_CMBP_1		(0x0010/4)
+#define IC_CMBP_2		(0x0014/4)
+#define IC_IDMAC_1		(0x0018/4)
+#define IC_IDMAC_2		(0x001C/4)
+#define IC_IDMAC_3		(0x0020/4)
+#define IC_IDMAC_4		(0x0024/4)
+
+#define IDMAC_CONF		(0x0000)
+#define IDMAC_CHA_EN(ch)	(0x0004/4 + (ch/32))
+#define IDMAC_SEP_ALPHA		(0x000C/4)
+#define IDMAC_ALT_SEP_ALPHA	(0x0010/4)
+#define IDMAC_CHA_PRI(ch)	(0x0014/4 + (ch/32))
+#define IDMAC_WM_EN(ch)		(0x001C/4 + (ch/32))
+#define IDMAC_CH_LOCK_EN_1	({g_ipu_hw_rev >= 2 ? \
+				  (0x0024/4) : 0; })
+#define IDMAC_CH_LOCK_EN_2	({g_ipu_hw_rev >= 2 ? \
+				  (0x0028/4) : \
+				  (0x0024/4); })
+#define IDMAC_SUB_ADDR_0	({g_ipu_hw_rev >= 2 ? \
+				  (0x002C/4) : \
+				  (0x0028/4); })
+#define IDMAC_SUB_ADDR_1	({g_ipu_hw_rev >= 2 ? \
+				  (0x0030/4) : \
+				  (0x002C/4); })
+#define IDMAC_SUB_ADDR_2	({g_ipu_hw_rev >= 2 ? \
+				  (0x0034/4) : \
+				  (0x0030/4); })
+/*
+ * IPUv3D doesn't support IDMAC_SUB_ADDR_3 and IDMAC_SUB_ADDR_4,
+ * so point them to readonly IDMAC_CHA_BUSY1 for IPUv3D.
+ */
+#define IDMAC_SUB_ADDR_3	({g_ipu_hw_rev >= 2 ? \
+				  (0x0038/4) : \
+				  (0x0040/4); })
+#define IDMAC_SUB_ADDR_4	({g_ipu_hw_rev >= 2 ? \
+				  (0x003c/4) : \
+				  (0x0040/4); })
+#define IDMAC_BAND_EN(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x0040/4 + (ch/32)) : \
+				  (0x0034/4 + (ch/32)); })
+#define IDMAC_CHA_BUSY(ch)	({g_ipu_hw_rev >= 2 ? \
+				  (0x0100/4 + (ch/32)) : \
+				  (0x0040/4 + (ch/32)); })
+
+#define DI_GENERAL		(0)
+#define DI_BS_CLKGEN0		(0x0004/4)
+#define DI_BS_CLKGEN1		(0x0008/4)
+
+#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/4)
+#define DI_DW_GEN(gen)		(0x0058/4 + gen)
+#define DI_DW_SET(gen, set)	(0x0088/4 + gen + 0xC*set)
+#define DI_SER_CONF		(0x015C/4)
+#define DI_SSC			(0x0160/4)
+#define DI_POL			(0x0164/4)
+#define DI_AW0			(0x0168/4)
+#define DI_AW1			(0x016C/4)
+#define DI_SCR_CONF		(0x0170/4)
+#define DI_STAT			(0x0174/4)
+
+#define DMFC_RD_CHAN		(0)
+#define DMFC_WR_CHAN		(0x0004/4)
+#define DMFC_WR_CHAN_DEF	(0x0008/4)
+#define DMFC_DP_CHAN		(0x000C/4)
+#define DMFC_DP_CHAN_DEF	(0x0010/4)
+#define DMFC_GENERAL1		(0x0014/4)
+#define DMFC_GENERAL2		(0x0018/4)
+#define DMFC_IC_CTRL		(0x001C/4)
+#define DMFC_STAT		(0x0020/4)
+
+#define DC_MAP_CONF_PTR(n)	(0x0108/4 + n/2)
+#define DC_MAP_CONF_VAL(n)	(0x0144/4 + n/2)
+
+#define _RL_CH_2_OFFSET(ch)	((ch == 0) ? 8 : ( \
+				 (ch == 1) ? 0x24 : ( \
+				 (ch == 2) ? 0x40 : ( \
+				 (ch == 5) ? 0x64 : ( \
+				 (ch == 6) ? 0x80 : ( \
+				 (ch == 8) ? 0x9C : ( \
+				 (ch == 9) ? 0xBC : (-1))))))))
+#define DC_RL_CH(ch, evt)	(_RL_CH_2_OFFSET(ch)/4 + evt/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_EVEN_UGDE0 		12
+#define DC_ODD_UGDE0 		13
+#define DC_EVEN_UGDE1 		14
+#define DC_ODD_UGDE1 		15
+#define DC_EVEN_UGDE2 		16
+#define DC_ODD_UGDE2 		17
+#define DC_EVEN_UGDE3 		18
+#define DC_ODD_UGDE3 		19
+
+#define dc_ch_offset(ch) \
+({ \
+	const u8 _offset[] = { \
+		0, 0x1C, 0x38, 0x54, 0x58, 0x5C, 0x78, 0, 0x94, 0xB4}; \
+	_offset[ch]; \
+})
+#define DC_WR_CH_CONF(ch)	(dc_ch_offset(ch)/4)
+#define DC_WR_CH_ADDR(ch)	(dc_ch_offset(ch)/4 + 4/4)
+
+#define DC_WR_CH_CONF_1		(0x001C/4)
+#define DC_WR_CH_ADDR_1		(0x0020/4)
+#define DC_WR_CH_CONF_5		(0x005C/4)
+#define DC_WR_CH_ADDR_5		(0x0060/4)
+#define DC_GEN			(0x00D4/4)
+#define DC_DISP_CONF1(disp)	(0x00D8/4 + disp)
+#define DC_DISP_CONF2(disp)	(0x00E8/4 + disp)
+#define DC_STAT			(0x01C8/4)
+#define DC_UGDE_0(evt)		(0x0174/4 + evt*4)
+#define DC_UGDE_1(evt)		(0x0178/4 + evt*4)
+#define DC_UGDE_2(evt)		(0x017C/4 + evt*4)
+#define DC_UGDE_3(evt)		(0x0180/4 + evt*4)
+
+#define DP_SYNC 0
+#define DP_ASYNC0 0x60
+#define DP_ASYNC1 0xBC
+#define DP_COM_CONF(flow)	(flow/4)
+#define DP_GRAPH_WIND_CTRL(flow) (0x0004/4 + flow/4)
+#define DP_FG_POS(flow)		(0x0008/4 + flow/4)
+#define DP_GAMMA_C(flow, i)	(0x0014/4 + flow/4 + i)
+#define DP_GAMMA_S(flow, i)	(0x0034/4 + flow/4 + i)
+#define DP_CSC_A_0(flow)	(0x0044/4 + flow/4)
+#define DP_CSC_A_1(flow)	(0x0048/4 + flow/4)
+#define DP_CSC_A_2(flow)	(0x004C/4 + flow/4)
+#define DP_CSC_A_3(flow)	(0x0050/4 + flow/4)
+#define DP_CSC_0(flow)		(0x0054/4 + flow/4)
+#define DP_CSC_1(flow)		(0x0058/4 + flow/4)
+
+enum {
+	IPU_CONF_CSI0_EN = 0x00000001,
+	IPU_CONF_CSI1_EN = 0x00000002,
+	IPU_CONF_IC_EN = 0x00000004,
+	IPU_CONF_ROT_EN = 0x00000008,
+	IPU_CONF_ISP_EN = 0x00000010,
+	IPU_CONF_DP_EN = 0x00000020,
+	IPU_CONF_DI0_EN = 0x00000040,
+	IPU_CONF_DI1_EN = 0x00000080,
+	IPU_CONF_DMFC_EN = 0x00000400,
+	IPU_CONF_SMFC_EN = 0x00000100,
+	IPU_CONF_DC_EN = 0x00000200,
+	IPU_CONF_VDI_EN = 0x00001000,
+	IPU_CONF_IDMAC_DIS = 0x00400000,
+	IPU_CONF_IC_DMFC_SEL = 0x02000000,
+	IPU_CONF_IC_DMFC_SYNC = 0x04000000,
+	IPU_CONF_VDI_DMFC_SYNC = 0x08000000,
+	IPU_CONF_CSI0_DATA_SOURCE = 0x10000000,
+	IPU_CONF_CSI0_DATA_SOURCE_OFFSET = 28,
+	IPU_CONF_CSI1_DATA_SOURCE = 0x20000000,
+	IPU_CONF_IC_INPUT = 0x40000000,
+	IPU_CONF_CSI_SEL = 0x80000000,
+
+	DI0_COUNTER_RELEASE = 0x01000000,
+	DI1_COUNTER_RELEASE = 0x02000000,
+
+	FS_PRPVF_ROT_SRC_SEL_MASK = 0x00000F00,
+	FS_PRPVF_ROT_SRC_SEL_OFFSET = 8,
+	FS_PRPENC_ROT_SRC_SEL_MASK = 0x0000000F,
+	FS_PRPENC_ROT_SRC_SEL_OFFSET = 0,
+	FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
+	FS_PP_ROT_SRC_SEL_OFFSET = 16,
+	FS_PP_SRC_SEL_MASK = 0x0000F000,
+	FS_PP_SRC_SEL_OFFSET = 12,
+	FS_PRP_SRC_SEL_MASK = 0x0F000000,
+	FS_PRP_SRC_SEL_OFFSET = 24,
+	FS_VF_IN_VALID = 0x80000000,
+	FS_ENC_IN_VALID = 0x40000000,
+	FS_VDI_SRC_SEL_MASK = 0x30000000,
+	FS_VDI_SRC_SEL_OFFSET = 28,
+
+
+	FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
+	FS_PRPENC_DEST_SEL_OFFSET = 0,
+	FS_PRPVF_DEST_SEL_MASK = 0x000000F0,
+	FS_PRPVF_DEST_SEL_OFFSET = 4,
+	FS_PRPVF_ROT_DEST_SEL_MASK = 0x00000F00,
+	FS_PRPVF_ROT_DEST_SEL_OFFSET = 8,
+	FS_PP_DEST_SEL_MASK = 0x0000F000,
+	FS_PP_DEST_SEL_OFFSET = 12,
+	FS_PP_ROT_DEST_SEL_MASK = 0x000F0000,
+	FS_PP_ROT_DEST_SEL_OFFSET = 16,
+	FS_PRPENC_ROT_DEST_SEL_MASK = 0x00F00000,
+	FS_PRPENC_ROT_DEST_SEL_OFFSET = 20,
+
+	FS_SMFC0_DEST_SEL_MASK = 0x0000000F,
+	FS_SMFC0_DEST_SEL_OFFSET = 0,
+	FS_SMFC1_DEST_SEL_MASK = 0x00000070,
+	FS_SMFC1_DEST_SEL_OFFSET = 4,
+	FS_SMFC2_DEST_SEL_MASK = 0x00000780,
+	FS_SMFC2_DEST_SEL_OFFSET = 7,
+	FS_SMFC3_DEST_SEL_MASK = 0x00003800,
+	FS_SMFC3_DEST_SEL_OFFSET = 11,
+
+	FS_DC1_SRC_SEL_MASK = 0x00F00000,
+	FS_DC1_SRC_SEL_OFFSET = 20,
+	FS_DC2_SRC_SEL_MASK = 0x000F0000,
+	FS_DC2_SRC_SEL_OFFSET = 16,
+	FS_DP_SYNC0_SRC_SEL_MASK = 0x0000000F,
+	FS_DP_SYNC0_SRC_SEL_OFFSET = 0,
+	FS_DP_SYNC1_SRC_SEL_MASK = 0x000000F0,
+	FS_DP_SYNC1_SRC_SEL_OFFSET = 4,
+	FS_DP_ASYNC0_SRC_SEL_MASK = 0x00000F00,
+	FS_DP_ASYNC0_SRC_SEL_OFFSET = 8,
+	FS_DP_ASYNC1_SRC_SEL_MASK = 0x0000F000,
+	FS_DP_ASYNC1_SRC_SEL_OFFSET = 12,
+
+	FS_AUTO_REF_PER_MASK = 0,
+	FS_AUTO_REF_PER_OFFSET = 16,
+
+	TSTAT_VF_MASK = 0x0000000C,
+	TSTAT_VF_OFFSET = 2,
+	TSTAT_VF_ROT_MASK = 0x00000300,
+	TSTAT_VF_ROT_OFFSET = 8,
+	TSTAT_ENC_MASK = 0x00000003,
+	TSTAT_ENC_OFFSET = 0,
+	TSTAT_ENC_ROT_MASK = 0x000000C0,
+	TSTAT_ENC_ROT_OFFSET = 6,
+	TSTAT_PP_MASK = 0x00000030,
+	TSTAT_PP_OFFSET = 4,
+	TSTAT_PP_ROT_MASK = 0x00000C00,
+	TSTAT_PP_ROT_OFFSET = 10,
+
+	TASK_STAT_IDLE = 0,
+	TASK_STAT_ACTIVE = 1,
+	TASK_STAT_WAIT4READY = 2,
+
+	/* Image Converter Register bits */
+	IC_CONF_PRPENC_EN = 0x00000001,
+	IC_CONF_PRPENC_CSC1 = 0x00000002,
+	IC_CONF_PRPENC_ROT_EN = 0x00000004,
+	IC_CONF_PRPVF_EN = 0x00000100,
+	IC_CONF_PRPVF_CSC1 = 0x00000200,
+	IC_CONF_PRPVF_CSC2 = 0x00000400,
+	IC_CONF_PRPVF_CMB = 0x00000800,
+	IC_CONF_PRPVF_ROT_EN = 0x00001000,
+	IC_CONF_PP_EN = 0x00010000,
+	IC_CONF_PP_CSC1 = 0x00020000,
+	IC_CONF_PP_CSC2 = 0x00040000,
+	IC_CONF_PP_CMB = 0x00080000,
+	IC_CONF_PP_ROT_EN = 0x00100000,
+	IC_CONF_IC_GLB_LOC_A = 0x10000000,
+	IC_CONF_KEY_COLOR_EN = 0x20000000,
+	IC_CONF_RWS_EN = 0x40000000,
+	IC_CONF_CSI_MEM_WR_EN = 0x80000000,
+
+	IC_IDMAC_1_CB0_BURST_16 = 0x00000001,
+	IC_IDMAC_1_CB1_BURST_16 = 0x00000002,
+	IC_IDMAC_1_CB2_BURST_16 = 0x00000004,
+	IC_IDMAC_1_CB3_BURST_16 = 0x00000008,
+	IC_IDMAC_1_CB4_BURST_16 = 0x00000010,
+	IC_IDMAC_1_CB5_BURST_16 = 0x00000020,
+	IC_IDMAC_1_CB6_BURST_16 = 0x00000040,
+	IC_IDMAC_1_CB7_BURST_16 = 0x00000080,
+	IC_IDMAC_1_PRPENC_ROT_MASK = 0x00003800,
+	IC_IDMAC_1_PRPENC_ROT_OFFSET = 11,
+	IC_IDMAC_1_PRPVF_ROT_MASK = 0x0001C000,
+	IC_IDMAC_1_PRPVF_ROT_OFFSET = 14,
+	IC_IDMAC_1_PP_ROT_MASK = 0x000E0000,
+	IC_IDMAC_1_PP_ROT_OFFSET = 17,
+	IC_IDMAC_1_PP_FLIP_RS = 0x00400000,
+	IC_IDMAC_1_PRPVF_FLIP_RS = 0x00200000,
+	IC_IDMAC_1_PRPENC_FLIP_RS = 0x00100000,
+
+	IC_IDMAC_2_PRPENC_HEIGHT_MASK = 0x000003FF,
+	IC_IDMAC_2_PRPENC_HEIGHT_OFFSET = 0,
+	IC_IDMAC_2_PRPVF_HEIGHT_MASK = 0x000FFC00,
+	IC_IDMAC_2_PRPVF_HEIGHT_OFFSET = 10,
+	IC_IDMAC_2_PP_HEIGHT_MASK = 0x3FF00000,
+	IC_IDMAC_2_PP_HEIGHT_OFFSET = 20,
+
+	IC_IDMAC_3_PRPENC_WIDTH_MASK = 0x000003FF,
+	IC_IDMAC_3_PRPENC_WIDTH_OFFSET = 0,
+	IC_IDMAC_3_PRPVF_WIDTH_MASK = 0x000FFC00,
+	IC_IDMAC_3_PRPVF_WIDTH_OFFSET = 10,
+	IC_IDMAC_3_PP_WIDTH_MASK = 0x3FF00000,
+	IC_IDMAC_3_PP_WIDTH_OFFSET = 20,
+
+	CSI_SENS_CONF_DATA_FMT_SHIFT = 8,
+	CSI_SENS_CONF_DATA_FMT_MASK = 0x00000700,
+	CSI_SENS_CONF_DATA_FMT_RGB_YUV444 = 0L,
+	CSI_SENS_CONF_DATA_FMT_YUV422_YUYV = 1L,
+	CSI_SENS_CONF_DATA_FMT_YUV422_UYVY = 2L,
+	CSI_SENS_CONF_DATA_FMT_BAYER = 3L,
+	CSI_SENS_CONF_DATA_FMT_RGB565 = 4L,
+	CSI_SENS_CONF_DATA_FMT_RGB555 = 5L,
+	CSI_SENS_CONF_DATA_FMT_RGB444 = 6L,
+	CSI_SENS_CONF_DATA_FMT_JPEG = 7L,
+
+	CSI_SENS_CONF_VSYNC_POL_SHIFT = 0,
+	CSI_SENS_CONF_HSYNC_POL_SHIFT = 1,
+	CSI_SENS_CONF_DATA_POL_SHIFT = 2,
+	CSI_SENS_CONF_PIX_CLK_POL_SHIFT = 3,
+	CSI_SENS_CONF_SENS_PRTCL_MASK = 0x00000070L,
+	CSI_SENS_CONF_SENS_PRTCL_SHIFT = 4,
+	CSI_SENS_CONF_PACK_TIGHT_SHIFT = 7,
+	CSI_SENS_CONF_DATA_WIDTH_SHIFT = 11,
+	CSI_SENS_CONF_EXT_VSYNC_SHIFT = 15,
+	CSI_SENS_CONF_DIVRATIO_SHIFT = 16,
+
+	CSI_SENS_CONF_DIVRATIO_MASK = 0x00FF0000L,
+	CSI_SENS_CONF_DATA_DEST_SHIFT = 24,
+	CSI_SENS_CONF_DATA_DEST_MASK = 0x07000000L,
+	CSI_SENS_CONF_JPEG8_EN_SHIFT = 27,
+	CSI_SENS_CONF_JPEG_EN_SHIFT = 28,
+	CSI_SENS_CONF_FORCE_EOF_SHIFT = 29,
+	CSI_SENS_CONF_DATA_EN_POL_SHIFT = 31,
+
+	CSI_DATA_DEST_ISP = 1L,
+	CSI_DATA_DEST_IC = 2L,
+	CSI_DATA_DEST_IDMAC = 4L,
+
+	CSI_CCIR_ERR_DET_EN = 0x01000000L,
+	CSI_HORI_DOWNSIZE_EN = 0x80000000L,
+	CSI_VERT_DOWNSIZE_EN = 0x40000000L,
+	CSI_TEST_GEN_MODE_EN = 0x01000000L,
+
+	CSI_HSC_MASK = 0x1FFF0000,
+	CSI_HSC_SHIFT = 16,
+	CSI_VSC_MASK = 0x00000FFF,
+	CSI_VSC_SHIFT = 0,
+
+	CSI_TEST_GEN_R_MASK = 0x000000FFL,
+	CSI_TEST_GEN_R_SHIFT = 0,
+	CSI_TEST_GEN_G_MASK = 0x0000FF00L,
+	CSI_TEST_GEN_G_SHIFT = 8,
+	CSI_TEST_GEN_B_MASK = 0x00FF0000L,
+	CSI_TEST_GEN_B_SHIFT = 16,
+
+	CSI_MIPI_DI0_MASK = 0x000000FFL,
+	CSI_MIPI_DI0_SHIFT = 0,
+	CSI_MIPI_DI1_MASK = 0x0000FF00L,
+	CSI_MIPI_DI1_SHIFT = 8,
+	CSI_MIPI_DI2_MASK = 0x00FF0000L,
+	CSI_MIPI_DI2_SHIFT = 16,
+	CSI_MIPI_DI3_MASK = 0xFF000000L,
+	CSI_MIPI_DI3_SHIFT = 24,
+
+	CSI_MAX_RATIO_SKIP_ISP_MASK = 0x00070000L,
+	CSI_MAX_RATIO_SKIP_ISP_SHIFT = 16,
+	CSI_SKIP_ISP_MASK = 0x00F80000L,
+	CSI_SKIP_ISP_SHIFT = 19,
+	CSI_MAX_RATIO_SKIP_SMFC_MASK = 0x00000007L,
+	CSI_MAX_RATIO_SKIP_SMFC_SHIFT = 0,
+	CSI_SKIP_SMFC_MASK = 0x000000F8L,
+	CSI_SKIP_SMFC_SHIFT = 3,
+	CSI_ID_2_SKIP_MASK = 0x00000300L,
+	CSI_ID_2_SKIP_SHIFT = 8,
+
+	CSI_COLOR_FIRST_ROW_MASK = 0x00000002L,
+	CSI_COLOR_FIRST_COMP_MASK = 0x00000001L,
+
+	SMFC_MAP_CH0_MASK = 0x00000007L,
+	SMFC_MAP_CH0_SHIFT = 0,
+	SMFC_MAP_CH1_MASK = 0x00000038L,
+	SMFC_MAP_CH1_SHIFT = 3,
+	SMFC_MAP_CH2_MASK = 0x000001C0L,
+	SMFC_MAP_CH2_SHIFT = 6,
+	SMFC_MAP_CH3_MASK = 0x00000E00L,
+	SMFC_MAP_CH3_SHIFT = 9,
+
+	SMFC_WM0_SET_MASK = 0x00000007L,
+	SMFC_WM0_SET_SHIFT = 0,
+	SMFC_WM1_SET_MASK = 0x000001C0L,
+	SMFC_WM1_SET_SHIFT = 6,
+	SMFC_WM2_SET_MASK = 0x00070000L,
+	SMFC_WM2_SET_SHIFT = 16,
+	SMFC_WM3_SET_MASK = 0x01C00000L,
+	SMFC_WM3_SET_SHIFT = 22,
+
+	SMFC_WM0_CLR_MASK = 0x00000038L,
+	SMFC_WM0_CLR_SHIFT = 3,
+	SMFC_WM1_CLR_MASK = 0x00000E00L,
+	SMFC_WM1_CLR_SHIFT = 9,
+	SMFC_WM2_CLR_MASK = 0x00380000L,
+	SMFC_WM2_CLR_SHIFT = 19,
+	SMFC_WM3_CLR_MASK = 0x0E000000L,
+	SMFC_WM3_CLR_SHIFT = 25,
+
+	SMFC_BS0_MASK = 0x0000000FL,
+	SMFC_BS0_SHIFT = 0,
+	SMFC_BS1_MASK = 0x000000F0L,
+	SMFC_BS1_SHIFT = 4,
+	SMFC_BS2_MASK = 0x00000F00L,
+	SMFC_BS2_SHIFT = 8,
+	SMFC_BS3_MASK = 0x0000F000L,
+	SMFC_BS3_SHIFT = 12,
+
+	PF_CONF_TYPE_MASK = 0x00000007,
+	PF_CONF_TYPE_SHIFT = 0,
+	PF_CONF_PAUSE_EN = 0x00000010,
+	PF_CONF_RESET = 0x00008000,
+	PF_CONF_PAUSE_ROW_MASK = 0x00FF0000,
+	PF_CONF_PAUSE_ROW_SHIFT = 16,
+
+	DI_DW_GEN_ACCESS_SIZE_OFFSET = 24,
+	DI_DW_GEN_COMPONENT_SIZE_OFFSET = 16,
+
+	DI_GEN_DI_CLK_EXT = 0x100000,
+	DI_GEN_POLARITY_DISP_CLK = 0x00020000,
+	DI_GEN_POLARITY_1 = 0x00000001,
+	DI_GEN_POLARITY_2 = 0x00000002,
+	DI_GEN_POLARITY_3 = 0x00000004,
+	DI_GEN_POLARITY_4 = 0x00000008,
+	DI_GEN_POLARITY_5 = 0x00000010,
+	DI_GEN_POLARITY_6 = 0x00000020,
+	DI_GEN_POLARITY_7 = 0x00000040,
+	DI_GEN_POLARITY_8 = 0x00000080,
+
+	DI_POL_DRDY_DATA_POLARITY = 0x00000080,
+	DI_POL_DRDY_POLARITY_15 = 0x00000010,
+
+	DI_VSYNC_SEL_OFFSET = 13,
+
+	DC_WR_CH_CONF_FIELD_MODE = 0x00000200,
+	DC_WR_CH_CONF_PROG_TYPE_OFFSET = 5,
+	DC_WR_CH_CONF_PROG_TYPE_MASK = 0x000000E0,
+	DC_WR_CH_CONF_PROG_DI_ID = 0x00000004,
+	DC_WR_CH_CONF_PROG_DISP_ID_OFFSET = 3,
+	DC_WR_CH_CONF_PROG_DISP_ID_MASK = 0x00000018,
+
+	DC_UGDE_0_ODD_EN = 0x02000000,
+	DC_UGDE_0_ID_CODED_MASK = 0x00000007,
+	DC_UGDE_0_ID_CODED_OFFSET = 0,
+	DC_UGDE_0_EV_PRIORITY_MASK = 0x00000078,
+	DC_UGDE_0_EV_PRIORITY_OFFSET = 3,
+
+	DP_COM_CONF_FG_EN = 0x00000001,
+	DP_COM_CONF_GWSEL = 0x00000002,
+	DP_COM_CONF_GWAM = 0x00000004,
+	DP_COM_CONF_GWCKE = 0x00000008,
+	DP_COM_CONF_CSC_DEF_MASK = 0x00000300,
+	DP_COM_CONF_CSC_DEF_OFFSET = 8,
+	DP_COM_CONF_CSC_DEF_FG = 0x00000300,
+	DP_COM_CONF_CSC_DEF_BG = 0x00000200,
+	DP_COM_CONF_CSC_DEF_BOTH = 0x00000100,
+	DP_COM_CONF_GAMMA_EN = 0x00001000,
+	DP_COM_CONF_GAMMA_YUV_EN = 0x00002000,
+
+	DI_SER_CONF_LLA_SER_ACCESS = 0x00000020,
+	DI_SER_CONF_SERIAL_CLK_POL = 0x00000010,
+	DI_SER_CONF_SERIAL_DATA_POL = 0x00000008,
+	DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
+	DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
+	DI_SER_CONF_WAIT4SERIAL = 0x00000001,
+
+	VDI_C_CH_420 = 0x00000000,
+	VDI_C_CH_422 = 0x00000002,
+	VDI_C_MOT_SEL_FULL = 0x00000008,
+	VDI_C_MOT_SEL_LOW = 0x00000004,
+	VDI_C_MOT_SEL_MED = 0x00000000,
+	VDI_C_BURST_SIZE1_4 = 0x00000030,
+	VDI_C_BURST_SIZE2_4 = 0x00000300,
+	VDI_C_BURST_SIZE3_4 = 0x00003000,
+	VDI_C_VWM1_SET_1 = 0x00000000,
+	VDI_C_VWM1_CLR_2 = 0x00080000,
+	VDI_C_VWM3_SET_1 = 0x00000000,
+	VDI_C_VWM3_CLR_2 = 0x02000000,
+	VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
+	VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
+};
+
+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 = -1,
+	DI_SYNC_CLK = 0,
+	DI_SYNC_INT_HSYNC = 1,
+	DI_SYNC_HSYNC = 2,
+	DI_SYNC_VSYNC = 3,
+	DI_SYNC_DE = 5,
+};
+
+/* DC template opcodes */
+#define WROD(lf)		(0x18 | (lf << 1))
+#define WRG	        	(0x01)
+
+#endif
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
new file mode 100644
index 0000000..d6c1588
--- /dev/null
+++ b/include/linux/ipu.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2005-2011 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
+ */
+
+/*!
+ * @defgroup IPU MXC Image Processing Unit (IPU) Driver
+ */
+/*!
+ * @file arch-mxc/ipu.h
+ *
+ * @brief This file contains the IPU driver API declarations.
+ *
+ * @ingroup IPU
+ */
+
+#ifndef __ASM_ARCH_IPU_H__
+#define __ASM_ARCH_IPU_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#ifdef __KERNEL__
+#include <linux/interrupt.h>
+#else
+#ifndef __cplusplus
+typedef unsigned char bool;
+#endif
+#define irqreturn_t int
+#define dma_addr_t int
+#define uint32_t unsigned int
+#define uint16_t unsigned short
+#define uint8_t unsigned char
+#define u32 unsigned int
+#define u8 unsigned char
+#define __u32 u32
+#endif
+
+/*!
+ * 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;
+
+/*!
+ * Enumeration of VDI MOTION select
+ */
+typedef enum {
+	MED_MOTION = 0,
+	LOW_MOTION = 1,
+	HIGH_MOTION = 2,
+} ipu_motion_sel;
+
+/*!
+ * Enumeration of DI ports for ADC.
+ */
+typedef enum {
+	DISP0,
+	DISP1,
+	DISP2,
+	DISP3
+} display_port_t;
+
+/*  IPU Pixel format definitions */
+/*  Four-character-code (FOURCC) */
+#define fourcc(a, b, c, d)\
+	 (((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
+
+/*!
+ * @name IPU Pixel Formats
+ *
+ * Pixel formats are defined with ASCII FOURCC code. The pixel format codes are
+ * the same used by V4L2 API.
+ */
+
+/*! @{ */
+/*! @name Generic or Raw Data Formats */
+/*! @{ */
+#define IPU_PIX_FMT_GENERIC fourcc('I', 'P', 'U', '0')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_GENERIC_32 fourcc('I', 'P', 'U', '1')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_LVDS666 fourcc('L', 'V', 'D', '6')	/*!< IPU Generic Data */
+#define IPU_PIX_FMT_LVDS888 fourcc('L', 'V', 'D', '8')	/*!< IPU Generic Data */
+/*! @} */
+/*! @name RGB Formats */
+/*! @{ */
+#define IPU_PIX_FMT_RGB332  fourcc('R', 'G', 'B', '1')	/*!<  8  RGB-3-3-2    */
+#define IPU_PIX_FMT_RGB555  fourcc('R', 'G', 'B', 'O')	/*!< 16  RGB-5-5-5    */
+#define IPU_PIX_FMT_RGB565  fourcc('R', 'G', 'B', 'P')	/*!< 1 6  RGB-5-6-5   */
+#define IPU_PIX_FMT_RGB666  fourcc('R', 'G', 'B', '6')	/*!< 18  RGB-6-6-6    */
+#define IPU_PIX_FMT_BGR666  fourcc('B', 'G', 'R', '6')	/*!< 18  BGR-6-6-6    */
+#define IPU_PIX_FMT_BGR24   fourcc('B', 'G', 'R', '3')	/*!< 24  BGR-8-8-8    */
+#define IPU_PIX_FMT_RGB24   fourcc('R', 'G', 'B', '3')	/*!< 24  RGB-8-8-8    */
+#define IPU_PIX_FMT_GBR24   fourcc('G', 'B', 'R', '3')	/*!< 24  GBR-8-8-8    */
+#define IPU_PIX_FMT_BGR32   fourcc('B', 'G', 'R', '4')	/*!< 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_BGRA32  fourcc('B', 'G', 'R', 'A')	/*!< 32  BGR-8-8-8-8  */
+#define IPU_PIX_FMT_RGB32   fourcc('R', 'G', 'B', '4')	/*!< 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_RGBA32  fourcc('R', 'G', 'B', 'A')	/*!< 32  RGB-8-8-8-8  */
+#define IPU_PIX_FMT_ABGR32  fourcc('A', 'B', 'G', 'R')	/*!< 32  ABGR-8-8-8-8 */
+/*! @} */
+/*! @name YUV Interleaved Formats */
+/*! @{ */
+#define IPU_PIX_FMT_YUYV    fourcc('Y', 'U', 'Y', 'V')	/*!< 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_UYVY    fourcc('U', 'Y', 'V', 'Y')	/*!< 16 YUV 4:2:2 */
+#define IPU_PIX_FMT_YVYU    fourcc('Y', 'V', 'Y', 'U')  /*!< 16 YVYU 4:2:2 */
+#define IPU_PIX_FMT_VYUY    fourcc('V', 'Y', 'U', 'Y')  /*!< 16 VYYU 4:2:2 */
+#define IPU_PIX_FMT_Y41P    fourcc('Y', '4', '1', 'P')	/*!< 12 YUV 4:1:1 */
+#define IPU_PIX_FMT_YUV444  fourcc('Y', '4', '4', '4')	/*!< 24 YUV 4:4:4 */
+#define IPU_PIX_FMT_VYU444  fourcc('V', '4', '4', '4')	/*!< 24 VYU 4:4:4 */
+/* two planes -- one Y, one Cb + Cr interleaved  */
+#define IPU_PIX_FMT_NV12    fourcc('N', 'V', '1', '2') /* 12  Y/CbCr 4:2:0  */
+/*! @} */
+/*! @name YUV Planar Formats */
+/*! @{ */
+#define IPU_PIX_FMT_GREY    fourcc('G', 'R', 'E', 'Y')	/*!< 8  Greyscale */
+#define IPU_PIX_FMT_YVU410P fourcc('Y', 'V', 'U', '9')	/*!< 9  YVU 4:1:0 */
+#define IPU_PIX_FMT_YUV410P fourcc('Y', 'U', 'V', '9')	/*!< 9  YUV 4:1:0 */
+#define IPU_PIX_FMT_YVU420P fourcc('Y', 'V', '1', '2')	/*!< 12 YVU 4:2:0 */
+#define IPU_PIX_FMT_YUV420P fourcc('I', '4', '2', '0')	/*!< 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YUV420P2 fourcc('Y', 'U', '1', '2')	/*!< 12 YUV 4:2:0 */
+#define IPU_PIX_FMT_YVU422P fourcc('Y', 'V', '1', '6')	/*!< 16 YVU 4:2:2 */
+#define IPU_PIX_FMT_YUV422P fourcc('4', '2', '2', 'P')	/*!< 16 YUV 4:2:2 */
+/*! @} */
+
+/* IPU device */
+struct ipu_pos {
+	u32 x;
+	u32 y;
+};
+
+struct ipu_crop {
+	struct ipu_pos pos;
+	u32 w;
+	u32 h;
+};
+
+struct ipu_deinterlace {
+	bool	enable;
+	u8	motion; /*see ipu_motion_sel*/
+#define IPU_DEINTERLACE_FIELD_TOP	0
+#define IPU_DEINTERLACE_FIELD_BOTTOM	1
+	u8	field_fmt;
+};
+
+struct ipu_input {
+	u32 width;
+	u32 height;
+	u32 format;
+	struct ipu_crop crop;
+	dma_addr_t paddr;
+
+	struct ipu_deinterlace deinterlace;
+	dma_addr_t paddr_n; /*valid when deinterlace enable*/
+};
+
+struct ipu_alpha {
+#define IPU_ALPHA_MODE_GLOBAL	0
+#define IPU_ALPHA_MODE_LOCAL	1
+	u8 mode;
+	u8 gvalue; /* 0~255 */
+	dma_addr_t loc_alp_paddr;
+};
+
+struct ipu_colorkey {
+	bool enable;
+	u32 value; /* RGB 24bit */
+};
+
+struct ipu_overlay {
+	u32	width;
+	u32	height;
+	u32	format;
+	struct ipu_crop crop;
+	struct ipu_alpha alpha;
+	struct ipu_colorkey colorkey;
+	dma_addr_t paddr;
+};
+
+struct ipu_output {
+	u32	width;
+	u32	height;
+	u32	format;
+	u8	rotate;
+	struct ipu_crop crop;
+	dma_addr_t paddr;
+};
+
+struct ipu_task {
+	struct ipu_input input;
+	struct ipu_output output;
+
+	bool overlay_en;
+	struct ipu_overlay overlay;
+
+#define IPU_TASK_PRIORITY_NORMAL 0
+#define IPU_TASK_PRIORITY_HIGH	1
+	u8	priority;
+
+#define	IPU_TASK_ID_ANY	0
+#define	IPU_TASK_ID_VF	1
+#define	IPU_TASK_ID_PP	2
+#define	IPU_TASK_ID_MAX 3
+	u8	task_id;
+
+	int	timeout;
+};
+
+enum {
+	IPU_CHECK_OK = 0,
+	IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN = 0x1,
+	IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN = 0x2,
+	IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN = 0x4,
+	IPU_CHECK_ERR_MIN,
+	IPU_CHECK_ERR_INPUT_CROP,
+	IPU_CHECK_ERR_OUTPUT_CROP,
+	IPU_CHECK_ERR_OVERLAY_CROP,
+	IPU_CHECK_ERR_INPUT_OVER_LIMIT,
+	IPU_CHECK_ERR_OV_OUT_NO_FIT,
+	IPU_CHECK_ERR_OVERLAY_WITH_VDI,
+	IPU_CHECK_ERR_PROC_NO_NEED,
+	IPU_CHECK_ERR_SPLIT_INPUTW_OVER,
+	IPU_CHECK_ERR_SPLIT_INPUTH_OVER,
+	IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER,
+	IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER,
+};
+
+/* IOCTL commands */
+#define IPU_CHECK_TASK		_IOWR('I', 0x1, struct ipu_task)
+#define IPU_QUEUE_TASK		_IOW('I', 0x2, struct ipu_task)
+#define IPU_ALLOC		_IOWR('I', 0x3, int)
+#define IPU_FREE		_IOW('I', 0x4, int)
+
+#endif