]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
ENGR00240987: ipu: port ipuv3 driver from 3.5.7 kernel
authorShawn Guo <shawn.guo@freescale.com>
Tue, 23 Jul 2013 14:49:00 +0000 (22:49 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Mon, 16 Jun 2014 13:24:13 +0000 (15:24 +0200)
This is a fast-forward porting of ipuv3 driver from 3.5.7 kernel to
kernel 3.10.  The change set is kept as minimum as possible with only
making necessary code changes to adapt 3.10 kernel internal API and
framework updates.  Everything else should be same as 3.5.7 one.  The
change set consists of the following.

 * Remove unused Kconfig options MXC_IPU_V3D, MXC_IPU_V3EX and
   MXC_IPU_V3H
 * Comment out busfreq calls
 * Move ipu-v3.h into include/linux/, and remove all <mach/*> includes
 * Drop __devinit and __devexit
 * Remove assignment of pltfm_data->pg = imx6q_ipu_pg;
 * Use generic device_reset() API rather than ipu_pltfm_data->init()
   hook to reset IPU
 * Includes <linux/sched/rt.h> ipu_device.c to fix undeclared
   MAX_USER_RT_PRIO error
 * Change compatible string to "fsl,imx6q-ipu" to align with community
   kernel
 * Define irq_sync before irq_err in DTS to align with community kernel
 * Drop "ipu1_" and "ipu2_" from clock names to save the handling of the
   second parameter of devm_clk_get()
 * Remove the buggy csi_clk setup in ipu_clk_setup_enable() and validate
   the clock before operate on it in ipu_csi_enable_mclk()
 * Replace iram API (linux/iram_alloc.h) with generic memory pool API
   (linux/genalloc.h) in VDOA driver

Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
20 files changed:
drivers/Kconfig
drivers/Makefile
drivers/mxc/Kconfig [new file with mode: 0644]
drivers/mxc/Makefile [new file with mode: 0644]
drivers/mxc/ipu3/Kconfig [new file with mode: 0644]
drivers/mxc/ipu3/Makefile [new file with mode: 0644]
drivers/mxc/ipu3/ipu_calc_stripes_sizes.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_capture.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_common.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_device.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_disp.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_ic.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_param_mem.h [new file with mode: 0644]
drivers/mxc/ipu3/ipu_pixel_clk.c [new file with mode: 0644]
drivers/mxc/ipu3/ipu_prv.h [new file with mode: 0644]
drivers/mxc/ipu3/ipu_regs.h [new file with mode: 0644]
drivers/mxc/ipu3/vdoa.c [new file with mode: 0644]
drivers/mxc/ipu3/vdoa.h [new file with mode: 0644]
include/linux/ipu-v3.h [new file with mode: 0644]
include/linux/ipu.h [new file with mode: 0644]

index 0e87a34b6472e65c62c1d4b4bdd3d6ac49dc3624..906f6daf6c903d772de93e43436f1c2835c9dfb4 100644 (file)
@@ -98,6 +98,8 @@ source "drivers/mmc/Kconfig"
 
 source "drivers/memstick/Kconfig"
 
+source "drivers/mxc/Kconfig"
+
 source "drivers/leds/Kconfig"
 
 source "drivers/accessibility/Kconfig"
index f98b50d8251d3849dfb871ca1fef595f0677bbc0..7c241900e5003179286a1b88433b2bd3076663c4 100644 (file)
@@ -114,6 +114,7 @@ obj-y                               += lguest/
 obj-$(CONFIG_CPU_FREQ)         += cpufreq/
 obj-$(CONFIG_CPU_IDLE)         += cpuidle/
 obj-y                          += mmc/
+obj-$(CONFIG_ARCH_MXC)         += mxc/
 obj-$(CONFIG_MEMSTICK)         += memstick/
 obj-y                          += leds/
 obj-$(CONFIG_INFINIBAND)       += infiniband/
diff --git a/drivers/mxc/Kconfig b/drivers/mxc/Kconfig
new file mode 100644 (file)
index 0000000..9ba4afb
--- /dev/null
@@ -0,0 +1,18 @@
+# drivers/mxc/Kconfig
+
+if ARCH_MXC
+
+menu "MXC support drivers"
+
+config MXC_IPU
+       bool "Image Processing Unit Driver"
+       select MXC_IPU_V3
+       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
new file mode 100644 (file)
index 0000000..bc576c6
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_MXC_IPU_V3) += ipu3/
diff --git a/drivers/mxc/ipu3/Kconfig b/drivers/mxc/ipu3/Kconfig
new file mode 100644 (file)
index 0000000..06bebff
--- /dev/null
@@ -0,0 +1,2 @@
+config MXC_IPU_V3
+       bool
diff --git a/drivers/mxc/ipu3/Makefile b/drivers/mxc/ipu3/Makefile
new file mode 100644 (file)
index 0000000..0259d68
--- /dev/null
@@ -0,0 +1,4 @@
+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 vdoa.o ipu_pixel_clk.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 (file)
index 0000000..4458996
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2009-2013 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/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/math64.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 u32 truncate(u32 up, /* 0: down; else: up */
+                                       u64 a, /* must be non-negative */
+                                       u32 b)
+{
+       u32 d;
+       u64 div;
+       div = div_u64(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:
+       case IPU_PIX_FMT_YUV444P:
+               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_YUV444P:
+       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 = f_calc(input_pixelformat, 0, NULL);
+       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 = m_calc(output_pixelformat);
+
+
+       if ((input_frame_width < 4) || (output_frame_width < 4))
+               return 1;
+
+       irr_opt = div_u64((((u64)(input_frame_width - 1)) << 32),
+                         (output_frame_width - 1));
+       rr_opt = div_u64((((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 = div_u64(((((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 = div_u64((((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) + div_u64(div, irr_steps);
+
+                       left->input_width = right->input_width = truncate(1, div, input_m);
+
+                       div = div_u64((((u64)((right->output_width - 1) * right->irr)) <<
+                                      32), irr_steps);
+                       difwr = (((u64)(input_frame_width - 1 - inw)) << 32) - div;
+                       div = div_u64((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 = div_u64((((u64)(irr_steps * inw)) << 32), onw);
+                       left->irr = truncate(0, div, 1);
+                       div = div_u64((((u64)(onw * left->irr)) << 32),
+                                     irr_steps);
+                       dinw = (((u64)inw) << 32) - div;
+
+                       div = div_u64((((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 = div_u64((((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 = div_u64((((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 = div_u64(((u64)((right->output_width - 1) * right->irr) <<
+                              32), irr_steps);
+               difwr = (u64)(input_frame_width - 1 - inw) - div;
+
+
+               div = div_u64((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 (file)
index 0000000..a14b0ea
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Copyright 2008-2013 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/clk.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+/*!
+ * _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, "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_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;
+
+       /* 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:
+       case IPU_PIX_FMT_GENERIC_16:
+               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);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       ipu_csi_write(ipu, csi, data, CSI_SENS_CONF);
+
+       /* Setup the mclk */
+       if (cfg_param.mclk > 0)
+               _ipu_csi_mclk_set(ipu, cfg_param.mclk, csi);
+
+       /* 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 = 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 if (width == 720 && height == 525) {
+                       /* NTSC case */
+                       /*
+                        * Field1BlankEnd = 0x6, Field1BlankStart = 0x2,
+                        * Field1ActiveEnd = 0x4, Field1ActiveStart = 0
+                        */
+                       ipu_csi_write(ipu, csi, 0x40596, CSI_CCIR_CODE_1);
+                       /*
+                        * Field0BlankEnd = 0x7, Field0BlankStart = 0x3,
+                        * Field0ActiveEnd = 0x5, Field0ActiveStart = 0x1
+                        */
+                       ipu_csi_write(ipu, csi, 0xD07DF, 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");
+                       mutex_unlock(&ipu->mutex_lock);
+                       _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));
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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)
+{
+       int ret;
+       _ipu_get(ipu);
+       ret = (ipu_csi_read(ipu, csi, CSI_SENS_CONF) &
+               CSI_SENS_CONF_SENS_PRTCL_MASK) >>
+               CSI_SENS_CONF_SENS_PRTCL_SHIFT;
+       _ipu_put(ipu);
+       return ret;
+}
+EXPORT_SYMBOL(ipu_csi_get_sensor_protocol);
+
+/*!
+ * 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)
+{
+       /* Return immediately if there is no csi_clk to manage */
+       if (ipu->csi_clk[csi] == NULL)
+               return 0;
+
+       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;
+
+       _ipu_get(ipu);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       reg = ipu_csi_read(ipu, csi, CSI_ACT_FRM_SIZE);
+       *width = (reg & 0xFFFF) + 1;
+       *height = (reg >> 16 & 0xFFFF) + 1;
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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)
+{
+       _ipu_get(ipu);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       ipu_csi_write(ipu, csi, (width - 1) | (height - 1) << 16, CSI_ACT_FRM_SIZE);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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;
+
+       _ipu_get(ipu);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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;
+}
+
+/*!
+ * csi_irq_handler
+ *
+ * @param      irq             interrupt id
+ * @param      dev_id          pointer to ipu handler
+ *
+ * @return     Returns if irq is handled
+ */
+static irqreturn_t csi_irq_handler(int irq, void *dev_id)
+{
+       struct ipu_soc *ipu = dev_id;
+       struct completion *comp = &ipu->csi_comp;
+
+       complete(comp);
+       return IRQ_HANDLED;
+}
+
+/*!
+ * _ipu_csi_wait4eof
+ *
+ * @param      ipu             ipu handler
+ * @param      channel      IDMAC channel
+ *
+ */
+void _ipu_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+       int ret;
+       int irq = 0;
+
+       if (channel == CSI_MEM0)
+               irq = IPU_IRQ_CSI0_OUT_EOF;
+       else if (channel == CSI_MEM1)
+               irq = IPU_IRQ_CSI1_OUT_EOF;
+       else if (channel == CSI_MEM2)
+               irq = IPU_IRQ_CSI2_OUT_EOF;
+       else if (channel == CSI_MEM3)
+               irq = IPU_IRQ_CSI3_OUT_EOF;
+       else if (channel == CSI_PRP_ENC_MEM)
+               irq = IPU_IRQ_PRP_ENC_OUT_EOF;
+       else if (channel == CSI_PRP_VF_MEM)
+               irq = IPU_IRQ_PRP_VF_OUT_EOF;
+       else{
+               dev_err(ipu->dev, "Not a CSI channel\n");
+               return;
+       }
+
+       init_completion(&ipu->csi_comp);
+       ret = ipu_request_irq(ipu, irq, csi_irq_handler, 0, NULL, ipu);
+       if (ret < 0) {
+               dev_err(ipu->dev, "CSI irq %d in use\n", irq);
+               return;
+       }
+       ret = wait_for_completion_timeout(&ipu->csi_comp, msecs_to_jiffies(500));
+       ipu_free_irq(ipu, irq, ipu);
+       dev_dbg(ipu->dev, "CSI stop timeout - %d * 10ms\n", 5 - ret);
+}
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
new file mode 100644 (file)
index 0000000..e8b4fba
--- /dev/null
@@ -0,0 +1,3099 @@
+/*
+ * Copyright 2005-2013 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/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/cacheflush.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+static struct ipu_soc ipu_array[MXC_IPU_MAX_NUM];
+int g_ipu_hw_rev;
+
+/* Static functions */
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc);
+static irqreturn_t ipu_err_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_vdi_out_chan(uint32_t dma_chan)
+{
+       return (dma_chan == 5);
+}
+
+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 >= IPU_V3DEX));
+}
+
+/*
+ * We usually use IDMAC 23 as full plane and IDMAC 27 as partial
+ * plane.
+ * IDMAC 23/24/28/41 can drive a display respectively - primary
+ * IDMAC 27 depends on IDMAC 23 - nonprimary
+ */
+static inline int _ipu_is_primary_disp_chan(uint32_t dma_chan)
+{
+       return ((dma_chan == 23) || (dma_chan == 24) ||
+               (dma_chan == 28) || (dma_chan == 41));
+}
+
+static inline int _ipu_is_sync_irq(uint32_t irq)
+{
+       /* sync interrupt register number */
+       int reg_num = irq / 32 + 1;
+
+       return ((reg_num == 1)  || (reg_num == 2)  || (reg_num == 3)  ||
+               (reg_num == 4)  || (reg_num == 7)  || (reg_num == 8)  ||
+               (reg_num == 11) || (reg_num == 12) || (reg_num == 13) ||
+               (reg_num == 14) || (reg_num == 15));
+}
+
+#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_clk_setup_enable(struct ipu_soc *ipu,
+                       struct ipu_pltfm_data *pdata)
+{
+       char pixel_clk_0[] = "ipu1_pclk_0";
+       char pixel_clk_1[] = "ipu1_pclk_1";
+       char pixel_clk_0_sel[] = "ipu1_pclk0_sel";
+       char pixel_clk_1_sel[] = "ipu1_pclk1_sel";
+       char pixel_clk_0_div[] = "ipu1_pclk0_div";
+       char pixel_clk_1_div[] = "ipu1_pclk1_div";
+       char *ipu_pixel_clk_sel[] = { "ipu1", "ipu1_di0", "ipu1_di1", };
+       char *pclk_sel;
+       struct clk *clk;
+       int ret;
+       int i;
+
+       pixel_clk_0[3] += pdata->id;
+       pixel_clk_1[3] += pdata->id;
+       pixel_clk_0_sel[3] += pdata->id;
+       pixel_clk_1_sel[3] += pdata->id;
+       pixel_clk_0_div[3] += pdata->id;
+       pixel_clk_1_div[3] += pdata->id;
+       for (i = 0; i < ARRAY_SIZE(ipu_pixel_clk_sel); i++) {
+               pclk_sel = ipu_pixel_clk_sel[i];
+               pclk_sel[3] += pdata->id;
+       }
+       dev_dbg(ipu->dev, "ipu_clk = %lu\n", clk_get_rate(ipu->ipu_clk));
+
+       clk = clk_register_mux_pix_clk(ipu->dev, pixel_clk_0_sel,
+                       (const char **)ipu_pixel_clk_sel,
+                       ARRAY_SIZE(ipu_pixel_clk_sel),
+                       0, pdata->id, 0, 0);
+       if (IS_ERR(clk)) {
+               dev_err(ipu->dev, "clk_register mux di0 failed");
+               return PTR_ERR(clk);
+       }
+       ipu->pixel_clk_sel[0] = clk;
+       clk = clk_register_mux_pix_clk(ipu->dev, pixel_clk_1_sel,
+                       (const char **)ipu_pixel_clk_sel,
+                       ARRAY_SIZE(ipu_pixel_clk_sel),
+                       0, pdata->id, 1, 0);
+       if (IS_ERR(clk)) {
+               dev_err(ipu->dev, "clk_register mux di1 failed");
+               return PTR_ERR(clk);
+       }
+       ipu->pixel_clk_sel[1] = clk;
+
+       clk = clk_register_div_pix_clk(ipu->dev, pixel_clk_0_div,
+                               pixel_clk_0_sel, 0, pdata->id, 0, 0);
+       if (IS_ERR(clk)) {
+               dev_err(ipu->dev, "clk register di0 div failed");
+               return PTR_ERR(clk);
+       }
+       clk = clk_register_div_pix_clk(ipu->dev, pixel_clk_1_div,
+                       pixel_clk_1_sel, CLK_SET_RATE_PARENT, pdata->id, 1, 0);
+       if (IS_ERR(clk)) {
+               dev_err(ipu->dev, "clk register di1 div failed");
+               return PTR_ERR(clk);
+       }
+
+       ipu->pixel_clk[0] = clk_register_gate_pix_clk(ipu->dev, pixel_clk_0,
+                               pixel_clk_0_div, CLK_SET_RATE_PARENT,
+                               pdata->id, 0, 0);
+       if (IS_ERR(ipu->pixel_clk[0])) {
+               dev_err(ipu->dev, "clk register di0 gate failed");
+               return PTR_ERR(ipu->pixel_clk[0]);
+       }
+       ipu->pixel_clk[1] = clk_register_gate_pix_clk(ipu->dev, pixel_clk_1,
+                               pixel_clk_1_div, CLK_SET_RATE_PARENT,
+                               pdata->id, 1, 0);
+       if (IS_ERR(ipu->pixel_clk[1])) {
+               dev_err(ipu->dev, "clk register di1 gate failed");
+               return PTR_ERR(ipu->pixel_clk[1]);
+       }
+
+       ret = clk_set_parent(ipu->pixel_clk_sel[0], ipu->ipu_clk);
+       if (ret) {
+               dev_err(ipu->dev, "clk set parent failed");
+               return ret;
+       }
+
+       ret = clk_set_parent(ipu->pixel_clk_sel[1], ipu->ipu_clk);
+       if (ret) {
+               dev_err(ipu->dev, "clk set parent failed");
+               return ret;
+       }
+
+       ipu->di_clk[0] = devm_clk_get(ipu->dev, "di0");
+       if (IS_ERR(ipu->di_clk[0])) {
+               dev_err(ipu->dev, "clk_get di0 failed");
+               return PTR_ERR(ipu->di_clk[0]);
+       }
+       ipu->di_clk[1] = devm_clk_get(ipu->dev, "di1");
+       if (IS_ERR(ipu->di_clk[1])) {
+               dev_err(ipu->dev, "clk_get di1 failed");
+               return PTR_ERR(ipu->di_clk[1]);
+       }
+
+       ipu->di_clk_sel[0] = devm_clk_get(ipu->dev, "di0_sel");
+       if (IS_ERR(ipu->di_clk_sel[0])) {
+               dev_err(ipu->dev, "clk_get di0_sel failed");
+               return PTR_ERR(ipu->di_clk_sel[0]);
+       }
+       ipu->di_clk_sel[1] = devm_clk_get(ipu->dev, "di1_sel");
+       if (IS_ERR(ipu->di_clk_sel[1])) {
+               dev_err(ipu->dev, "clk_get di1_sel failed");
+               return PTR_ERR(ipu->di_clk_sel[1]);
+       }
+
+       return 0;
+}
+
+static int ipu_mem_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;
+}
+
+struct ipu_soc *ipu_get_soc(int id)
+{
+       if (id >= MXC_IPU_MAX_NUM)
+               return ERR_PTR(-ENODEV);
+       else if (!ipu_array[id].online)
+               return ERR_PTR(-ENODEV);
+       else
+               return &(ipu_array[id]);
+}
+EXPORT_SYMBOL_GPL(ipu_get_soc);
+
+void _ipu_get(struct ipu_soc *ipu)
+{
+       int ret;
+
+       ret = clk_enable(ipu->ipu_clk);
+       if (ret < 0)
+               BUG();
+}
+
+void _ipu_put(struct ipu_soc *ipu)
+{
+       clk_disable(ipu->ipu_clk);
+}
+
+void ipu_disable_hsp_clk(struct ipu_soc *ipu)
+{
+       _ipu_put(ipu);
+}
+EXPORT_SYMBOL(ipu_disable_hsp_clk);
+
+static struct platform_device_id imx_ipu_type[] = {
+       {
+               .name = "ipu-imx6q",
+               .driver_data = IPU_V3H,
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(platform, imx_ipu_type);
+
+static const struct of_device_id imx_ipuv3_dt_ids[] = {
+       { .compatible = "fsl,imx6q-ipu", .data = &imx_ipu_type[IMX6Q_IPU], },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx_ipuv3_dt_ids);
+
+/*!
+ * 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 ipu_probe(struct platform_device *pdev)
+{
+       struct ipu_soc *ipu;
+       struct resource *res;
+       unsigned long ipu_base;
+       const struct of_device_id *of_id =
+                       of_match_device(imx_ipuv3_dt_ids, &pdev->dev);
+       struct ipu_pltfm_data *pltfm_data;
+       int ret = 0;
+       u32 bypass_reset;
+
+       dev_dbg(&pdev->dev, "<%s>\n", __func__);
+
+       pltfm_data = devm_kzalloc(&pdev->dev, sizeof(struct ipu_pltfm_data),
+                               GFP_KERNEL);
+       if (!pltfm_data)
+               return -ENOMEM;
+
+       ret = of_property_read_u32(pdev->dev.of_node,
+                                       "bypass_reset", &bypass_reset);
+       if (ret < 0) {
+               dev_dbg(&pdev->dev, "can not get bypass_reset\n");
+               return ret;
+       }
+       pltfm_data->bypass_reset = (bool)bypass_reset;
+
+       pltfm_data->id = of_alias_get_id(pdev->dev.of_node, "ipu");
+       if (pltfm_data->id < 0) {
+               dev_dbg(&pdev->dev, "can not get alias id\n");
+               return pltfm_data->id;
+       }
+
+       if (of_id)
+               pdev->id_entry = of_id->data;
+       pltfm_data->devtype = pdev->id_entry->driver_data;
+       g_ipu_hw_rev = pltfm_data->devtype;
+
+       ipu = &ipu_array[pltfm_data->id];
+       memset(ipu, 0, sizeof(struct ipu_soc));
+       ipu->dev = &pdev->dev;
+       ipu->pdata = pltfm_data;
+       dev_dbg(ipu->dev, "IPU rev:%d\n", g_ipu_hw_rev);
+       spin_lock_init(&ipu->int_reg_spin_lock);
+       spin_lock_init(&ipu->rdy_reg_spin_lock);
+       mutex_init(&ipu->mutex_lock);
+
+       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) {
+               dev_err(&pdev->dev, "can't get device resources\n");
+               return -ENODEV;
+       }
+
+       if (!devm_request_mem_region(&pdev->dev, res->start,
+                                    resource_size(res), pdev->name))
+               return -EBUSY;
+
+       ret = devm_request_irq(&pdev->dev, ipu->irq_sync,
+                       ipu_sync_irq_handler, 0, pdev->name, ipu);
+       if (ret) {
+               dev_err(ipu->dev, "request SYNC interrupt failed\n");
+               return ret;
+       }
+       ret = devm_request_irq(&pdev->dev, ipu->irq_err,
+                       ipu_err_irq_handler, 0, pdev->name, ipu);
+       if (ret) {
+               dev_err(ipu->dev, "request ERR interrupt failed\n");
+               return ret;
+       }
+
+       ipu_base = res->start;
+       /* base fixup */
+       if (g_ipu_hw_rev == IPU_V3H)    /* IPUv3H */
+               ipu_base += IPUV3H_REG_BASE;
+       else if (g_ipu_hw_rev == IPU_V3M)       /* IPUv3M */
+               ipu_base += IPUV3M_REG_BASE;
+       else                    /* IPUv3D, v3E, v3EX */
+               ipu_base += IPUV3DEX_REG_BASE;
+
+       ipu->cm_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_CM_REG_BASE, PAGE_SIZE);
+       ipu->ic_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_IC_REG_BASE, PAGE_SIZE);
+       ipu->idmac_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_IDMAC_REG_BASE, PAGE_SIZE);
+       /* DP Registers are accessed thru the SRM */
+       ipu->dp_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_SRM_REG_BASE, PAGE_SIZE);
+       ipu->dc_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_DC_REG_BASE, PAGE_SIZE);
+       ipu->dmfc_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_DMFC_REG_BASE, PAGE_SIZE);
+       ipu->di_reg[0] = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_DI0_REG_BASE, PAGE_SIZE);
+       ipu->di_reg[1] = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_DI1_REG_BASE, PAGE_SIZE);
+       ipu->smfc_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_SMFC_REG_BASE, PAGE_SIZE);
+       ipu->csi_reg[0] = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_CSI0_REG_BASE, PAGE_SIZE);
+       ipu->csi_reg[1] = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_CSI1_REG_BASE, PAGE_SIZE);
+       ipu->cpmem_base = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_CPMEM_REG_BASE, SZ_128K);
+       ipu->tpmem_base = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_TPM_REG_BASE, SZ_64K);
+       ipu->dc_tmpl_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_DC_TMPL_REG_BASE, SZ_128K);
+       ipu->vdi_reg = devm_ioremap(&pdev->dev,
+                               ipu_base + IPU_VDI_REG_BASE, PAGE_SIZE);
+       ipu->disp_base[1] = devm_ioremap(&pdev->dev,
+                               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)
+               return -ENOMEM;
+
+       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);
+
+       ipu->ipu_clk = devm_clk_get(ipu->dev, "bus");
+       if (IS_ERR(ipu->ipu_clk)) {
+               dev_err(ipu->dev, "clk_get ipu failed");
+               return PTR_ERR(ipu->ipu_clk);
+       }
+
+       /* ipu_clk is always prepared */
+       ret = clk_prepare_enable(ipu->ipu_clk);
+       if (ret < 0) {
+               dev_err(ipu->dev, "ipu clk enable failed\n");
+               return ret;
+       }
+
+       ipu->online = true;
+       ret = ipu_clk_setup_enable(ipu, pltfm_data);
+       if (ret < 0) {
+               dev_err(ipu->dev, "ipu clk setup failed\n");
+               ipu->online = false;
+               return ret;
+       }
+
+       platform_set_drvdata(pdev, ipu);
+
+       if (!pltfm_data->bypass_reset) {
+               ret = device_reset(&pdev->dev);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to reset: %d\n", ret);
+                       return ret;
+               }
+
+               ipu_mem_reset(ipu);
+
+               ipu_disp_init(ipu);
+
+               /* Set MCU_T to divide MCU access window into 2 */
+               ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18),
+                            IPU_DISP_GEN);
+       }
+
+       /* Set sync refresh channels and CSI->mem channel as high priority */
+       ipu_idmac_write(ipu, 0x18800001L, IDMAC_CHA_PRI(0));
+
+       /* Enable error interrupts by default */
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+       if (!pltfm_data->bypass_reset)
+               clk_disable(ipu->ipu_clk);
+
+       register_ipu_device(ipu, ipu->pdata->id);
+
+       pm_runtime_enable(&pdev->dev);
+
+       return ret;
+}
+
+int ipu_remove(struct platform_device *pdev)
+{
+       struct ipu_soc *ipu = platform_get_drvdata(pdev);
+
+       unregister_ipu_device(ipu, ipu->pdata->id);
+
+       clk_put(ipu->ipu_clk);
+
+       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 >= IPU_V3DEX) {
+               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));
+       dev_dbg(ipu->dev, "IPU_VDIC_VDI_FSIZE = \t0x%08X\n",
+              ipu_vdi_read(ipu, VDI_FSIZE));
+       dev_dbg(ipu->dev, "IPU_VDIC_VDI_C = \t0x%08X\n",
+              ipu_vdi_read(ipu, VDI_C));
+       dev_dbg(ipu->dev, "IPU_IC_CONF = \t0x%08X\n",
+              ipu_ic_read(ipu, IC_CONF));
+}
+
+/*!
+ * 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;
+
+       dev_dbg(ipu->dev, "init channel = %d\n", IPU_CHAN_ID(channel));
+
+       ret = pm_runtime_get_sync(ipu->dev);
+       if (ret < 0) {
+               dev_err(ipu->dev, "ch = %d, pm_runtime_get failed:%d!\n",
+                               IPU_CHAN_ID(channel), ret);
+               dump_stack();
+               return ret;
+       }
+       /*
+        * Here, ret could be 1 if the device's runtime PM status was
+        * already 'active', so clear it to be 0.
+        */
+       ret = 0;
+
+       _ipu_get(ipu);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       /* Re-enable error interrupts every time a channel is initialized */
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(5));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(6));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(9));
+       ipu_cm_write(ipu, 0xFFFFFFFF, IPU_INT_CTRL(10));
+
+       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_vc,
+                               params->csi_mem.csi);
+                       _ipu_csi_set_mipi_di(ipu, params->csi_mem.mipi_vc,
+                               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) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_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;
+
+               if (params->csi_prp_enc_mem.mipi_en) {
+                       ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+                               params->csi_prp_enc_mem.csi));
+                       _ipu_csi_set_mipi_di(ipu,
+                               params->csi_prp_enc_mem.mipi_vc,
+                               params->csi_prp_enc_mem.mipi_id,
+                               params->csi_prp_enc_mem.csi);
+               } else
+                       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) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_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;
+
+               if (params->csi_prp_vf_mem.mipi_en) {
+                       ipu_conf |= (1 << (IPU_CONF_CSI0_DATA_SOURCE_OFFSET +
+                               params->csi_prp_vf_mem.csi));
+                       _ipu_csi_set_mipi_di(ipu,
+                               params->csi_prp_vf_mem.mipi_vc,
+                               params->csi_prp_vf_mem.mipi_id,
+                               params->csi_prp_vf_mem.csi);
+               } else
+                       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 == MEM_VDI_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:
+       case MEM_VDI_PRP_VF_MEM_N:
+       case MEM_VDI_MEM_P:
+       case MEM_VDI_MEM_N:
+               _ipu_vdi_init(ipu, channel, params);
+               break;
+       case MEM_VDI_MEM:
+               if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+                    (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+               ipu->using_ic_dirct_ch = MEM_VDI_MEM;
+               ipu->ic_use_count++;
+               ipu->vdi_use_count++;
+               _ipu_ic_init_prpvf(ipu, params, false);
+               _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;
+       }
+
+       ipu->channel_init_mask |= 1L << IPU_CHAN_ID(channel);
+
+       ipu_cm_write(ipu, ipu_conf, IPU_CONF);
+
+err:
+       mutex_unlock(&ipu->mutex_lock);
+       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;
+       uint32_t dc_chan = 0;
+       int ret;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       if ((ipu->channel_init_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+               dev_dbg(ipu->dev, "Channel already uninitialized %d\n",
+                       IPU_CHAN_ID(channel));
+               mutex_unlock(&ipu->mutex_lock);
+               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));
+               mutex_unlock(&ipu->mutex_lock);
+               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_MEM:
+               ipu->ic_use_count--;
+               ipu->vdi_use_count--;
+               if (ipu->using_ic_dirct_ch == MEM_VDI_MEM)
+                       ipu->using_ic_dirct_ch = 0;
+               _ipu_ic_uninit_prpvf(ipu);
+               _ipu_vdi_uninit(ipu);
+               break;
+       case MEM_VDI_PRP_VF_MEM_P:
+       case MEM_VDI_PRP_VF_MEM_N:
+       case MEM_VDI_MEM_P:
+       case MEM_VDI_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:
+               dc_chan = 1;
+               _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:
+               dc_chan = 5;
+               _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:
+               dc_chan = 8;
+               _ipu_dc_uninit(ipu, 8);
+               ipu->di_use_count[ipu->dc_di_assignment[8]]--;
+               ipu->dc_use_count--;
+               break;
+       case DIRECT_ASYNC1:
+               dc_chan = 9;
+               _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));
+
+       /*
+        * Disable pixel clk and its parent clock(if the parent clock
+        * usecount is 1) after clearing DC/DP/DI bits in IPU_CONF
+        * register to prevent LVDS display channel starvation.
+        */
+       if (_ipu_is_primary_disp_chan(in_dma))
+               clk_disable_unprepare(ipu->pixel_clk[ipu->dc_di_assignment[dc_chan]]);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _ipu_put(ipu);
+
+       ret = pm_runtime_put_sync_suspend(ipu->dev);
+       if (ret < 0) {
+               dev_err(ipu->dev, "ch = %d, pm_runtime_put failed:%d!\n",
+                               IPU_CHAN_ID(channel), ret);
+               dump_stack();
+       }
+
+       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;
+
+       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;
+       }
+
+       if (_ipu_is_vdi_out_chan(dma_chan) &&
+               ((width < 16) || (height < 16) || (width % 2) || (height % 4))) {
+               dev_err(ipu->dev, "vdi width/height limited err\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;
+       }
+
+       mutex_lock(&ipu->mutex_lock);
+
+       /* 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) || _ipu_is_vdi_out_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) ||
+               _ipu_is_vdi_out_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);
+               /*
+                * This is different from IPUv3 spec, but it is confirmed
+                * in IPUforum that SMFC burst size should be NPB[6:3]
+                * when IDMAC works in 16-bit generic data mode.
+                */
+               if (pixel_fmt == IPU_PIX_FMT_GENERIC)
+                       /* 8 bits per pixel */
+                       burst_size = burst_size >> 4;
+               else if (pixel_fmt == IPU_PIX_FMT_GENERIC_16)
+                       /* 16 bits per pixel */
+                       burst_size = burst_size >> 3;
+               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 (ipu->pdata->devtype == IPU_V3H) {
+                       _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);
+       } else {
+               if (ipu->pdata->devtype == IPU_V3H)
+                       _ipu_ch_param_set_axi_id(ipu, dma_chan, 1);
+       }
+
+       _ipu_ch_param_dump(ipu, dma_chan);
+
+       if (phyaddr_2 && g_ipu_hw_rev >= IPU_V3DEX) {
+               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));
+
+       }
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       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;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, 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;
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(ipu_update_channel_buffer);
+
+/*!
+ * This function is called to update the band mode setting 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       band_height     Input parameter for band lines:
+ *                             shoule be log2(4/8/16/32/64/128/256).
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
+                                ipu_buffer_t type, uint32_t band_height)
+{
+       uint32_t reg;
+       int ret = 0;
+       uint32_t dma_chan = channel_2_dma(channel, type);
+
+       if ((2 > band_height) || (8 < band_height))
+               return -EINVAL;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       reg = ipu_idmac_read(ipu, IDMAC_BAND_EN(dma_chan));
+       reg |= 1 << (dma_chan % 32);
+       ipu_idmac_write(ipu, reg, IDMAC_BAND_EN(dma_chan));
+
+       _ipu_ch_param_set_bandmode(ipu, dma_chan, band_height);
+       dev_dbg(ipu->dev, "dma_chan:%d, band_height:%d.\n\n",
+                               dma_chan, 1 << band_height);
+       mutex_unlock(&ipu->mutex_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL(ipu_set_channel_bandmode);
+
+/*!
+ * 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;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, 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);
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, 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;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+       /* Mark buffer to be ready. */
+       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));
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, 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;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+       /* Mark buffers to be ready. */
+       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));
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, 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;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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;
+       case MEM_VDOA_MEM:
+               fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+               if (MEM_VDI_MEM == dest_ch)
+                       fs_proc_flow3 |= FS_VDOA_DEST_SEL_VDI;
+               else if (MEM_PP_MEM == dest_ch)
+                       fs_proc_flow3 |= FS_VDOA_DEST_SEL_IC;
+               else {
+                       retval = -EINVAL;
+                       goto err;
+               }
+               break;
+       default:
+               retval = -EINVAL;
+               goto err;
+       }
+
+       switch (dest_ch) {
+       case MEM_PP_MEM:
+               fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
+               if (MEM_VDOA_MEM == src_ch)
+                       fs_proc_flow1 |= FS_PP_SRC_SEL_VDOA;
+               else
+                       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;
+       case MEM_VDI_MEM:
+               fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+               if (MEM_VDOA_MEM == src_ch)
+                       fs_proc_flow1 |= FS_VDI_SRC_SEL_VDOA;
+               else {
+                       retval = -EINVAL;
+                       goto err;
+               }
+               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:
+       mutex_unlock(&ipu->mutex_lock);
+       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;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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;
+       case MEM_VDOA_MEM:
+               fs_proc_flow3 &= ~FS_VDOA_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;
+       case MEM_VDI_MEM:
+               fs_proc_flow1 &= ~FS_VDI_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:
+       mutex_unlock(&ipu->mutex_lock);
+       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;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       if (ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) {
+               dev_err(ipu->dev, "Warning: channel already enabled %d\n",
+                       IPU_CHAN_ID(channel));
+               mutex_unlock(&ipu->mutex_lock);
+               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_is_vdi_out_chan(out_dma))
+               _ipu_ic_enable_task(ipu, channel);
+
+       ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       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;
+       unsigned long lock_flags;
+
+       if (dma_chan == IDMA_CHAN_INVALID)
+               return -EINVAL;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, 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));
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+       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;
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+       _ipu_clear_buffer_ready(ipu, channel, type, bufNum);
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, 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;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       if ((ipu->channel_enable_mask & (1L << IPU_CHAN_ID(channel))) == 0) {
+               dev_dbg(ipu->dev, "Channel already disabled %d\n",
+                       IPU_CHAN_ID(channel));
+               mutex_unlock(&ipu->mutex_lock);
+               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))) {
+               mutex_unlock(&ipu->mutex_lock);
+               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);
+       }
+
+       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) && (ipu_is_channel_busy(ipu, MEM_BG_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 && !_ipu_is_smfc_chan(out_dma) &&
+                  channel != CSI_PRP_VF_MEM && channel != CSI_PRP_ENC_MEM) {
+               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;
+                       int timeout = 50000;
+
+                       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_dbg(ipu->dev, "warning: no channel busy, break\n");
+                               break;
+                       }
+
+                       ipu_cm_write(ipu, IPUIRQ_2_MASK(irq),
+                                       IPUIRQ_2_STATREG(irq));
+
+                       dev_dbg(ipu->dev, "warning: channel %d busy, need wait\n", irq);
+
+                       while (((ipu_cm_read(ipu, IPUIRQ_2_STATREG(irq))
+                               & IPUIRQ_2_MASK(irq)) == 0) &&
+                               (idma_is_set(ipu, IDMAC_CHA_BUSY, irq))) {
+                               udelay(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;
+                               }
+                       }
+                       dev_dbg(ipu->dev, "wait_time:%d\n", 50000 - timeout);
+
+               }
+       }
+
+       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_is_vdi_out_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));
+       }
+
+       if (channel == MEM_FG_SYNC)
+               _ipu_disp_set_window_pos(ipu, channel, fg_pos_x, fg_pos_y);
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+       /* 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);
+       }
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+       ipu->channel_enable_mask &= ~(1L << IPU_CHAN_ID(channel));
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       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;
+
+       if (csi > 1) {
+               dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+               return -EINVAL;
+       }
+
+       _ipu_get(ipu);
+       mutex_lock(&ipu->mutex_lock);
+       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);
+       }
+       mutex_unlock(&ipu->mutex_lock);
+       _ipu_put(ipu);
+       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;
+
+       if (csi > 1) {
+               dev_err(ipu->dev, "Wrong csi num_%d\n", csi);
+               return -EINVAL;
+       }
+       _ipu_get(ipu);
+       mutex_lock(&ipu->mutex_lock);
+       ipu->csi_use_count[csi]--;
+       if (ipu->csi_use_count[csi] == 0) {
+               _ipu_csi_wait4eof(ipu, ipu->csi_channel[csi]);
+               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);
+       }
+       mutex_unlock(&ipu->mutex_lock);
+       _ipu_put(ipu);
+       return 0;
+}
+EXPORT_SYMBOL(ipu_disable_csi);
+
+static irqreturn_t ipu_sync_irq_handler(int irq, void *desc)
+{
+       struct ipu_soc *ipu = desc;
+       int i;
+       uint32_t line, bit, int_stat, int_ctrl;
+       irqreturn_t result = IRQ_NONE;
+       const int int_reg[] = { 1, 2, 3, 4, 11, 12, 13, 14, 15, 0 };
+
+       spin_lock(&ipu->int_reg_spin_lock);
+
+       for (i = 0; int_reg[i] != 0; i++) {
+               int_stat = ipu_cm_read(ipu, IPU_INT_STAT(int_reg[i]));
+               int_ctrl = ipu_cm_read(ipu, IPU_INT_CTRL(int_reg[i]));
+               int_stat &= int_ctrl;
+               ipu_cm_write(ipu, int_stat, IPU_INT_STAT(int_reg[i]));
+               while ((line = ffs(int_stat)) != 0) {
+                       bit = --line;
+                       int_stat &= ~(1UL << line);
+                       line += (int_reg[i] - 1) * 32;
+                       result |=
+                           ipu->irq_list[line].handler(line,
+                                                      ipu->irq_list[line].
+                                                      dev_id);
+                       if (ipu->irq_list[line].flags & IPU_IRQF_ONESHOT) {
+                               int_ctrl &= ~(1UL << bit);
+                               ipu_cm_write(ipu, int_ctrl,
+                                               IPU_INT_CTRL(int_reg[i]));
+                       }
+               }
+       }
+
+       spin_unlock(&ipu->int_reg_spin_lock);
+
+       return result;
+}
+
+static irqreturn_t ipu_err_irq_handler(int irq, void *desc)
+{
+       struct ipu_soc *ipu = desc;
+       int i;
+       uint32_t int_stat;
+       const int err_reg[] = { 5, 6, 9, 10, 0 };
+
+       spin_lock(&ipu->int_reg_spin_lock);
+
+       for (i = 0; err_reg[i] != 0; i++) {
+               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_warn(ipu->dev,
+                               "IPU Warning - 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]));
+               }
+       }
+
+       spin_unlock(&ipu->int_reg_spin_lock);
+
+       return IRQ_HANDLED;
+}
+
+/*!
+ * 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.
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int ipu_enable_irq(struct ipu_soc *ipu, uint32_t irq)
+{
+       uint32_t reg;
+       unsigned long lock_flags;
+       int ret = 0;
+
+       _ipu_get(ipu);
+
+       spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+       /*
+        * Check sync interrupt handler only, since we do nothing for
+        * error interrupts but than print out register values in the
+        * error interrupt source handler.
+        */
+       if (_ipu_is_sync_irq(irq) && (ipu->irq_list[irq].handler == NULL)) {
+               dev_err(ipu->dev, "handler hasn't been registered on sync "
+                                 "irq %d\n", irq);
+               ret = -EACCES;
+               goto out;
+       }
+
+       reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+       reg |= IPUIRQ_2_MASK(irq);
+       ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+       spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+       _ipu_put(ipu);
+
+       return ret;
+}
+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->int_reg_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->int_reg_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)
+{
+       unsigned long lock_flags;
+
+       _ipu_get(ipu);
+
+       spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+       ipu_cm_write(ipu, IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq));
+
+       spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+       _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;
+       unsigned long lock_flags;
+
+       _ipu_get(ipu);
+
+       spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+       reg = ipu_cm_read(ipu, IPUIRQ_2_STATREG(irq));
+       spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+       _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)
+{
+       uint32_t reg;
+       unsigned long lock_flags;
+       int ret = 0;
+
+       BUG_ON(irq >= IPU_IRQ_COUNT);
+
+       _ipu_get(ipu);
+
+       spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+       if (ipu->irq_list[irq].handler != NULL) {
+               dev_err(ipu->dev,
+                       "handler already installed on irq %d\n", irq);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /*
+        * Check sync interrupt handler only, since we do nothing for
+        * error interrupts but than print out register values in the
+        * error interrupt source handler.
+        */
+       if (_ipu_is_sync_irq(irq) && (handler == NULL)) {
+               dev_err(ipu->dev, "handler is NULL for sync irq %d\n", irq);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       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;
+
+       /* clear irq stat for previous use */
+       ipu_cm_write(ipu, IPUIRQ_2_MASK(irq), IPUIRQ_2_STATREG(irq));
+       /* enable the interrupt */
+       reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+       reg |= IPUIRQ_2_MASK(irq);
+       ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+out:
+       spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+       _ipu_put(ipu);
+
+       return ret;
+}
+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)
+{
+       uint32_t reg;
+       unsigned long lock_flags;
+
+       _ipu_get(ipu);
+
+       spin_lock_irqsave(&ipu->int_reg_spin_lock, lock_flags);
+
+       /* disable the interrupt */
+       reg = ipu_cm_read(ipu, IPUIRQ_2_CTRLREG(irq));
+       reg &= ~IPUIRQ_2_MASK(irq);
+       ipu_cm_write(ipu, reg, IPUIRQ_2_CTRLREG(irq));
+       if (ipu->irq_list[irq].dev_id == dev_id)
+               memset(&ipu->irq_list[irq], 0, sizeof(ipu->irq_list[irq]));
+
+       spin_unlock_irqrestore(&ipu->int_reg_spin_lock, lock_flags);
+
+       _ipu_put(ipu);
+}
+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;
+}
+
+/*!
+ * This function check for  a logical channel status
+ *
+ * @param      ipu             ipu handler
+ * @param      channel         Input parameter for the logical channel ID.
+ *
+ * @return      This function returns 0 on idle and 1 on busy.
+ *
+ */
+uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
+{
+       uint32_t dma_status;
+
+       _ipu_get(ipu);
+       mutex_lock(&ipu->mutex_lock);
+       dma_status = ipu_is_channel_busy(ipu, channel);
+       mutex_unlock(&ipu->mutex_lock);
+       _ipu_put(ipu);
+
+       dev_dbg(ipu->dev, "%s, dma_status:%d.\n", __func__, dma_status);
+
+       return dma_status;
+}
+EXPORT_SYMBOL(ipu_channel_status);
+
+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);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       /* 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_dp_dc_disable(ipu, from_ch, true);
+
+       /* 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));
+
+       spin_lock_irqsave(&ipu->rdy_reg_spin_lock, lock_flags);
+       _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);
+       spin_unlock_irqrestore(&ipu->rdy_reg_spin_lock, lock_flags);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       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:
+       case IPU_PIX_FMT_YUV444P:
+               return 1;
+               break;
+       case IPU_PIX_FMT_GENERIC_16:    /* generic data */
+       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:
+       case IPU_PIX_FMT_YUV444:
+               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;
+}
+
+#ifdef CONFIG_PM
+static int ipu_suspend(struct device *dev)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(dev);
+
+       /* All IDMAC channel and IPU clock should be disabled.*/
+       if (ipu->pdata->pg)
+               ipu->pdata->pg(1);
+
+       dev_dbg(dev, "ipu suspend.\n");
+       return 0;
+}
+
+static int ipu_resume(struct device *dev)
+{
+       struct ipu_soc *ipu = dev_get_drvdata(dev);
+
+       if (ipu->pdata->pg) {
+               ipu->pdata->pg(0);
+
+               _ipu_get(ipu);
+               _ipu_dmfc_init(ipu, dmfc_type_setup, 1);
+               /* Set sync refresh channels as high priority */
+               ipu_idmac_write(ipu, 0x18800001L, IDMAC_CHA_PRI(0));
+               _ipu_put(ipu);
+       }
+       dev_dbg(dev, "ipu resume.\n");
+       return 0;
+}
+
+int ipu_runtime_suspend(struct device *dev)
+{
+#if 0
+       release_bus_freq(BUS_FREQ_HIGH);
+       dev_dbg(dev, "ipu busfreq high release.\n");
+#endif
+       return 0;
+}
+
+int ipu_runtime_resume(struct device *dev)
+{
+#if 0
+       request_bus_freq(BUS_FREQ_HIGH);
+       dev_dbg(dev, "ipu busfreq high requst.\n");
+#endif
+       return 0;
+}
+
+static const struct dev_pm_ops ipu_pm_ops = {
+       SET_RUNTIME_PM_OPS(ipu_runtime_suspend, ipu_runtime_resume, NULL)
+       SET_SYSTEM_SLEEP_PM_OPS(ipu_suspend, ipu_resume)
+};
+#endif
+
+/*!
+ * This structure contains pointers to the power management callback functions.
+ */
+static struct platform_driver mxcipu_driver = {
+       .driver = {
+                       .name           = "imx-ipuv3",
+                       .of_match_table = imx_ipuv3_dt_ids,
+               #ifdef CONFIG_PM
+                       .pm     = &ipu_pm_ops,
+               #endif
+       },
+       .probe          = ipu_probe,
+       .id_table       = imx_ipu_type,
+       .remove         = ipu_remove,
+};
+
+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 (file)
index 0000000..be36e37
--- /dev/null
@@ -0,0 +1,3642 @@
+/*
+ * Copyright 2005-2013 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/clk.h>
+#include <linux/cpumask.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/sched/rt.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/vmalloc.h>
+#include <linux/wait.h>
+
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+#include "vdoa.h"
+
+#define CHECK_RETCODE(cont, str, err, label, ret)                      \
+do {                                                                   \
+       if (cont) {                                                     \
+               dev_err(t->dev, "ERR:[0x%p]-no:0x%x "#str" ret:%d,"     \
+                               "line:%d\n", t, t->task_no, ret, __LINE__);\
+               if (ret != -EACCES) {                                   \
+                       t->state = err;                                 \
+                       goto label;                                     \
+               }                                                       \
+       }                                                               \
+} while (0)
+
+#define CHECK_RETCODE_CONT(cont, str, err, ret)                                \
+do {                                                                   \
+       if (cont) {                                                     \
+               dev_err(t->dev, "ERR:[0x%p]-no:0x%x"#str" ret:%d,"      \
+                               "line:%d\n", t, t->task_no, ret, __LINE__);\
+               if (ret != -EACCES) {                                   \
+                       if (t->state == STATE_OK)                       \
+                               t->state = err;                         \
+               }                                                       \
+       }                                                               \
+} while (0)
+
+#undef DBG_IPU_PERF
+#ifdef DBG_IPU_PERF
+#define CHECK_PERF(ts)                                                 \
+do {                                                                   \
+       getnstimeofday(ts);                                             \
+} while (0)
+
+#define DECLARE_PERF_VAR                                               \
+       struct timespec ts_queue;                                       \
+       struct timespec ts_dotask;                                      \
+       struct timespec ts_waitirq;                                     \
+       struct timespec ts_sche;                                        \
+       struct timespec ts_rel;                                         \
+       struct timespec ts_frame
+
+#define PRINT_TASK_STATISTICS                                          \
+do {                                                                   \
+       ts_queue = timespec_sub(tsk->ts_dotask, tsk->ts_queue);         \
+       ts_dotask = timespec_sub(tsk->ts_waitirq, tsk->ts_dotask);      \
+       ts_waitirq = timespec_sub(tsk->ts_inirq, tsk->ts_waitirq);      \
+       ts_sche = timespec_sub(tsk->ts_wakeup, tsk->ts_inirq);          \
+       ts_rel = timespec_sub(tsk->ts_rel, tsk->ts_wakeup);             \
+       ts_frame = timespec_sub(tsk->ts_rel, tsk->ts_queue);            \
+       dev_dbg(tsk->dev, "[0x%p] no-0x%x, ts_q:%ldus, ts_do:%ldus,"    \
+               "ts_waitirq:%ldus,ts_sche:%ldus, ts_rel:%ldus,"         \
+               "ts_frame: %ldus\n", tsk, tsk->task_no,                 \
+       ts_queue.tv_nsec / NSEC_PER_USEC + ts_queue.tv_sec * USEC_PER_SEC,\
+       ts_dotask.tv_nsec / NSEC_PER_USEC + ts_dotask.tv_sec * USEC_PER_SEC,\
+       ts_waitirq.tv_nsec / NSEC_PER_USEC + ts_waitirq.tv_sec * USEC_PER_SEC,\
+       ts_sche.tv_nsec / NSEC_PER_USEC + ts_sche.tv_sec * USEC_PER_SEC,\
+       ts_rel.tv_nsec / NSEC_PER_USEC + ts_rel.tv_sec * USEC_PER_SEC,\
+       ts_frame.tv_nsec / NSEC_PER_USEC + ts_frame.tv_sec * USEC_PER_SEC); \
+       if ((ts_frame.tv_nsec/NSEC_PER_USEC + ts_frame.tv_sec*USEC_PER_SEC) > \
+               80000)  \
+               dev_dbg(tsk->dev, "ts_frame larger than 80ms [0x%p] no-0x%x.\n"\
+                               , tsk, tsk->task_no);   \
+} while (0)
+#else
+#define CHECK_PERF(ts)
+#define DECLARE_PERF_VAR
+#define PRINT_TASK_STATISTICS
+#endif
+
+#define        IPU_PP_CH_VF    (IPU_TASK_ID_VF - 1)
+#define        IPU_PP_CH_PP    (IPU_TASK_ID_PP - 1)
+#define MAX_PP_CH      (IPU_TASK_ID_MAX - 1)
+#define VDOA_DEF_TIMEOUT_MS    (HZ/2)
+
+/* Strucutures and variables for exporting MXC IPU as device*/
+typedef enum {
+       STATE_OK = 0,
+       STATE_QUEUE,
+       STATE_IN_PROGRESS,
+       STATE_ERR,
+       STATE_TIMEOUT,
+       STATE_RES_TIMEOUT,
+       STATE_NO_IPU,
+       STATE_NO_IRQ,
+       STATE_IPU_BUSY,
+       STATE_IRQ_FAIL,
+       STATE_IRQ_TIMEOUT,
+       STATE_ENABLE_CHAN_FAIL,
+       STATE_DISABLE_CHAN_FAIL,
+       STATE_SEL_BUF_FAIL,
+       STATE_INIT_CHAN_FAIL,
+       STATE_LINK_CHAN_FAIL,
+       STATE_UNLINK_CHAN_FAIL,
+       STATE_INIT_CHAN_BUF_FAIL,
+       STATE_INIT_CHAN_BAND_FAIL,
+       STATE_SYS_NO_MEM,
+       STATE_VDOA_IRQ_TIMEOUT,
+       STATE_VDOA_IRQ_FAIL,
+       STATE_VDOA_TASK_FAIL,
+} ipu_state_t;
+
+enum {
+       INPUT_CHAN_VDI_P = 1,
+       INPUT_CHAN,
+       INPUT_CHAN_VDI_N,
+};
+
+struct ipu_state_msg {
+       int state;
+       char *msg;
+} state_msg[] = {
+       {STATE_OK, "ok"},
+       {STATE_QUEUE, "split queue"},
+       {STATE_IN_PROGRESS, "split in progress"},
+       {STATE_ERR, "error"},
+       {STATE_TIMEOUT, "split task timeout"},
+       {STATE_RES_TIMEOUT, "wait resource timeout"},
+       {STATE_NO_IPU, "no ipu found"},
+       {STATE_NO_IRQ, "no irq found for task"},
+       {STATE_IPU_BUSY, "ipu busy"},
+       {STATE_IRQ_FAIL, "request irq failed"},
+       {STATE_IRQ_TIMEOUT, "wait for irq timeout"},
+       {STATE_ENABLE_CHAN_FAIL, "ipu enable channel fail"},
+       {STATE_DISABLE_CHAN_FAIL, "ipu disable channel fail"},
+       {STATE_SEL_BUF_FAIL, "ipu select buf fail"},
+       {STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
+       {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
+       {STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
+       {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+       {STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
+       {STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
+       {STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
+       {STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
+       {STATE_VDOA_TASK_FAIL, "vdoa task 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;
+       u32 rl_split_line;
+       u32 ud_split_line;
+};
+
+struct task_set {
+#define        NULL_MODE       0x0
+#define        IC_MODE         0x1
+#define        ROT_MODE        0x2
+#define        VDI_MODE        0x4
+#define IPU_PREPROCESS_MODE_MASK       (IC_MODE | ROT_MODE | VDI_MODE)
+/* VDOA_MODE means this task use vdoa, and VDOA has two modes:
+ * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
+ * to memory. BAND mode needs hareware sync with IPU, it is used default
+ * if connected to VDIC.
+ */
+#define        VDOA_MODE       0x8
+#define        VDOA_BAND_MODE  0x10
+       u8      mode;
+#define IC_VF  0x1
+#define IC_PP  0x2
+#define ROT_VF 0x4
+#define ROT_PP 0x8
+#define VDI_VF 0x10
+#define        VDOA_ONLY       0x20
+       u8      task;
+#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
+#define SPLIT_MASK     0xF
+       u8      split_mode;
+       u8      band_lines;
+       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;
+
+       struct stripe_setting sp_setting;
+};
+
+struct ipu_split_task {
+       struct ipu_task task;
+       struct ipu_task_entry *parent_task;
+       struct ipu_task_entry *child_task;
+       u32 task_no;
+};
+
+struct ipu_task_entry {
+       struct ipu_input input;
+       struct ipu_output output;
+
+       bool overlay_en;
+       struct ipu_overlay overlay;
+#define DEF_TIMEOUT_MS 1000
+#define DEF_DELAY_MS 20
+       int     timeout;
+       int     irq;
+
+       u8      task_id;
+       u8      ipu_id;
+       u8      task_in_list;
+       u8      split_done;
+       struct mutex split_lock;
+       wait_queue_head_t split_waitq;
+
+       struct list_head node;
+       struct list_head split_list;
+       struct ipu_soc *ipu;
+       struct device *dev;
+       struct task_set set;
+       wait_queue_head_t task_waitq;
+       struct completion irq_comp;
+       struct kref refcount;
+       ipu_state_t state;
+       u32 task_no;
+       atomic_t done;
+       atomic_t res_free;
+       atomic_t res_get;
+
+       struct ipu_task_entry *parent;
+       char *vditmpbuf[2];
+       u32 old_save_lines;
+       u32 old_size;
+       bool buf1filled;
+       bool buf0filled;
+
+       vdoa_handle_t vdoa_handle;
+       struct vdoa_output_mem {
+               void *vaddr;
+               dma_addr_t paddr;
+               int size;
+       } vdoa_dma;
+
+#ifdef DBG_IPU_PERF
+       struct timespec ts_queue;
+       struct timespec ts_dotask;
+       struct timespec ts_waitirq;
+       struct timespec ts_inirq;
+       struct timespec ts_wakeup;
+       struct timespec ts_rel;
+#endif
+};
+
+struct ipu_channel_tabel {
+       struct mutex    lock;
+       u8              used[MXC_IPU_MAX_NUM][MAX_PP_CH];
+       u8              vdoa_used;
+};
+
+struct ipu_thread_data {
+       struct ipu_soc *ipu;
+       u32     id;
+       u32     is_vdoa;
+};
+
+struct ipu_alloc_list {
+       struct list_head list;
+       dma_addr_t phy_addr;
+       void *cpu_addr;
+       u32 size;
+       void *file_index;
+};
+
+static LIST_HEAD(ipu_alloc_list);
+static DEFINE_MUTEX(ipu_alloc_lock);
+static struct ipu_channel_tabel        ipu_ch_tbl;
+static LIST_HEAD(ipu_task_list);
+static DEFINE_SPINLOCK(ipu_task_list_lock);
+static DECLARE_WAIT_QUEUE_HEAD(thread_waitq);
+static DECLARE_WAIT_QUEUE_HEAD(res_waitq);
+static atomic_t req_cnt;
+static atomic_t file_index = ATOMIC_INIT(1);
+static int major;
+static int max_ipu_no;
+static int thread_id;
+static atomic_t frame_no;
+static struct class *ipu_class;
+static struct device *ipu_dev;
+static int debug;
+module_param(debug, int, 0600);
+#ifdef DBG_IPU_PERF
+static struct timespec ts_frame_max;
+static u32 ts_frame_avg;
+static atomic_t frame_cnt;
+#endif
+
+static bool deinterlace_3_field(struct ipu_task_entry *t)
+{
+       return ((t->set.mode & VDI_MODE) &&
+               (t->input.deinterlace.motion != HIGH_MOTION));
+}
+
+static u32 tiled_filed_size(struct ipu_task_entry *t)
+{
+       u32 field_size;
+
+       /* note: page_align is required by VPU hw ouput buffer */
+       field_size = TILED_NV12_FRAME_SIZE(t->input.width, t->input.height/2);
+       return field_size;
+}
+
+static bool only_ic(u8 mode)
+{
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
+       return ((mode == IC_MODE) || (mode == VDI_MODE));
+}
+
+static bool only_rot(u8 mode)
+{
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
+       return (mode == ROT_MODE);
+}
+
+static bool ic_and_rot(u8 mode)
+{
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
+       return ((mode == (IC_MODE | ROT_MODE)) ||
+                (mode == (VDI_MODE | ROT_MODE)));
+}
+
+static bool need_split(struct ipu_task_entry *t)
+{
+       return ((t->set.split_mode != NO_SPLIT) || (t->task_no & SPLIT_MASK));
+}
+
+unsigned int fmt_to_bpp(unsigned int 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:
+       case IPU_PIX_FMT_YUV444P:
+               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;
+}
+EXPORT_SYMBOL_GPL(fmt_to_bpp);
+
+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_YUV444P:
+       case IPU_PIX_FMT_NV12:
+       case IPU_PIX_FMT_TILED_NV12:
+       case IPU_PIX_FMT_TILED_NV12F:
+               return YUV_CS;
+               break;
+       default:
+               return NULL_CS;
+       }
+}
+EXPORT_SYMBOL_GPL(colorspaceofpixel);
+
+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;
+}
+EXPORT_SYMBOL_GPL(need_csc);
+
+static int soc_max_in_width(u32 is_vdoa)
+{
+       return is_vdoa ? 8192 : 4096;
+}
+
+static int soc_max_vdi_in_width(void)
+{
+       return IPU_MAX_VDI_IN_WIDTH;
+}
+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 void dump_task_info(struct ipu_task_entry *t)
+{
+       if (!debug)
+               return;
+       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);
+       dev_dbg(t->dev, "[0x%p]\tTask_no = 0x%x\n\n\n", (void *)t, t->task_no);
+}
+
+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;
+       case IPU_CHECK_ERR_SPLIT_WITH_ROT:
+               dev_err(dev, "not support split mode with rotation\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, int fmt)
+{
+       if ((width == 0) || (height == 0)) {
+               pr_err("Invalid param: width=%d, height=%d\n", width, height);
+               return -EINVAL;
+       }
+
+       if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
+               (IPU_PIX_FMT_TILED_NV12F == fmt)) {
+               if (crop->w || crop->h) {
+                       if (((crop->w + crop->pos.x) > width)
+                       || ((crop->h + crop->pos.y) > height)
+                       || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       ) {
+                               pr_err("set_crop error MB align.\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       crop->pos.x = 0;
+                       crop->pos.y = 0;
+                       crop->w = width;
+                       crop->h = height;
+                       if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
+                               pr_err("set_crop error w/h MB align.\n");
+                               return -EINVAL;
+                       }
+               }
+       } else {
+               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;
+       }
+
+       if ((crop->w == 0) || (crop->h == 0)) {
+               pr_err("Invalid crop param: crop.w=%d, crop.h=%d\n",
+                       crop->w, crop->h);
+               return -EINVAL;
+       }
+
+       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;
+               /* In case height is odd, round up to even */
+               *voff = *uoff + (width/2) * ((height+1)/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;
+               /* In case height is odd, round up to even */
+               *uoff = *voff + (width/2) * ((height+1)/2);
+               break;
+       case IPU_PIX_FMT_YVU422P:
+               *off = pos_y * width + pos_x;
+               *voff = (width * (height - pos_y) - pos_x)
+                       + (width/2) * pos_y + pos_x/2;
+               *uoff = *voff + (width/2) * height;
+               break;
+       case IPU_PIX_FMT_YUV422P:
+               *off = pos_y * width + pos_x;
+               *uoff = (width * (height - pos_y) - pos_x)
+                       + (width/2) * pos_y + pos_x/2;
+               *voff = *uoff + (width/2) * height;
+               break;
+       case IPU_PIX_FMT_YUV444P:
+               *off = pos_y * width + pos_x;
+               *uoff = width * height;
+               *voff = 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;
+       case IPU_PIX_FMT_TILED_NV12:
+               /*
+                * tiled format, progressive:
+                * assuming that line is aligned with MB height (aligned to 16)
+                * offset = line * stride + (pixel / MB_width) * pixels_in_MB
+                * = line * stride + (pixel / 16) * 256
+                * = line * stride + pixel * 16
+                */
+               *off = pos_y * width + (pos_x << 4);
+               *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1) - *off;
+               break;
+       case IPU_PIX_FMT_TILED_NV12F:
+               /*
+                * tiled format, interlaced:
+                * same as above, only number of pixels in MB is 128,
+                * instead of 256
+                */
+               *off = (pos_y >> 1) * width + (pos_x << 3);
+               *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1) - *off;
+               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, bool vdi_split)
+{
+       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;
+       u32 max_width;
+       int ret;
+
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+               return IPU_CHECK_ERR_SPLIT_WITH_ROT;
+
+       iw = t->input.crop.w;
+       ih = t->input.crop.h;
+
+       ow = t->output.crop.w;
+       oh = t->output.crop.h;
+
+       memset(&left_stripe, 0, sizeof(left_stripe));
+       memset(&right_stripe, 0, sizeof(right_stripe));
+       memset(&up_stripe, 0, sizeof(up_stripe));
+       memset(&down_stripe, 0, sizeof(down_stripe));
+
+       if (t->set.split_mode & RL_SPLIT) {
+               /*
+                * We do want equal strips: initialize stripes in case
+                * calc_stripes returns before actually doing the calculation
+                */
+               left_stripe.input_width = iw / 2;
+               left_stripe.output_width = ow / 2;
+               right_stripe.input_column = iw / 2;
+               right_stripe.output_column = ow / 2;
+
+               if (vdi_split)
+                       max_width = soc_max_vdi_in_width();
+               else
+                       max_width = soc_max_out_width();
+               ret = ipu_calc_stripes_sizes(iw,
+                               ow,
+                               max_width,
+                               (((unsigned long long)1) << 32), /* 32bit for fractional*/
+                               1, /* equal stripes */
+                               t->input.format,
+                               t->output.format,
+                               &left_stripe,
+                               &right_stripe);
+               if (ret)
+                       dev_dbg(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+                                t->task_no, ret);
+               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) {
+               /*
+                * We do want equal strips: initialize stripes in case
+                * calc_stripes returns before actually doing the calculation
+                */
+               up_stripe.input_width = ih / 2;
+               up_stripe.output_width = oh / 2;
+               down_stripe.input_column = ih / 2;
+               down_stripe.output_column = oh / 2;
+               ret = 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);
+               if (ret)
+                       dev_err(t->dev, "Warn: no:0x%x,calc_stripes ret:%d\n",
+                                t->task_no, ret);
+               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;
+       int timeout;
+       bool vdi_split = false;
+
+       if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
+               (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
+               ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+                       !t->input.deinterlace.enable)) {
+               ret = IPU_CHECK_ERR_NOT_SUPPORT;
+               goto done;
+       }
+
+       /* check input */
+       ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+               t->input.format);
+       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,
+               t->output.format);
+       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);
+
+       if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               if ((t->input.crop.w > soc_max_in_width(1)) ||
+                       (t->input.crop.h > soc_max_in_height())) {
+                       ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+                       goto done;
+               }
+               /* output fmt: NV12 and YUYV, now don't support resize */
+               if (((IPU_PIX_FMT_NV12 != t->output.format) &&
+                               (IPU_PIX_FMT_YUYV != t->output.format)) ||
+                       (t->input.crop.w != t->output.crop.w) ||
+                       (t->input.crop.h != t->output.crop.h)) {
+                       ret = IPU_CHECK_ERR_NOT_SUPPORT;
+                       goto done;
+               }
+       }
+
+       /* 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, t->overlay.format);
+               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 (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
+               if ((t->input.crop.w > soc_max_in_width(0)) ||
+                       (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 ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               if (t->set.mode & ROT_MODE) {
+                       ret = IPU_CHECK_ERR_NOT_SUPPORT;
+                       goto done;
+               }
+               t->set.mode |= VDOA_MODE;
+               if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
+                       t->set.mode |= VDOA_BAND_MODE;
+               t->set.mode &= ~IC_MODE;
+       }
+
+       if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+               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;
+               if (!t->set.split_mode && (t->set.mode & VDI_MODE) &&
+                               (t->input.crop.w > soc_max_vdi_in_width())) {
+                       t->set.split_mode |= RL_SPLIT;
+                       vdi_split = true;
+               }
+               if (t->set.split_mode) {
+                       if ((t->set.split_mode == RL_SPLIT) ||
+                                (t->set.split_mode == UD_SPLIT))
+                               timeout = DEF_TIMEOUT_MS * 2 + DEF_DELAY_MS;
+                       else
+                               timeout = DEF_TIMEOUT_MS * 4 + DEF_DELAY_MS;
+                       if (t->timeout < timeout)
+                               t->timeout = timeout;
+
+                       ret = update_split_setting(t, vdi_split);
+                       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 (debug) {
+               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;
+
+       if (t->set.mode & VDI_MODE) {
+               if (t->task_id != IPU_TASK_ID_VF)
+                       t->task_id = IPU_TASK_ID_VF;
+               t->set.task = VDI_VF;
+               if (t->set.mode & ROT_MODE)
+                       t->set.task |= ROT_VF;
+       }
+
+       if (VDOA_MODE == t->set.mode) {
+               if (t->set.task != 0) {
+                       dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
+                                       t->set.task, t);
+                       return -EINVAL;
+               }
+               t->set.task |= VDOA_ONLY;
+       }
+
+       if (VDOA_BAND_MODE & t->set.mode) {
+               /* to save band size: 1<<3 = 8 lines */
+               t->set.band_lines = 3;
+       }
+
+       dump_task_info(t);
+
+       return ret;
+}
+
+static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
+{
+       uint32_t        status;
+       uint32_t        status_vf;
+       uint32_t        status_rot;
+
+       if (is_vf) {
+               status = ipu_channel_status(ipu, MEM_VDI_PRP_VF_MEM);
+               status_vf = ipu_channel_status(ipu, MEM_PRP_VF_MEM);
+               status_rot = ipu_channel_status(ipu, MEM_ROT_VF_MEM);
+               return status || status_vf || status_rot;
+       } else {
+               status = ipu_channel_status(ipu, MEM_PP_MEM);
+               status_rot = ipu_channel_status(ipu, MEM_ROT_PP_MEM);
+               return status || status_rot;
+       }
+}
+
+static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+       int             i;
+       struct ipu_soc  *ipu;
+       u8              *used;
+       uint32_t        found_ipu = 0;
+       uint32_t        found_vdoa = 0;
+       struct ipu_channel_tabel        *tbl = &ipu_ch_tbl;
+
+       mutex_lock(&tbl->lock);
+       if (t->set.mode & VDOA_MODE) {
+               if (NULL != t->vdoa_handle)
+                       found_vdoa = 1;
+               else {
+                       found_vdoa = tbl->vdoa_used ? 0 : 1;
+                       if (found_vdoa) {
+                               tbl->vdoa_used = 1;
+                               vdoa_get_handle(&t->vdoa_handle);
+                       } else
+                               /* first get vdoa->ipu resource sequence */
+                               goto out;
+                       if (t->set.task & VDOA_ONLY)
+                               goto out;
+               }
+       }
+
+       for (i = 0; i < max_ipu_no; i++) {
+               ipu = ipu_get_soc(i);
+               if (IS_ERR(ipu))
+                       dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+                                t->task_no, found_vdoa, i);
+
+               used = &tbl->used[i][IPU_PP_CH_VF];
+               if (t->set.mode & VDI_MODE) {
+                       if (0 == *used) {
+                               *used = 1;
+                               found_ipu = 1;
+                               break;
+                       }
+               } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+                       if (0 == *used) {
+                               t->task_id = IPU_TASK_ID_VF;
+                               if (t->set.mode & IC_MODE)
+                                       t->set.task |= IC_VF;
+                               if (t->set.mode & ROT_MODE)
+                                       t->set.task |= ROT_VF;
+                               *used = 1;
+                               found_ipu = 1;
+                               break;
+                       }
+               } else
+                       dev_err(t->dev, "no:0x%x,found_vdoa:%d, mode:0x%x\n",
+                                t->task_no, found_vdoa, t->set.mode);
+       }
+       if (found_ipu)
+               goto next;
+
+       for (i = 0; i < max_ipu_no; i++) {
+               ipu = ipu_get_soc(i);
+               if (IS_ERR(ipu))
+                       dev_err(t->dev, "no:0x%x,found_vdoa:%d, ipu:%d\n",
+                                t->task_no, found_vdoa, i);
+
+               if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+                       used = &tbl->used[i][IPU_PP_CH_PP];
+                       if (0 == *used) {
+                               t->task_id = IPU_TASK_ID_PP;
+                               if (t->set.mode & IC_MODE)
+                                       t->set.task |= IC_PP;
+                               if (t->set.mode & ROT_MODE)
+                                       t->set.task |= ROT_PP;
+                               *used = 1;
+                               found_ipu = 1;
+                               break;
+                       }
+               }
+       }
+
+next:
+       if (found_ipu) {
+               t->ipu = ipu;
+               t->ipu_id = i;
+               t->dev = ipu->dev;
+               if (atomic_inc_return(&t->res_get) == 2)
+                       dev_err(t->dev,
+                               "ERR no:0x%x,found_vdoa:%d,get ipu twice\n",
+                                t->task_no, found_vdoa);
+       }
+out:
+       dev_dbg(t->dev,
+               "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
+                __func__, t->task_no, found_vdoa, found_ipu);
+       mutex_unlock(&tbl->lock);
+       if (t->set.task & VDOA_ONLY)
+               return found_vdoa;
+       else if (t->set.mode & VDOA_MODE)
+               return found_vdoa && found_ipu;
+       else
+               return found_ipu;
+}
+
+static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
+{
+       int ret;
+       int rel_vdoa = 0, rel_ipu = 0;
+       struct ipu_channel_tabel        *tbl = &ipu_ch_tbl;
+
+       mutex_lock(&tbl->lock);
+       if (tsk->set.mode & VDOA_MODE) {
+               if (!tbl->vdoa_used && tsk->vdoa_handle)
+                       dev_err(tsk->dev,
+                               "ERR no:0x%x,vdoa not used,mode:0x%x\n",
+                                tsk->task_no, tsk->set.mode);
+               if (tbl->vdoa_used && tsk->vdoa_handle) {
+                       tbl->vdoa_used = 0;
+                       vdoa_put_handle(&tsk->vdoa_handle);
+                       if (tsk->ipu)
+                               tsk->ipu->vdoa_en = 0;
+                       rel_vdoa = 1;
+                       if (vdoa_only || (tsk->set.task & VDOA_ONLY))
+                               goto out;
+               }
+       }
+
+       tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
+       rel_ipu = 1;
+       ret = atomic_inc_return(&tsk->res_free);
+       if (ret == 2)
+               dev_err(tsk->dev,
+                       "ERR no:0x%x,rel_vdoa:%d,put ipu twice\n",
+                        tsk->task_no, rel_vdoa);
+out:
+       dev_dbg(tsk->dev,
+               "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
+                __func__, tsk->task_no, rel_vdoa, rel_ipu);
+       mutex_unlock(&tbl->lock);
+}
+
+static int get_vdoa_ipu_res(struct ipu_task_entry *t)
+{
+       int             ret;
+       uint32_t        found = 0;
+
+       found = _get_vdoa_ipu_res(t);
+       if (!found) {
+               t->ipu_id = -1;
+               t->ipu = NULL;
+               /* blocking to get resource */
+               ret = atomic_inc_return(&req_cnt);
+               dev_dbg(t->dev,
+                       "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
+               ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
+                                msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+               if (ret == 0) {
+                       dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
+                                        t, t->task_no, t->timeout - DEF_DELAY_MS);
+                       ret = -ETIMEDOUT;
+                       t->state = STATE_RES_TIMEOUT;
+                       goto out;
+               } else {
+                       if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
+                               dev_err(t->dev,
+                                       "ERR[no-0x%x] can not get ipu!\n",
+                                       t->task_no);
+                       ret = atomic_read(&req_cnt);
+                       if (ret > 0)
+                               ret = atomic_dec_return(&req_cnt);
+                       else
+                               dev_err(t->dev,
+                                       "ERR[no-0x%x] req_cnt:%d mismatch!\n",
+                                       t->task_no, ret);
+                       dev_dbg(t->dev, "no-0x%x,[0x%p],req_cnt:%d, got_res!\n",
+                                               t->task_no, t, ret);
+                       found = 1;
+               }
+       }
+
+out:
+       return found;
+}
+
+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);
+       kref_init(&tsk->refcount);
+       tsk->state = -EINVAL;
+       tsk->ipu_id = -1;
+       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;
+       if (tsk->timeout && (tsk->timeout > DEF_TIMEOUT_MS))
+               tsk->timeout = task->timeout;
+       else
+               tsk->timeout = DEF_TIMEOUT_MS;
+
+       return tsk;
+}
+
+static void task_mem_free(struct kref *ref)
+{
+       struct ipu_task_entry *tsk =
+                       container_of(ref, struct ipu_task_entry, refcount);
+
+       memset(tsk, 0, sizeof(*tsk));
+       kfree(tsk);
+}
+
+int create_split_child_task(struct ipu_split_task *sp_task)
+{
+       int ret = 0;
+       struct ipu_task_entry *tsk;
+
+       tsk = create_task_entry(&sp_task->task);
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
+
+       sp_task->child_task = tsk;
+       tsk->task_no = sp_task->task_no;
+
+       ret = prepare_task(tsk);
+       if (ret < 0)
+               goto err;
+
+       tsk->parent = sp_task->parent_task;
+       tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+
+       list_add(&tsk->node, &tsk->parent->split_list);
+       dev_dbg(tsk->dev, "[0x%p] sp_tsk Q list,no-0x%x\n", tsk, tsk->task_no);
+       tsk->state = STATE_QUEUE;
+       CHECK_PERF(&tsk->ts_queue);
+err:
+       return ret;
+}
+
+static inline int sp_task_check_done(struct ipu_split_task *sp_task,
+                       struct ipu_task_entry *parent, int num, int *idx)
+{
+       int i;
+       int ret = 0;
+       struct ipu_task_entry *tsk;
+       struct mutex *lock = &parent->split_lock;
+
+       *idx = -EINVAL;
+       mutex_lock(lock);
+       for (i = 0; i < num; i++) {
+               tsk = sp_task[i].child_task;
+               if (tsk && tsk->split_done) {
+                       *idx = i;
+                       ret = 1;
+                       goto out;
+               }
+       }
+
+out:
+       mutex_unlock(lock);
+       return ret;
+}
+
+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;
+       int ret;
+
+       sp_task->task_no |= stripe;
+
+       task->input = t->input;
+       task->output = t->output;
+       task->overlay_en = t->overlay_en;
+       if (task->overlay_en)
+               task->overlay = t->overlay;
+       task->task_id = t->task_id;
+       if ((t->set.split_mode == RL_SPLIT) ||
+                (t->set.split_mode == UD_SPLIT))
+               task->timeout = t->timeout / 2;
+       else
+               task->timeout = t->timeout / 4;
+
+       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;
+               t->set.sp_setting.rl_split_line = t->set.sp_setting.o_bottom_pos;
+               t->set.sp_setting.ud_split_line = t->set.sp_setting.o_right_pos;
+
+       } else {
+               task->output.crop.w = t->set.sp_setting.ow;
+               task->output.crop.h = t->set.sp_setting.oh;
+               t->set.sp_setting.rl_split_line = t->set.sp_setting.o_right_pos;
+               t->set.sp_setting.ud_split_line = t->set.sp_setting.o_bottom_pos;
+       }
+
+       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, "ERR:should not be here\n");
+               break;
+       }
+
+       ret = create_split_child_task(sp_task);
+       if (ret < 0)
+               dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
+       return ret;
+}
+
+static int queue_split_task(struct ipu_task_entry *t,
+                               struct ipu_split_task *sp_task, uint32_t size)
+{
+       int err[4];
+       int ret = 0;
+       int i, j;
+       struct ipu_task_entry *tsk = NULL;
+       struct mutex *lock = &t->split_lock;
+
+       dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
+                        t, t->task_no, size);
+       mutex_init(lock);
+       init_waitqueue_head(&t->split_waitq);
+       INIT_LIST_HEAD(&t->split_list);
+       for (j = 0; j < size; j++) {
+               memset(&sp_task[j], 0, sizeof(*sp_task));
+               sp_task[j].parent_task = t;
+               sp_task[j].task_no = t->task_no;
+       }
+
+       if (t->set.split_mode == RL_SPLIT) {
+               i = 0;
+               err[i] = create_split_task(RIGHT_STRIPE, &sp_task[i]);
+               if (err[i] < 0)
+                       goto err_start;
+               i = 1;
+               err[i] = create_split_task(LEFT_STRIPE, &sp_task[i]);
+       } else if (t->set.split_mode == UD_SPLIT) {
+               i = 0;
+               err[i] = create_split_task(DOWN_STRIPE, &sp_task[i]);
+               if (err[i] < 0)
+                       goto err_start;
+               i = 1;
+               err[i] = create_split_task(UP_STRIPE, &sp_task[i]);
+       } else {
+               i = 0;
+               err[i] = create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+               if (err[i] < 0)
+                       goto err_start;
+               i = 1;
+               err[i] = create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[i]);
+               if (err[i] < 0)
+                       goto err_start;
+               i = 2;
+               err[i] = create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[i]);
+               if (err[i] < 0)
+                       goto err_start;
+               i = 3;
+               err[i] = create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[i]);
+       }
+
+err_start:
+       for (j = 0; j < (i + 1); j++) {
+               if (err[j] < 0) {
+                       if (sp_task[j].child_task)
+                               dev_err(t->dev,
+                                "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
+                               j, sp_task[j].child_task->task_no,
+                               sp_task[j].child_task->state, err[j]);
+                       goto err_exit;
+               }
+               dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
+                       sp_task[j].child_task, j, sp_task[j].child_task->task_no,
+                       state_msg[sp_task[j].child_task->state].msg, err[j]);
+       }
+
+       return ret;
+
+err_exit:
+       for (j = 0; j < (i + 1); j++) {
+               if (err[j] < 0 && !ret)
+                       ret = err[j];
+               tsk = sp_task[j].child_task;
+               if (!tsk)
+                       continue;
+               kfree(tsk);
+               memset(tsk, 0, sizeof(*tsk));
+       }
+       t->state = STATE_ERR;
+       return ret;
+
+}
+
+static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
+                               ipu_channel_t channel, uint32_t ch_type)
+{
+       int ret = 0;
+       int i;
+       uint32_t ipu_fmt;
+       dma_addr_t inbuf_base = 0;
+       u32 field_size;
+       struct vdoa_params param;
+       struct vdoa_ipu_buf buf;
+       struct ipu_soc *ipu_idx;
+       u32 ipu_stride, obuf_size;
+       u32 height, width;
+       ipu_buffer_t type;
+
+       if ((IPU_PIX_FMT_YUYV != t->output.format) &&
+               (IPU_PIX_FMT_NV12 != t->output.format)) {
+               dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
+               return -EINVAL;
+       }
+
+       memset(&param, 0, sizeof(param));
+       /* init channel tiled bufs */
+       if (deinterlace_3_field(t) &&
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               field_size = tiled_filed_size(t);
+               if (INPUT_CHAN_VDI_P == ch_type) {
+                       inbuf_base = t->input.paddr + field_size;
+                       param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
+               } else if (INPUT_CHAN == ch_type) {
+                       inbuf_base = t->input.paddr_n;
+                       param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
+               } else if (INPUT_CHAN_VDI_N == ch_type) {
+                       inbuf_base = t->input.paddr_n + field_size;
+                       param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
+               } else
+                       return -EINVAL;
+               height = t->input.crop.h >> 1; /* field format for vdoa */
+               width = t->input.crop.w;
+               param.vfield_buf.vubo = t->set.i_uoff;
+               param.interlaced = 1;
+               param.scan_order = 1;
+               type = IPU_INPUT_BUFFER;
+       } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
+                       (INPUT_CHAN == ch_type)) {
+               height = t->input.crop.h;
+               width = t->input.crop.w;
+               param.vframe_buf.veba = t->input.paddr + t->set.i_off;
+               param.vframe_buf.vubo = t->set.i_uoff;
+               type = IPU_INPUT_BUFFER;
+       } else
+               return -EINVAL;
+
+       param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
+       if (param.band_mode && (t->set.band_lines != 3) &&
+                (t->set.band_lines != 4) && (t->set.band_lines != 5))
+               return -EINVAL;
+       else if (param.band_mode)
+               param.band_lines = (1 << t->set.band_lines);
+       for (i = 0; i < max_ipu_no; i++) {
+               ipu_idx = ipu_get_soc(i);
+               if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
+                       break;
+       }
+       if (t->set.task & VDOA_ONLY)
+               /* dummy, didn't need ipu res */
+               i = 0;
+       if (max_ipu_no == i) {
+               dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
+               return -EINVAL;
+       }
+
+       param.ipu_num = i;
+       param.vpu_stride = t->input.width;
+       param.height = height;
+       param.width = width;
+       if (IPU_PIX_FMT_NV12 == t->output.format)
+               param.pfs = VDOA_PFS_NV12;
+       else
+               param.pfs = VDOA_PFS_YUYV;
+       ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
+                               IPU_PIX_FMT_NV12;
+       ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
+       obuf_size = PAGE_ALIGN(param.width * param.height *
+                               fmt_to_bpp(ipu_fmt)/8);
+       dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
+                       param.band_mode, param.band_lines);
+       if (!param.band_mode) {
+               /* note: if only for tiled -> raster convert and
+                  no other post-processing, we don't need alloc buf
+                  and use output buffer directly.
+               */
+               if (t->set.task & VDOA_ONLY)
+                       param.ieba0 = t->output.paddr;
+               else {
+                       dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
+                       return -EINVAL;
+               }
+       } else {
+               if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
+                       dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
+                       return -EINVAL;
+               }
+       }
+       ret = vdoa_setup(t->vdoa_handle, &param);
+       if (ret)
+               goto done;
+       vdoa_get_output_buf(t->vdoa_handle, &buf);
+       if (t->set.task & VDOA_ONLY)
+               goto done;
+
+       ret = ipu_init_channel_buffer(ipu,
+                       channel,
+                       type,
+                       ipu_fmt,
+                       width,
+                       height,
+                       ipu_stride,
+                       IPU_ROTATE_NONE,
+                       buf.ieba0,
+                       buf.ieba1,
+                       0,
+                       buf.iubo,
+                       0);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_BUF_FAIL;
+               goto done;
+       }
+
+       if (param.band_mode) {
+               ret = ipu_set_channel_bandmode(ipu, channel,
+                               type, t->set.band_lines);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BAND_FAIL;
+                       goto done;
+               }
+       }
+done:
+       return ret;
+}
+
+static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       int ret = 0;
+
+       if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
+               ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+               CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
+       } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
+               ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
+               ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
+                                       INPUT_CHAN_VDI_P);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
+               ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
+                                       INPUT_CHAN_VDI_N);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
+       } else {
+               ret = -EINVAL;
+               dev_err(t->dev, "ERR[no-0x%x] invalid fmt:0x%x!\n",
+                       t->task_no, t->input.format);
+       }
+
+done:
+       return ret;
+}
+
+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;
+       u32 vdi_frame_idx = 0;
+
+       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 if (t->overlay.alpha.loc_alp_paddr)
+                       params.mem_prp_vf_mem.alpha_chan_en = 1;
+               /* otherwise, alpha bending per pixel is used. */
+               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;
+               }
+       }
+
+       if (t->input.deinterlace.enable) {
+               if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_FIELD_MASK)
+                       params.mem_prp_vf_mem.field_fmt =
+                               IPU_DEINTERLACE_FIELD_BOTTOM;
+               else
+                       params.mem_prp_vf_mem.field_fmt =
+                               IPU_DEINTERLACE_FIELD_TOP;
+
+               if (t->input.deinterlace.field_fmt & IPU_DEINTERLACE_RATE_EN)
+                       vdi_frame_idx = t->input.deinterlace.field_fmt &
+                                               IPU_DEINTERLACE_RATE_FRAME1;
+       }
+
+       if (t->set.mode & VDOA_MODE)
+               ipu->vdoa_en = 1;
+
+       /* init channels */
+       if (!(t->set.task & VDOA_ONLY)) {
+               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 ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               ret = init_tiled_ch_bufs(ipu, t);
+               if (ret < 0)
+                       goto done;
+       } else {
+               if ((deinterlace_3_field(t)) &&
+                       (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+                       if (params.mem_prp_vf_mem.field_fmt ==
+                               IPU_DEINTERLACE_FIELD_TOP) {
+                               if (vdi_frame_idx) {
+                                       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;
+                                       params.mem_prp_vf_mem.field_fmt =
+                                               IPU_DEINTERLACE_FIELD_BOTTOM;
+                               } else {
+                                       inbuf_p = t->input.paddr + t->set.i_off;
+                                       inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+                                       inbuf_n = t->input.paddr_n + t->set.i_off;
+                               }
+                       } else {
+                               if (vdi_frame_idx) {
+                                       inbuf_p = t->input.paddr + t->set.i_off;
+                                       inbuf = t->input.paddr_n + t->set.istride + t->set.i_off;
+                                       inbuf_n = t->input.paddr_n + t->set.i_off;
+                                       params.mem_prp_vf_mem.field_fmt =
+                                               IPU_DEINTERLACE_FIELD_TOP;
+                               } else {
+                                       inbuf_p = t->input.paddr + t->set.istride +
+                                                       t->set.i_off;
+                                       inbuf = t->input.paddr + t->set.i_off;
+                                       inbuf_n = t->input.paddr_n + t->set.istride +
+                                                       t->set.i_off;
+                               }
+                       }
+               } else {
+                       if (t->input.deinterlace.enable) {
+                               if (params.mem_prp_vf_mem.field_fmt ==
+                                       IPU_DEINTERLACE_FIELD_TOP) {
+                                       if (vdi_frame_idx) {
+                                               inbuf = t->input.paddr + t->set.istride + t->set.i_off;
+                                               params.mem_prp_vf_mem.field_fmt =
+                                                       IPU_DEINTERLACE_FIELD_BOTTOM;
+                                       } else
+                                               inbuf = t->input.paddr + t->set.i_off;
+                               } else {
+                                       if (vdi_frame_idx) {
+                                               inbuf = t->input.paddr + t->set.i_off;
+                                               params.mem_prp_vf_mem.field_fmt =
+                                                       IPU_DEINTERLACE_FIELD_TOP;
+                                       } else
+                                               inbuf = t->input.paddr + 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_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
+               ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+                       + t->set.ov_alpha_off;
+
+       if ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+               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) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+               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;
+               }
+       }
+
+       if (!(t->set.task & VDOA_ONLY)) {
+               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;
+               }
+       }
+
+       if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+               ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+               CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
+                               STATE_LINK_CHAN_FAIL, done, ret);
+       }
+
+done:
+       return ret;
+}
+
+static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       int ret;
+
+       if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+               ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
+                               STATE_UNLINK_CHAN_FAIL, ret);
+       }
+       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,
+                       in_stride,
+                       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;
+       case MEM_VDI_MEM:
+               irq = IPU_IRQ_VDIC_OUT_EOF;
+               break;
+       default:
+               irq = -EINVAL;
+       }
+
+       return irq;
+}
+
+static irqreturn_t task_irq_handler(int irq, void *dev_id)
+{
+       struct ipu_task_entry *prev_tsk = dev_id;
+
+       CHECK_PERF(&prev_tsk->ts_inirq);
+       complete(&prev_tsk->irq_comp);
+       dev_dbg(prev_tsk->dev, "[0x%p] no-0x%x in-irq!",
+                                prev_tsk, prev_tsk->task_no);
+
+       return IRQ_HANDLED;
+}
+
+/* Fix deinterlace up&down split mode medium line */
+static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       u32 vdi_size;
+       u32 vdi_save_lines;
+       u32 stripe_mode;
+       u32 task_no;
+       u32 i, offset_addr;
+       unsigned char  *base_off;
+       struct ipu_task_entry *parent = t->parent;
+
+       if (!parent) {
+               dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
+               return;
+       }
+       stripe_mode = t->task_no & 0xf;
+       task_no = t->task_no >> 4;
+
+       base_off = (char *) __va(t->output.paddr);
+       if (base_off == NULL) {
+               dev_err(t->dev, "ERR[0x%p]Falied get vitual address\n", t);
+               return;
+       }
+
+       vdi_save_lines = (t->output.crop.h - t->set.sp_setting.ud_split_line)/2;
+       vdi_size = vdi_save_lines * t->output.crop.w * 2;
+
+       if (vdi_save_lines <= 0) {
+               dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
+               return;
+       }
+
+       /*check vditmpbuf buffer have alloced or buffer size is changed */
+       if ((vdi_save_lines != parent->old_save_lines) ||
+               (vdi_size != parent->old_size)) {
+               if (parent->vditmpbuf[0] != NULL)
+                       kfree(parent->vditmpbuf[0]);
+               if (parent->vditmpbuf[1] != NULL)
+                       kfree(parent->vditmpbuf[1]);
+
+               parent->vditmpbuf[0] = kmalloc(vdi_size, GFP_KERNEL);
+               if (parent->vditmpbuf[0] == NULL) {
+                       dev_err(t->dev,
+                               "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
+                       return;
+               }
+               memset(parent->vditmpbuf[0], 0, vdi_size);
+
+               parent->vditmpbuf[1] = kmalloc(vdi_size, GFP_KERNEL);
+               if (parent->vditmpbuf[1] == NULL) {
+                       dev_err(t->dev,
+                               "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
+                       return;
+               }
+               memset(parent->vditmpbuf[1], 0, vdi_size);
+
+               parent->old_save_lines = vdi_save_lines;
+               parent->old_size = vdi_size;
+       }
+
+       /* UP stripe or UP&LEFT stripe */
+       if ((stripe_mode == UP_STRIPE) ||
+                       (stripe_mode == (UP_STRIPE | LEFT_STRIPE))) {
+               if (!parent->buf0filled) {
+                       offset_addr = t->set.o_off +
+                               t->set.sp_setting.ud_split_line*t->set.ostride;
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + vdi_size);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                               t->output.paddr + offset_addr + vdi_size);
+
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
+                                       base_off + offset_addr +
+                                       i*t->set.ostride, t->output.crop.w*2);
+                       parent->buf0filled = true;
+               } else {
+                       offset_addr = t->set.o_off + (t->output.crop.h -
+                                       vdi_save_lines) * t->set.ostride;
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(base_off + offset_addr + i*t->set.ostride,
+                                               parent->vditmpbuf[0] + i*t->output.crop.w*2,
+                                               t->output.crop.w*2);
+
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + i*t->set.ostride);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + i*t->set.ostride);
+                       parent->buf0filled = false;
+               }
+       }
+       /*Down stripe or Down&Left stripe*/
+       else if ((stripe_mode == DOWN_STRIPE) ||
+                       (stripe_mode == (DOWN_STRIPE | LEFT_STRIPE))) {
+               if (!parent->buf0filled) {
+                       offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + vdi_size);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + vdi_size);
+
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(parent->vditmpbuf[0] + i*t->output.crop.w*2,
+                                               base_off + offset_addr + i*t->set.ostride,
+                                               t->output.crop.w*2);
+                       parent->buf0filled = true;
+               } else {
+                       offset_addr = t->set.o_off;
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(base_off + offset_addr + i*t->set.ostride,
+                                               parent->vditmpbuf[0] + i*t->output.crop.w*2,
+                                               t->output.crop.w*2);
+
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + i*t->set.ostride);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + i*t->set.ostride);
+                       parent->buf0filled = false;
+               }
+       }
+       /*Up&Right stripe*/
+       else if (stripe_mode == (UP_STRIPE | RIGHT_STRIPE)) {
+               if (!parent->buf1filled) {
+                       offset_addr = t->set.o_off +
+                               t->set.sp_setting.ud_split_line*t->set.ostride;
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + vdi_size);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + vdi_size);
+
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
+                                               base_off + offset_addr + i*t->set.ostride,
+                                               t->output.crop.w*2);
+                       parent->buf1filled = true;
+               } else {
+                       offset_addr = t->set.o_off +
+                               (t->output.crop.h - vdi_save_lines)*t->set.ostride;
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(base_off + offset_addr + i*t->set.ostride,
+                                               parent->vditmpbuf[1] + i*t->output.crop.w*2,
+                                               t->output.crop.w*2);
+
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + i*t->set.ostride);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + i*t->set.ostride);
+                       parent->buf1filled = false;
+               }
+       }
+       /*Down stripe or Down&Right stript*/
+       else if (stripe_mode == (DOWN_STRIPE | RIGHT_STRIPE)) {
+               if (!parent->buf1filled) {
+                       offset_addr = t->set.o_off + vdi_save_lines*t->set.ostride;
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + vdi_save_lines*t->set.ostride);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(parent->vditmpbuf[1] + i*t->output.crop.w*2,
+                                               base_off + offset_addr + i*t->set.ostride,
+                                               t->output.crop.w*2);
+                       parent->buf1filled = true;
+               } else {
+                       offset_addr = t->set.o_off;
+                       for (i = 0; i < vdi_save_lines; i++)
+                               memcpy(base_off + offset_addr + i*t->set.ostride,
+                                               parent->vditmpbuf[1] + i*t->output.crop.w*2,
+                                               t->output.crop.w*2);
+
+                       dmac_flush_range(base_off + offset_addr,
+                                       base_off + offset_addr + vdi_save_lines*t->set.ostride);
+                       outer_flush_range(t->output.paddr + offset_addr,
+                                       t->output.paddr + offset_addr + vdi_save_lines*t->set.ostride);
+                       parent->buf1filled = false;
+               }
+       }
+}
+
+static void do_task_release(struct ipu_task_entry *t, int fail)
+{
+       int ret;
+       struct ipu_soc *ipu = t->ipu;
+
+       if (t->input.deinterlace.enable && !fail &&
+                       (t->task_no & (UP_STRIPE | DOWN_STRIPE)))
+               vdi_split_process(ipu, t);
+
+       ipu_free_irq(ipu, t->irq, t);
+
+       if (t->vdoa_dma.vaddr)
+               dma_free_coherent(t->dev,
+                       t->vdoa_dma.size,
+                       t->vdoa_dma.vaddr,
+                       t->vdoa_dma.paddr);
+
+       if (only_ic(t->set.mode)) {
+               ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
+                               STATE_DISABLE_CHAN_FAIL, ret);
+               if (deinterlace_3_field(t)) {
+                       ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+                                                       true);
+                       CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_p",
+                                       STATE_DISABLE_CHAN_FAIL, ret);
+                       ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+                                                       true);
+                       CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic_n",
+                                       STATE_DISABLE_CHAN_FAIL, ret);
+               }
+       } else if (only_rot(t->set.mode)) {
+               ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_rot",
+                               STATE_DISABLE_CHAN_FAIL, ret);
+       } else if (ic_and_rot(t->set.mode)) {
+               ret = ipu_unlink_channels(ipu, t->set.ic_chan, t->set.rot_chan);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch",
+                               STATE_UNLINK_CHAN_FAIL, ret);
+               ret = ipu_disable_channel(ipu, t->set.rot_chan, true);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-rot",
+                               STATE_DISABLE_CHAN_FAIL, ret);
+               ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch ic_and_rot-ic",
+                               STATE_DISABLE_CHAN_FAIL, ret);
+               if (deinterlace_3_field(t)) {
+                       ret = ipu_disable_channel(ipu, t->set.vdi_ic_p_chan,
+                                                       true);
+                       CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-p",
+                                       STATE_DISABLE_CHAN_FAIL, ret);
+                       ret = ipu_disable_channel(ipu, t->set.vdi_ic_n_chan,
+                                                       true);
+                       CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch icrot-ic-n",
+                                       STATE_DISABLE_CHAN_FAIL, ret);
+               }
+       }
+
+       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)) {
+               uninit_ic(ipu, t);
+               uninit_rot(ipu, t);
+       }
+
+       t->state = STATE_OK;
+       CHECK_PERF(&t->ts_rel);
+       return;
+}
+
+static void do_task_vdoa_only(struct ipu_task_entry *t)
+{
+       int ret;
+
+       ret = init_tiled_ch_bufs(NULL, t);
+       CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
+       ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+       vdoa_stop(t->vdoa_handle);
+       CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
+                       STATE_VDOA_IRQ_TIMEOUT, out, ret);
+
+       t->state = STATE_OK;
+out:
+       return;
+}
+
+static void do_task(struct ipu_task_entry *t)
+{
+       int r_size;
+       int irq;
+       int ret;
+       uint32_t busy;
+       struct ipu_soc *ipu = t->ipu;
+
+       CHECK_PERF(&t->ts_dotask);
+
+       if (!ipu) {
+               t->state = STATE_NO_IPU;
+               return;
+       }
+
+       init_completion(&t->irq_comp);
+       dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
+                t->task_no, 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) {
+               if (t->set.mode & VDOA_BAND_MODE) {
+                       t->set.ic_chan = MEM_VDI_MEM;
+                       if (deinterlace_3_field(t)) {
+                               t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
+                               t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
+                       }
+                       dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
+                                        (void *)t);
+               } else {
+                       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 ch MEM_VDI_PRP_VF_MEM\n", 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);
+       }
+
+       if (t->task_id == IPU_TASK_ID_VF)
+               busy = ic_vf_pp_is_busy(ipu, true);
+       else if (t->task_id == IPU_TASK_ID_PP)
+               busy = ic_vf_pp_is_busy(ipu, false);
+       else {
+               dev_err(ipu->dev, "ERR[no:0x%x]ipu task_id:%d invalid!\n",
+                               t->task_no, t->task_id);
+               return;
+       }
+       if (busy) {
+               dev_err(ipu->dev, "ERR[0x%p-no:0x%x]ipu task_id:%d busy!\n",
+                               (void *)t, t->task_no, t->task_id);
+               t->state = STATE_IPU_BUSY;
+               return;
+       }
+
+       irq = get_irq(t);
+       if (irq < 0) {
+               t->state = STATE_NO_IRQ;
+               return;
+       }
+       t->irq = irq;
+
+       /* 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);
+               CHECK_RETCODE(ret < 0, "init_ic only_ic",
+                               t->state, chan_setup, ret);
+       } else if (only_rot(t->set.mode)) {
+               dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
+               ret = init_rot(ipu, t);
+               CHECK_RETCODE(ret < 0, "init_rot only_rot",
+                               t->state, chan_setup, ret);
+       } else if (ic_and_rot(t->set.mode)) {
+               int rot_idx = (t->task_id == IPU_TASK_ID_VF) ? 0 : 1;
+
+               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 = PAGE_ALIGN(t->set.r_width * t->set.r_height
+                       * fmt_to_bpp(t->set.r_fmt)/8);
+
+               if (r_size > ipu->rot_dma[rot_idx].size) {
+                       dev_dbg(t->dev, "[0x%p]realloc rot buffer\n", (void *)t);
+
+                       if (ipu->rot_dma[rot_idx].vaddr)
+                               dma_free_coherent(t->dev,
+                                       ipu->rot_dma[rot_idx].size,
+                                       ipu->rot_dma[rot_idx].vaddr,
+                                       ipu->rot_dma[rot_idx].paddr);
+
+                       ipu->rot_dma[rot_idx].size = r_size;
+                       ipu->rot_dma[rot_idx].vaddr = dma_alloc_coherent(t->dev,
+                                               r_size,
+                                               &ipu->rot_dma[rot_idx].paddr,
+                                               GFP_DMA | GFP_KERNEL);
+                       CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
+                                       "ic_and_rot", STATE_SYS_NO_MEM,
+                                       chan_setup, -ENOMEM);
+               }
+               t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
+
+               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);
+               CHECK_RETCODE(ret < 0, "init_ic ic_and_rot",
+                               t->state, chan_setup, ret);
+               ret = init_rot(ipu, t);
+               CHECK_RETCODE(ret < 0, "init_rot ic_and_rot",
+                               t->state, chan_setup, ret);
+               ret = ipu_link_channels(ipu, t->set.ic_chan,
+                               t->set.rot_chan);
+               CHECK_RETCODE(ret < 0, "ipu_link_ch ic_and_rot",
+                               STATE_LINK_CHAN_FAIL, chan_setup, ret);
+       } else {
+               dev_err(t->dev, "ERR [0x%p]do task: should not be here\n", t);
+               t->state = STATE_ERR;
+               return;
+       }
+
+       ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, t);
+       CHECK_RETCODE(ret < 0, "ipu_req_irq",
+                       STATE_IRQ_FAIL, chan_setup, ret);
+
+       /* enable/start channel */
+       if (only_ic(t->set.mode)) {
+               ret = ipu_enable_channel(ipu, t->set.ic_chan);
+               CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic",
+                               STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               if (deinterlace_3_field(t)) {
+                       ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+                       CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_p",
+                                       STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+                       ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+                       CHECK_RETCODE(ret < 0, "ipu_enable_ch only_ic_n",
+                                       STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               }
+
+               ret = ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER,
+                                       0);
+               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic",
+                               STATE_SEL_BUF_FAIL, chan_buf, ret);
+               if (t->overlay_en) {
+                       ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                               IPU_GRAPH_IN_BUFFER, 0);
+                       CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_g",
+                                       STATE_SEL_BUF_FAIL, chan_buf, ret);
+                       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+                               ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_ALPHA_IN_BUFFER, 0);
+                               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_a",
+                                               STATE_SEL_BUF_FAIL, chan_buf,
+                                               ret);
+                       }
+               }
+               if (!(t->set.mode & VDOA_BAND_MODE)) {
+                       if (deinterlace_3_field(t))
+                               ipu_select_multi_vdi_buffer(ipu, 0);
+                       else {
+                               ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_INPUT_BUFFER, 0);
+                               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
+                                       STATE_SEL_BUF_FAIL, chan_buf, ret);
+                       }
+               }
+       } else if (only_rot(t->set.mode)) {
+               ret = ipu_enable_channel(ipu, t->set.rot_chan);
+               CHECK_RETCODE(ret < 0, "ipu_enable_ch only_rot",
+                               STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               ret = ipu_select_buffer(ipu, t->set.rot_chan,
+                                               IPU_OUTPUT_BUFFER, 0);
+               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_o",
+                               STATE_SEL_BUF_FAIL, chan_buf, ret);
+               ret = ipu_select_buffer(ipu, t->set.rot_chan,
+                                               IPU_INPUT_BUFFER, 0);
+               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_rot_i",
+                               STATE_SEL_BUF_FAIL, chan_buf, ret);
+       } else if (ic_and_rot(t->set.mode)) {
+               ret = ipu_enable_channel(ipu, t->set.rot_chan);
+               CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-rot",
+                               STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               ret = ipu_enable_channel(ipu, t->set.ic_chan);
+               CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-ic",
+                               STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               if (deinterlace_3_field(t)) {
+                       ret = ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+                       CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-p",
+                                       STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+                       ret = ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
+                       CHECK_RETCODE(ret < 0, "ipu_enable_ch ic_and_rot-n",
+                                       STATE_ENABLE_CHAN_FAIL, chan_en, ret);
+               }
+
+               ret = ipu_select_buffer(ipu, t->set.rot_chan,
+                                               IPU_OUTPUT_BUFFER, 0);
+               CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-rot-o",
+                               STATE_SEL_BUF_FAIL, chan_buf, ret);
+               if (t->overlay_en) {
+                       ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_GRAPH_IN_BUFFER, 0);
+                       CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-g",
+                                       STATE_SEL_BUF_FAIL, chan_buf, ret);
+                       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+                               ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_ALPHA_IN_BUFFER, 0);
+                               CHECK_RETCODE(ret < 0, "ipu_sel_buf icrot-ic-a",
+                                               STATE_SEL_BUF_FAIL,
+                                               chan_buf, ret);
+                       }
+               }
+               ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                               IPU_OUTPUT_BUFFER, 0);
+               CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-o",
+                               STATE_SEL_BUF_FAIL, chan_buf, ret);
+               if (deinterlace_3_field(t))
+                       ipu_select_multi_vdi_buffer(ipu, 0);
+               else {
+                       ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_INPUT_BUFFER, 0);
+                       CHECK_RETCODE(ret < 0, "ipu_sel_buf ic_and_rot-ic-i",
+                                       STATE_SEL_BUF_FAIL, chan_buf, ret);
+               }
+       }
+
+       if (need_split(t))
+               t->state = STATE_IN_PROGRESS;
+
+       if (t->set.mode & VDOA_BAND_MODE) {
+               ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+               CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
+                               STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
+       }
+
+       CHECK_PERF(&t->ts_waitirq);
+       ret = wait_for_completion_timeout(&t->irq_comp,
+                                msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
+       CHECK_PERF(&t->ts_wakeup);
+       CHECK_RETCODE(ret == 0, "wait_for_comp_timeout",
+                       STATE_IRQ_TIMEOUT, chan_rel, ret);
+       dev_dbg(t->dev, "[0x%p] no-0x%x ipu irq done!", t, t->task_no);
+
+chan_rel:
+chan_buf:
+chan_en:
+chan_setup:
+       if (t->set.mode & VDOA_BAND_MODE)
+               vdoa_stop(t->vdoa_handle);
+       do_task_release(t, t->state >= STATE_ERR);
+       return;
+}
+
+static void do_task_vdoa_vdi(struct ipu_task_entry *t)
+{
+       int i;
+       int ret;
+       u32 stripe_width;
+
+       /* FIXME: crop mode not support now */
+       stripe_width = t->input.width >> 1;
+       t->input.crop.pos.x = 0;
+       t->input.crop.pos.y = 0;
+       t->input.crop.w = stripe_width;
+       t->input.crop.h = t->input.height;
+       t->output.crop.w = stripe_width;
+       t->output.crop.h = t->input.height;
+
+       for (i = 0; i < 2; i++) {
+               t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
+               t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
+               /* check input */
+               ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+                       t->input.format);
+               if (ret < 0) {
+                       ret = STATE_ERR;
+                       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);
+               dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
+                       t->set.i_off, t->set.i_uoff, t->set.istride);
+               /* check output */
+               ret = set_crop(&t->output.crop, t->input.width,
+                                       t->output.height, t->output.format);
+               if (ret < 0) {
+                       ret = STATE_ERR;
+                       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);
+
+               dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
+                               t->set.o_off, t->set.o_uoff, t->set.ostride);
+
+               do_task(t);
+       }
+
+       return;
+done:
+       dev_err(t->dev, "ERR %s set_crop.\n", __func__);
+       t->state = ret;
+       return;
+}
+
+static void get_res_do_task(struct ipu_task_entry *t)
+{
+       uint32_t        found;
+       uint32_t        split_child;
+       struct mutex    *lock;
+
+       found = get_vdoa_ipu_res(t);
+       if (!found) {
+               dev_err(t->dev, "ERR:[0x%p] no-0x%x can not get res\n",
+                       t, t->task_no);
+               return;
+       } else {
+               if (t->set.task & VDOA_ONLY)
+                       do_task_vdoa_only(t);
+               else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+                               (t->set.mode & VDOA_BAND_MODE) &&
+                               (t->input.crop.w > soc_max_vdi_in_width()))
+                       do_task_vdoa_vdi(t);
+               else
+                       do_task(t);
+               put_vdoa_ipu_res(t, 0);
+       }
+       if (t->state != STATE_OK) {
+               dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
+                       t, t->task_no, state_msg[t->state].msg);
+       }
+
+       split_child = need_split(t) && t->parent;
+       if (split_child) {
+               lock = &t->parent->split_lock;
+               mutex_lock(lock);
+               t->split_done = 1;
+               mutex_unlock(lock);
+               wake_up(&t->parent->split_waitq);
+       }
+
+       return;
+}
+
+static void wait_split_task_complete(struct ipu_task_entry *parent,
+                               struct ipu_split_task *sp_task, uint32_t size)
+{
+       struct ipu_task_entry *tsk = NULL;
+       int ret = 0, rc;
+       int j, idx = -1;
+       unsigned long flags;
+       struct mutex *lock = &parent->split_lock;
+       int k, busy_vf, busy_pp;
+       struct ipu_soc *ipu;
+       DECLARE_PERF_VAR;
+
+       for (j = 0; j < size; j++) {
+               rc = wait_event_timeout(
+                       parent->split_waitq,
+                       sp_task_check_done(sp_task, parent, size, &idx),
+                       msecs_to_jiffies(parent->timeout - DEF_DELAY_MS));
+               if (!rc) {
+                       dev_err(parent->dev,
+                               "ERR:[0x%p] no-0x%x, split_task timeout,j:%d,"
+                               "size:%d.\n",
+                                parent, parent->task_no, j, size);
+                       ret = -ETIMEDOUT;
+                       goto out;
+               } else {
+                       if (idx < 0) {
+                               dev_err(parent->dev,
+                               "ERR:[0x%p] no-0x%x, invalid task idx:%d\n",
+                                parent, parent->task_no, idx);
+                               continue;
+                       }
+                       tsk = sp_task[idx].child_task;
+                       mutex_lock(lock);
+                       if (!tsk->split_done || !tsk->ipu)
+                               dev_err(tsk->dev,
+                               "ERR:no-0x%x,split not done:%d/null ipu:0x%p\n",
+                                tsk->task_no, tsk->split_done, tsk->ipu);
+                       tsk->split_done = 0;
+                       mutex_unlock(lock);
+
+                       dev_dbg(tsk->dev,
+                               "[0x%p] no-0x%x sp_tsk[%d] done,state:%d.\n",
+                                tsk, tsk->task_no, idx, tsk->state);
+                       #ifdef DBG_IPU_PERF
+                               CHECK_PERF(&tsk->ts_rel);
+                               PRINT_TASK_STATISTICS;
+                       #endif
+               }
+       }
+
+out:
+       if (ret == -ETIMEDOUT) {
+               /* debug */
+               for (k = 0; k < max_ipu_no; k++) {
+                       ipu = ipu_get_soc(k);
+                       if (IS_ERR(ipu)) {
+                               dev_err(parent->dev, "no:0x%x, null ipu:%d\n",
+                                parent->task_no, k);
+                       } else {
+                               busy_vf = ic_vf_pp_is_busy(ipu, true);
+                               busy_pp = ic_vf_pp_is_busy(ipu, false);
+                               dev_err(parent->dev,
+                                       "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
+                                       k, busy_vf, busy_pp);
+                       }
+               }
+               for (k = 0; k < size; k++) {
+                       tsk = sp_task[k].child_task;
+                       if (!tsk)
+                               continue;
+                       dev_err(parent->dev,
+                               "ERR: sp_task[%d][0x%p] no-0x%x done:%d,"
+                                "state:%s,on_list:%d, ipu:0x%p,timeout!\n",
+                                k, tsk, tsk->task_no, tsk->split_done,
+                                state_msg[tsk->state].msg, tsk->task_in_list,
+                                tsk->ipu);
+               }
+       }
+
+       for (j = 0; j < size; j++) {
+               tsk = sp_task[j].child_task;
+               if (!tsk)
+                       continue;
+               spin_lock_irqsave(&ipu_task_list_lock, flags);
+               if (tsk->task_in_list) {
+                       list_del(&tsk->node);
+                       tsk->task_in_list = 0;
+                       dev_dbg(tsk->dev,
+                               "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
+                                tsk, tsk->task_no, tsk->task_id);
+               }
+               spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+               if (!tsk->ipu)
+                       continue;
+               if (tsk->state != STATE_OK) {
+                       dev_err(tsk->dev,
+                               "ERR:[0x%p] no-0x%x,id:%d, sp_tsk state: %s\n",
+                                       tsk, tsk->task_no, tsk->task_id,
+                                       state_msg[tsk->state].msg);
+               }
+               kref_put(&tsk->refcount, task_mem_free);
+       }
+
+       kfree(parent->vditmpbuf[0]);
+       kfree(parent->vditmpbuf[1]);
+
+       if (ret < 0)
+               parent->state = STATE_TIMEOUT;
+       else
+               parent->state = STATE_OK;
+       return;
+}
+
+static inline int find_task(struct ipu_task_entry **t, int thread_id)
+{
+       int found;
+       unsigned long flags;
+       struct ipu_task_entry *tsk;
+       struct list_head *task_list = &ipu_task_list;
+
+       *t = NULL;
+       spin_lock_irqsave(&ipu_task_list_lock, flags);
+       found = !list_empty(task_list);
+       if (found) {
+               tsk = list_first_entry(task_list, struct ipu_task_entry, node);
+               if (tsk->task_in_list) {
+                       list_del(&tsk->node);
+                       tsk->task_in_list = 0;
+                       *t = tsk;
+                       kref_get(&tsk->refcount);
+                       dev_dbg(tsk->dev,
+                       "thread_id:%d,[0x%p] task_no:0x%x,mode:0x%x list_del\n",
+                       thread_id, tsk, tsk->task_no, tsk->set.mode);
+               } else
+                       dev_err(tsk->dev,
+                       "thread_id:%d,task_no:0x%x,mode:0x%x not on list_del\n",
+                       thread_id, tsk->task_no, tsk->set.mode);
+       }
+       spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+       return found;
+}
+
+static int ipu_task_thread(void *argv)
+{
+       struct ipu_task_entry *tsk;
+       struct ipu_task_entry *sp_tsk0;
+       struct ipu_split_task sp_task[4];
+       /* priority lower than irq_thread */
+       const struct sched_param param = {
+               .sched_priority = MAX_USER_RT_PRIO/2 - 1,
+       };
+       int ret;
+       int curr_thread_id;
+       uint32_t size;
+       unsigned long flags;
+       unsigned int cpu;
+       struct cpumask cpu_mask;
+       struct ipu_thread_data *data = (struct ipu_thread_data *)argv;
+
+       thread_id++;
+       curr_thread_id = thread_id;
+       sched_setscheduler(current, SCHED_FIFO, &param);
+
+       if (!data->is_vdoa) {
+               cpu = cpumask_first(cpu_online_mask);
+               cpumask_set_cpu(cpu, &cpu_mask);
+               ret = sched_setaffinity(data->ipu->thread[data->id]->pid,
+                       &cpu_mask);
+               if (ret < 0) {
+                       pr_err("%s: sched_setaffinity fail:%d.\n", __func__, ret);
+               }
+               pr_debug("%s: sched_setaffinity cpu:%d.\n", __func__, cpu);
+       }
+
+       while (!kthread_should_stop()) {
+               int split_fail = 0;
+               int split_parent;
+               int split_child;
+
+               wait_event(thread_waitq, find_task(&tsk, curr_thread_id));
+
+               if (!tsk) {
+                       pr_err("thread:%d can not find task.\n",
+                               curr_thread_id);
+                       continue;
+               }
+
+               /* note: other threads run split child task */
+               split_parent = need_split(tsk) && !tsk->parent;
+               split_child = need_split(tsk) && tsk->parent;
+               if (split_parent) {
+                       if ((tsk->set.split_mode == RL_SPLIT) ||
+                                (tsk->set.split_mode == UD_SPLIT))
+                               size = 2;
+                       else
+                               size = 4;
+                       ret = queue_split_task(tsk, sp_task, size);
+                       if (ret < 0) {
+                               split_fail = 1;
+                       } else {
+                               struct list_head *pos;
+
+                               spin_lock_irqsave(&ipu_task_list_lock, flags);
+
+                               sp_tsk0 = list_first_entry(&tsk->split_list,
+                                               struct ipu_task_entry, node);
+                               list_del(&sp_tsk0->node);
+
+                               list_for_each(pos, &tsk->split_list) {
+                                       struct ipu_task_entry *tmp;
+
+                                       tmp = list_entry(pos,
+                                               struct ipu_task_entry, node);
+                                       tmp->task_in_list = 1;
+                                       dev_dbg(tmp->dev,
+                                               "[0x%p] no-0x%x,id:%d sp_tsk "
+                                               "add_to_list.\n", tmp,
+                                               tmp->task_no, tmp->task_id);
+                               }
+                               /* add to global list */
+                               list_splice(&tsk->split_list, &ipu_task_list);
+
+                               spin_unlock_irqrestore(&ipu_task_list_lock,
+                                                                       flags);
+                               /* let the parent thread do the first sp_task */
+                               /* FIXME: ensure the correct sequence for split
+                                       4size: 5/6->9/a*/
+                               if (!sp_tsk0)
+                                       dev_err(tsk->dev,
+                                       "ERR: no-0x%x,can not get split_tsk0\n",
+                                       tsk->task_no);
+                               wake_up(&thread_waitq);
+                               get_res_do_task(sp_tsk0);
+                               dev_dbg(sp_tsk0->dev,
+                                       "thread:%d complete tsk no:0x%x.\n",
+                                       curr_thread_id, sp_tsk0->task_no);
+                               ret = atomic_read(&req_cnt);
+                               if (ret > 0) {
+                                       wake_up(&res_waitq);
+                                       dev_dbg(sp_tsk0->dev,
+                                       "sp_tsk0 sche thread:%d no:0x%x,"
+                                       "req_cnt:%d\n", curr_thread_id,
+                                       sp_tsk0->task_no, ret);
+                                       /* For other threads to get_res */
+                                       schedule();
+                               }
+                       }
+               } else
+                       get_res_do_task(tsk);
+
+               /* wait for all 4 sp_task finished here or timeout
+                       and then release all resources */
+               if (split_parent && !split_fail)
+                       wait_split_task_complete(tsk, sp_task, size);
+
+               if (!split_child) {
+                       atomic_inc(&tsk->done);
+                       wake_up(&tsk->task_waitq);
+               }
+
+               dev_dbg(tsk->dev, "thread:%d complete tsk no:0x%x-[0x%p].\n",
+                               curr_thread_id, tsk->task_no, tsk);
+               ret = atomic_read(&req_cnt);
+               if (ret > 0) {
+                       wake_up(&res_waitq);
+                       dev_dbg(tsk->dev, "sche thread:%d no:0x%x,req_cnt:%d\n",
+                               curr_thread_id, tsk->task_no, ret);
+                       /* note: give cpu to other threads to get_res */
+                       schedule();
+               }
+
+               kref_put(&tsk->refcount, task_mem_free);
+       }
+
+       pr_info("ERR %s exit.\n", __func__);
+       return 0;
+}
+
+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;
+       dump_task_info(tsk);
+
+       kref_put(&tsk->refcount, task_mem_free);
+       if (ret != 0)
+               pr_debug("%s ret:%d.\n", __func__, ret);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_check_task);
+
+int ipu_queue_task(struct ipu_task *task)
+{
+       struct ipu_task_entry *tsk;
+       unsigned long flags;
+       int ret;
+       u32 tmp_task_no;
+       DECLARE_PERF_VAR;
+
+       tsk = create_task_entry(task);
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
+
+       CHECK_PERF(&tsk->ts_queue);
+       ret = prepare_task(tsk);
+       if (ret < 0)
+               goto done;
+
+       if (need_split(tsk)) {
+               CHECK_PERF(&tsk->ts_dotask);
+               CHECK_PERF(&tsk->ts_waitirq);
+               CHECK_PERF(&tsk->ts_inirq);
+               CHECK_PERF(&tsk->ts_wakeup);
+       }
+
+       /* task_no last four bits for split task type*/
+       tmp_task_no = atomic_inc_return(&frame_no);
+       tsk->task_no = tmp_task_no << 4;
+       init_waitqueue_head(&tsk->task_waitq);
+
+       spin_lock_irqsave(&ipu_task_list_lock, flags);
+       list_add_tail(&tsk->node, &ipu_task_list);
+       tsk->task_in_list = 1;
+       dev_dbg(tsk->dev, "[0x%p,no-0x%x] list_add_tail\n", tsk, tsk->task_no);
+       spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+       wake_up(&thread_waitq);
+
+       ret = wait_event_timeout(tsk->task_waitq, atomic_read(&tsk->done),
+                                               msecs_to_jiffies(tsk->timeout));
+       if (0 == ret) {
+               /* note: the timeout should larger than the internal timeout!*/
+               ret = -ETIMEDOUT;
+               dev_err(tsk->dev, "ERR: [0x%p] no-0x%x, timeout:%dms!\n",
+                               tsk, tsk->task_no, tsk->timeout);
+       } else {
+               if (STATE_OK != tsk->state) {
+                       dev_err(tsk->dev, "ERR: [0x%p] no-0x%x,state %d: %s\n",
+                               tsk, tsk->task_no, tsk->state,
+                               state_msg[tsk->state].msg);
+                       ret = -ECANCELED;
+               } else
+                       ret = 0;
+       }
+
+       spin_lock_irqsave(&ipu_task_list_lock, flags);
+       if (tsk->task_in_list) {
+               list_del(&tsk->node);
+               tsk->task_in_list = 0;
+               dev_dbg(tsk->dev, "[0x%p] no:0x%x list_del\n",
+                               tsk, tsk->task_no);
+       }
+       spin_unlock_irqrestore(&ipu_task_list_lock, flags);
+
+#ifdef DBG_IPU_PERF
+       CHECK_PERF(&tsk->ts_rel);
+       PRINT_TASK_STATISTICS;
+       if (ts_frame_avg == 0)
+               ts_frame_avg = ts_frame.tv_nsec / NSEC_PER_USEC +
+                               ts_frame.tv_sec * USEC_PER_SEC;
+       else
+               ts_frame_avg = (ts_frame_avg + ts_frame.tv_nsec / NSEC_PER_USEC
+                               + ts_frame.tv_sec * USEC_PER_SEC)/2;
+       if (timespec_compare(&ts_frame, &ts_frame_max) > 0)
+               ts_frame_max = ts_frame;
+
+       atomic_inc(&frame_cnt);
+
+       if ((atomic_read(&frame_cnt) %  1000) == 0)
+               pr_debug("ipu_dev: max frame time:%ldus, avg frame time:%dus,"
+                       "frame_cnt:%d\n", ts_frame_max.tv_nsec / NSEC_PER_USEC
+                       + ts_frame_max.tv_sec * USEC_PER_SEC,
+                       ts_frame_avg, atomic_read(&frame_cnt));
+#endif
+done:
+       if (ret < 0)
+               dev_err(tsk->dev, "ERR: no-0x%x,ipu_queue_task err:%d\n",
+                               tsk->task_no, ret);
+
+       kref_put(&tsk->refcount, task_mem_free);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_queue_task);
+
+static int mxc_ipu_open(struct inode *inode, struct file *file)
+{
+       file->private_data = (void *)atomic_inc_return(&file_index);
+       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 | GFP_KERNEL);
+                       if (mem->cpu_addr == NULL) {
+                               kfree(mem);
+                               return -ENOMEM;
+                       }
+                       mem->file_index = file->private_data;
+                       mutex_lock(&ipu_alloc_lock);
+                       list_add(&mem->list, &ipu_alloc_list);
+                       mutex_unlock(&ipu_alloc_lock);
+
+                       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;
+                       mutex_lock(&ipu_alloc_lock);
+                       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;
+                               }
+                       }
+                       mutex_unlock(&ipu_alloc_lock);
+                       if (0 == ret)
+                               dev_dbg(ipu_dev, "free %d bytes @ 0x%08X\n",
+                                       mem->size, mem->phy_addr);
+
+                       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;
+
+       mutex_lock(&ipu_alloc_lock);
+       list_for_each_entry(mem, &ipu_alloc_list, list) {
+               if (offset == mem->phy_addr) {
+                       found = true;
+                       len = mem->size;
+                       break;
+               }
+       }
+       mutex_unlock(&ipu_alloc_lock);
+       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)
+{
+       struct ipu_alloc_list *mem;
+       struct ipu_alloc_list *n;
+
+       mutex_lock(&ipu_alloc_lock);
+       list_for_each_entry_safe(mem, n, &ipu_alloc_list, list) {
+               if ((mem->cpu_addr != 0) &&
+                       (file->private_data == mem->file_index)) {
+                       list_del(&mem->list);
+                       dma_free_coherent(ipu_dev,
+                                         mem->size,
+                                         mem->cpu_addr,
+                                         mem->phy_addr);
+                       dev_dbg(ipu_dev, "rel-free %d bytes @ 0x%08X\n",
+                               mem->size, mem->phy_addr);
+                       kfree(mem);
+               }
+       }
+       mutex_unlock(&ipu_alloc_lock);
+       atomic_dec(&file_index);
+
+       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;
+       static int idx;
+       static struct ipu_thread_data thread_data[5];
+
+       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);
+
+               mutex_init(&ipu_ch_tbl.lock);
+       }
+       max_ipu_no = ++id;
+       ipu->rot_dma[0].size = 0;
+       ipu->rot_dma[1].size = 0;
+
+       thread_data[idx].ipu = ipu;
+       thread_data[idx].id = 0;
+       thread_data[idx].is_vdoa = 0;
+       ipu->thread[0] = kthread_run(ipu_task_thread, &thread_data[idx++],
+                                       "ipu%d_task", id);
+       if (IS_ERR(ipu->thread[0])) {
+               ret = PTR_ERR(ipu->thread[0]);
+               goto kthread0_fail;
+       }
+
+       thread_data[idx].ipu = ipu;
+       thread_data[idx].id = 1;
+       thread_data[idx].is_vdoa = 0;
+       ipu->thread[1] = kthread_run(ipu_task_thread, &thread_data[idx++],
+                               "ipu%d_task", 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);
+       }
+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)
+{
+       int i;
+
+       kthread_stop(ipu->thread[0]);
+       kthread_stop(ipu->thread[1]);
+       for (i = 0; i < 2; i++) {
+               if (ipu->rot_dma[i].vaddr)
+                       dma_free_coherent(ipu_dev,
+                               ipu->rot_dma[i].size,
+                               ipu->rot_dma[i].vaddr,
+                               ipu->rot_dma[i].paddr);
+       }
+
+       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 (file)
index 0000000..09babc6
--- /dev/null
@@ -0,0 +1,1962 @@
+/*
+ * Copyright 2005-2013 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/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <asm/atomic.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.h"
+
+struct dp_csc_param_t {
+       int mode;
+       void *coeff;
+};
+
+#define SYNC_WAVE 0
+#define NULL_WAVE (-1)
+#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
+
+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, 1, 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, 12, 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;
+       } else if (channel == MEM_BG_SYNC) {
+               reg = ipu_cm_read(ipu, IPU_SRM_PRI2) | 0x8;
+               ipu_cm_write(ipu, reg, IPU_SRM_PRI2);
+       }
+
+       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_prepare_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);
+
+               if (ipu_is_channel_busy(ipu, MEM_BG_SYNC)) {
+                       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);
+       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));
+       }
+}
+
+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;
+       uint32_t h_total, v_total;
+       int map;
+       int ret;
+       struct clk *ldb_di0_clk, *ldb_di1_clk;
+       struct clk *di_parent;
+
+       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_sel[disp]);
+       if (!di_parent) {
+               dev_err(ipu->dev, "get di clk parent fail\n");
+               return -EINVAL;
+       }
+       ldb_di0_clk = clk_get(ipu->dev, "ldb_di0");
+       if (IS_ERR(ldb_di0_clk)) {
+               dev_err(ipu->dev, "clk_get di0 failed");
+               return PTR_ERR(ldb_di0_clk);
+       }
+       ldb_di1_clk = clk_get(ipu->dev, "ldb_di1");
+       if (IS_ERR(ldb_di1_clk)) {
+               dev_err(ipu->dev, "clk_get di1 failed");
+               return PTR_ERR(ldb_di1_clk);
+       }
+
+       if (ldb_di0_clk == di_parent || ldb_di1_clk == di_parent) {
+               /* if di clk parent is tve/ldb, then keep it;*/
+               dev_dbg(ipu->dev, "use special clk parent\n");
+               ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->di_clk[disp]);
+               if (ret) {
+                       dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+                       return ret;
+               }
+               clk_put(ldb_di0_clk);
+               clk_put(ldb_di1_clk);
+       } else {
+               /* try ipu clk first*/
+               dev_dbg(ipu->dev, "try ipu internal clk\n");
+               ret = clk_set_parent(ipu->pixel_clk_sel[disp], ipu->ipu_clk);
+               if (ret) {
+                       dev_err(ipu->dev, "set pixel clk error:%d\n", ret);
+                       return ret;
+               }
+               rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+               dev_dbg(ipu->dev, "rounded pix clk:%d\n", rounded_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");
+
+                       rounded_pixel_clk =
+                               clk_round_rate(ipu->di_clk[disp], pixel_clk);
+                       ret = clk_set_rate(ipu->di_clk[disp],
+                                               rounded_pixel_clk);
+                       if (ret) {
+                               dev_err(ipu->dev,
+                                       "set di clk rate error:%d\n", ret);
+                               return ret;
+                       }
+                       dev_dbg(ipu->dev, "di clk:%d\n", rounded_pixel_clk);
+                       ret = clk_set_parent(ipu->pixel_clk_sel[disp],
+                                               ipu->di_clk[disp]);
+                       if (ret) {
+                               dev_err(ipu->dev,
+                                       "set pixel clk parent error:%d\n", ret);
+                               return ret;
+                       }
+               }
+       }
+       rounded_pixel_clk = clk_round_rate(ipu->pixel_clk[disp], pixel_clk);
+       dev_dbg(ipu->dev, "round pixel clk:%d\n", rounded_pixel_clk);
+       ret = clk_set_rate(ipu->pixel_clk[disp], rounded_pixel_clk);
+       if (ret) {
+               dev_err(ipu->dev, "set pixel clk rate error:%d\n", ret);
+               return ret;
+       }
+       msleep(5);
+       /* Get integer portion of divider */
+       div = clk_get_rate(clk_get_parent(ipu->pixel_clk[disp])) / rounded_pixel_clk;
+       dev_dbg(ipu->dev, "div:%d\n", div);
+       if (!div) {
+               dev_err(ipu->dev, "invalid pixel clk div = 0\n");
+               return -EINVAL;
+       }
+
+
+       mutex_lock(&ipu->mutex_lock);
+
+       _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");
+               mutex_unlock(&ipu->mutex_lock);
+               return -EINVAL;
+       }
+
+       /*clear DI*/
+       di_gen = ipu_di_read(ipu, disp, DI_GENERAL);
+       di_gen &= (0x3 << 20);
+       ipu_di_write(ipu, disp, di_gen, DI_GENERAL);
+
+       if (sig.interlaced) {
+               if (g_ipu_hw_rev >= IPU_V3DEX) {
+                       /* 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, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+                       _ipu_dc_write_tmpl(ipu, 4, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+                       _ipu_dc_write_tmpl(ipu, 1, 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, WROD(0), 0, map, SYNC_WAVE, 4, 5, 0);
+                  _ipu_dc_write_tmpl(ipu, 7, WRG, 0, map, NULL_WAVE, 0, 0, 1);
+                  _ipu_dc_write_tmpl(ipu, 12, 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)));
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       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;
+
+       if ((disp != 0) || (disp != 1))
+               return;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+
+       mutex_unlock(&ipu->mutex_lock);
+}
+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);
+
+       /* 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;
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+       }
+
+       mutex_unlock(&ipu->mutex_lock);
+       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;
+
+       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);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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;
+
+       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);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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;
+
+       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);
+
+       mutex_lock(&ipu->mutex_lock);
+
+       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);
+
+       mutex_unlock(&ipu->mutex_lock);
+
+       _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;
+
+       _ipu_get(ipu);
+       mutex_lock(&ipu->mutex_lock);
+       ret = _ipu_disp_set_window_pos(ipu, channel, x_pos, y_pos);
+       mutex_unlock(&ipu->mutex_lock);
+       _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;
+
+       _ipu_get(ipu);
+       mutex_lock(&ipu->mutex_lock);
+       ret = _ipu_disp_get_window_pos(ipu, channel, x_pos, y_pos);
+       mutex_unlock(&ipu->mutex_lock);
+       _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 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 (file)
index 0000000..2129f04
--- /dev/null
@@ -0,0 +1,881 @@
+/*
+ * Copyright 2005-2013 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/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include "ipu_param_mem.h"
+#include "ipu_regs.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);
+       dev_dbg(ipu->dev, "VDI_C = \t0x%08X\n", reg);
+}
+
+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_VDI_MEM:
+               ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_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_VDI_MEM:
+               ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_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;
+       uint32_t pix_per_burst;
+
+       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;
+               pix_per_burst = 32;
+        } else {
+               pixel_fmt = VDI_C_CH_420;
+               pix_per_burst = 64;
+       }
+
+       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;
+
+       case MEM_VDI_MEM:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE2_OFFSET;
+               break;
+       case MEM_VDI_MEM_P:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE1_OFFSET;
+               reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
+               break;
+       case MEM_VDI_MEM_N:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE3_OFFSET;
+               reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
+               break;
+       default:
+               break;
+       }
+       ipu_vdi_write(ipu, reg, VDI_C);
+
+       if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_TOP)
+               _ipu_vdi_set_top_field_man(ipu, true);
+       else if (params->mem_prp_vf_mem.field_fmt == IPU_DEINTERLACE_FIELD_BOTTOM)
+               _ipu_vdi_set_top_field_man(ipu, false);
+
+       _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) ||
+               (params->mem_prp_vf_mem.outv_resize_ratio >=
+                                               IC_RSZ_MAX_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) ||
+               (params->mem_prp_vf_mem.outh_resize_ratio >=
+                                               IC_RSZ_MAX_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) ||
+               (params->mem_prp_enc_mem.outv_resize_ratio >=
+                                               IC_RSZ_MAX_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) ||
+               (params->mem_prp_enc_mem.outh_resize_ratio >=
+                                               IC_RSZ_MAX_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) ||
+               (params->mem_pp_mem.outv_resize_ratio >=
+                                               IC_RSZ_MAX_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) ||
+               (params->mem_pp_mem.outh_resize_ratio >=
+                                               IC_RSZ_MAX_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;
+       } else if (dma_chan == 5) {     /* VDIC OUTPUT - CB7 */
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB7_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_dbg(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 (file)
index 0000000..f0e2f17
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * Copyright 2005-2013 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/bitrev.h>
+#include <linux/types.h>
+
+#include "ipu_prv.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, "EBA0 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
+       dev_dbg(ipu->dev, "EBA1 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
+       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, "scan_order %d\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
+       dev_dbg(ipu->dev, "uv_stride %d\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
+       dev_dbg(ipu->dev, "u_offset 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
+       dev_dbg(ipu->dev, "v_offset 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
+
+       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 fill_cpmem(struct ipu_soc *ipu, int ch, struct ipu_ch_param *params)
+{
+       int i, w;
+       void *addr = ipu_ch_param_addr(ipu, ch);
+
+       /* 2 words, 5 valid data */
+       for (w = 0; w < 2; w++) {
+               for (i = 0; i < 5; i++) {
+                       writel(params->word[w].data[i], addr);
+                       addr += 4;
+               }
+               addr += 12;
+       }
+}
+
+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->vdoa_en) {
+               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 {
+               /* note: for vdoa+vdi- ch8/9/10, always use band mode */
+               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_16:
+               /* Represents 16-bit generic data */
+               ipu_ch_param_set_field(&params, 0, 107, 3, 3);  /* bits/pixel */
+               ipu_ch_param_set_field(&params, 1, 85, 4, 6);   /* pix format */
+               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* 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)) {
+                       if (ipu->vdoa_en) {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+                       } else {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+                       }
+               } 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_YUV444P:
+               /* BPP & pixel format */
+               ipu_ch_param_set_field(&params, 1, 85, 4, 0);   /* pix format */
+               ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+               uv_stride = stride;
+               u_offset = (u == 0) ? stride * height : u;
+               v_offset = (v == 0) ? 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)) {
+                       if (ipu->vdoa_en) {
+                                /* one field buffer, memory width 64bits */
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 63);
+                       } else {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+                                /* top/bottom field in one buffer*/
+                               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));
+       fill_cpmem(ipu, ch, &params);
+       if (addr2) {
+               sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+               if (sub_ch <= 0)
+                       return;
+
+               ipu_ch_param_set_field(&params, 1, 0, 29, addr2 >> 3);
+               ipu_ch_param_set_field(&params, 1, 29, 29, 0);
+               if (addr2%8)
+                       dev_warn(ipu->dev,
+                                "IDMAC%d's sub-CPMEM entry%d EBA0 is not "
+                                "8-byte aligned\n", ch, sub_ch);
+
+               dev_dbg(ipu->dev, "initializing idma ch %d @ %p sub cpmem\n", ch,
+                                       ipu_ch_param_addr(ipu, sub_ch));
+               fill_cpmem(ipu, sub_ch, &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 old_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_16:
+       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_YUV444P:
+               uv_stride = stride;
+               u_offset = stride * (height - vertical_offset - 1) +
+                                       (stride - horizontal_offset) +
+                                       (uv_stride * vertical_offset) +
+                                       horizontal_offset;
+               v_offset = u_offset + uv_stride * height;
+               u_fix = u ? (u + (uv_stride * vertical_offset) +
+                                       horizontal_offset -
+                                       (stride * vertical_offset) -
+                                       (horizontal_offset)) :
+                                       u_offset;
+               v_fix = v ? (v + (uv_stride * vertical_offset) +
+                                       horizontal_offset -
+                                       (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);
+
+       old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22);
+       if (old_offset != u_offset / 8)
+               ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22, u_offset / 8);
+       old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22);
+       if (old_offset != v_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;
+       old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22);
+       if (old_offset != u_offset / 8)
+               ipu_ch_param_mod_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 46, 22, u_offset / 8);
+       old_offset = ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, sub_ch), 0, 68, 22);
+       if (old_offset != v_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);
+};
+
+static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
+                       uint32_t ch, uint32_t band_height)
+{
+       int32_t sub_ch = 0;
+
+       ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
+                                       0, 114, 3, band_height - 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),
+                                       0, 114, 3, band_height - 1);
+
+       dev_dbg(ipu->dev, "BNDM 0x%x, ",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
+}
+#endif
diff --git a/drivers/mxc/ipu3/ipu_pixel_clk.c b/drivers/mxc/ipu3/ipu_pixel_clk.c
new file mode 100644 (file)
index 0000000..c1f6f7d
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2013 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_pixel_clk.c
+ *
+ * @brief IPU pixel clock implementation
+ *
+ * @ingroup IPU
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu-v3.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+
+ /*
+ * muxd clock implementation
+ */
+struct clk_di_mux {
+       struct clk_hw hw;
+       u8              ipu_id;
+       u8              di_id;
+       u8              flags;
+       u8              index;
+};
+#define to_clk_di_mux(_hw) container_of(_hw, struct clk_di_mux, hw)
+
+static int _ipu_pixel_clk_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_di_mux *mux = to_clk_di_mux(hw);
+       struct ipu_soc *ipu = ipu_get_soc(mux->ipu_id);
+       u32 di_gen;
+
+       di_gen = ipu_di_read(ipu, mux->di_id, DI_GENERAL);
+       if (index == 0)
+               /* ipu1_clk or ipu2_clk internal clk */
+               di_gen &= ~DI_GEN_DI_CLK_EXT;
+       else
+               di_gen |= DI_GEN_DI_CLK_EXT;
+
+       ipu_di_write(ipu, mux->di_id, di_gen, DI_GENERAL);
+       mux->index = index;
+       pr_debug("ipu_pixel_clk: di_clk_ext:0x%x, di_gen reg:0x%x.\n",
+                       !(di_gen & DI_GEN_DI_CLK_EXT), di_gen);
+       return 0;
+}
+
+static u8 _ipu_pixel_clk_get_parent(struct clk_hw *hw)
+{
+       struct clk_di_mux *mux = to_clk_di_mux(hw);
+
+       return mux->index;
+}
+
+const struct clk_ops clk_mux_di_ops = {
+       .get_parent = _ipu_pixel_clk_get_parent,
+       .set_parent = _ipu_pixel_clk_set_parent,
+};
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+               const char **parent_names, u8 num_parents, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_mux_flags)
+{
+       struct clk_di_mux *mux;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       mux = kzalloc(sizeof(struct clk_di_mux), GFP_KERNEL);
+       if (!mux)
+               return ERR_PTR(-ENOMEM);
+
+       init.name = name;
+       init.ops = &clk_mux_di_ops;
+       init.flags = flags;
+       init.parent_names = parent_names;
+       init.num_parents = num_parents;
+
+       mux->ipu_id = ipu_id;
+       mux->di_id = di_id;
+       mux->flags = clk_mux_flags | CLK_SET_RATE_PARENT;
+       mux->hw.init = &init;
+
+       clk = clk_register(dev, &mux->hw);
+       if (IS_ERR(clk))
+               kfree(mux);
+
+       return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_div {
+       struct clk_hw hw;
+       u8              ipu_id;
+       u8              di_id;
+       u8              flags;
+};
+#define to_clk_di_div(_hw) container_of(_hw, struct clk_di_div, hw)
+
+static unsigned long _ipu_pixel_clk_div_recalc_rate(struct clk_hw *hw,
+                                       unsigned long parent_rate)
+{
+       struct clk_di_div *di_div = to_clk_di_div(hw);
+       struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+       u32 div;
+       u64 final_rate = (unsigned long long)parent_rate * 16;
+
+       _ipu_get(ipu);
+       div = ipu_di_read(ipu, di_div->di_id, DI_BS_CLKGEN0);
+       _ipu_put(ipu);
+       pr_debug("ipu_di%d read BS_CLKGEN0 div:%d, final_rate:%lld, prate:%ld\n",
+                       di_div->di_id, div, final_rate, parent_rate);
+
+       if (div == 0)
+               return 0;
+       do_div(final_rate, div);
+
+       return (unsigned long)final_rate;
+}
+
+static long _ipu_pixel_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long *parent_clk_rate)
+{
+       u64 div, final_rate;
+       u32 remainder;
+       u64 parent_rate = (unsigned long long)(*parent_clk_rate) * 16;
+
+       /*
+        * Calculate divider
+        * Fractional part is 4 bits,
+        * so simply multiply by 2^4 to get fractional part.
+        */
+       div = parent_rate;
+       remainder = do_div(div, rate);
+       /* Round the divider value */
+       if (remainder > (rate/2))
+               div++;
+       if (div < 0x10)            /* Min DI disp clock divider is 1 */
+               div = 0x10;
+       if (div & ~0xFEF)
+               div &= 0xFF8;
+       else {
+               /* Round up divider if it gets us closer to desired pix clk */
+               if ((div & 0xC) == 0xC) {
+                       div += 0x10;
+                       div &= ~0xF;
+               }
+       }
+       final_rate = parent_rate;
+       do_div(final_rate, div);
+
+       return final_rate;
+}
+
+static int _ipu_pixel_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+                           unsigned long parent_clk_rate)
+{
+       struct clk_di_div *di_div = to_clk_di_div(hw);
+       struct ipu_soc *ipu = ipu_get_soc(di_div->ipu_id);
+       u64 div, parent_rate;
+       u32 remainder;
+
+       parent_rate = (unsigned long long)parent_clk_rate * 16;
+       div = parent_rate;
+       remainder = do_div(div, rate);
+       /* Round the divider value */
+       if (remainder > (rate/2))
+               div++;
+
+       /* Round up divider if it gets us closer to desired pix clk */
+       if ((div & 0xC) == 0xC) {
+               div += 0x10;
+               div &= ~0xF;
+       }
+       if (div > 0x1000)
+               pr_err("Overflow, di:%d, DI_BS_CLKGEN0 div:0x%x\n",
+                               di_div->di_id, (u32)div);
+       _ipu_get(ipu);
+       ipu_di_write(ipu, di_div->di_id, (u32)div, DI_BS_CLKGEN0);
+
+       /* Setup pixel clock timing */
+       /* FIXME: needs to be more flexible */
+       /* Down time is half of period */
+       ipu_di_write(ipu, di_div->di_id, ((u32)div / 16) << 16, DI_BS_CLKGEN1);
+       _ipu_put(ipu);
+
+       return 0;
+}
+
+static struct clk_ops clk_div_ops = {
+       .recalc_rate = _ipu_pixel_clk_div_recalc_rate,
+       .round_rate = _ipu_pixel_clk_div_round_rate,
+       .set_rate = _ipu_pixel_clk_div_set_rate,
+};
+
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_div_flags)
+{
+       struct clk_di_div *di_div;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       di_div = kzalloc(sizeof(struct clk_di_div), GFP_KERNEL);
+       if (!di_div)
+               return ERR_PTR(-ENOMEM);
+
+       /* struct clk_di_div assignments */
+       di_div->ipu_id = ipu_id;
+       di_div->di_id = di_id;
+       di_div->flags = clk_div_flags;
+
+       init.name = name;
+       init.ops = &clk_div_ops;
+       init.flags = flags | CLK_SET_RATE_PARENT;
+       init.parent_names = parent_name ? &parent_name : NULL;
+       init.num_parents = parent_name ? 1 : 0;
+
+       di_div->hw.init = &init;
+
+       clk = clk_register(dev, &di_div->hw);
+       if (IS_ERR(clk))
+               kfree(clk);
+
+       return clk;
+}
+
+/*
+ * Gated clock implementation
+ */
+struct clk_di_gate {
+       struct clk_hw hw;
+       u8              ipu_id;
+       u8              di_id;
+       u8              flags;
+};
+#define to_clk_di_gate(_hw) container_of(_hw, struct clk_di_gate, hw)
+
+static int _ipu_pixel_clk_enable(struct clk_hw *hw)
+{
+       struct clk_di_gate *gate = to_clk_di_gate(hw);
+       struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+       u32 disp_gen;
+
+       disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+       disp_gen |= gate->di_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_hw *hw)
+{
+       struct clk_di_gate *gate = to_clk_di_gate(hw);
+       struct ipu_soc *ipu = ipu_get_soc(gate->ipu_id);
+       u32 disp_gen;
+
+       disp_gen = ipu_cm_read(ipu, IPU_DISP_GEN);
+       disp_gen &= gate->di_id ? ~DI1_COUNTER_RELEASE : ~DI0_COUNTER_RELEASE;
+       ipu_cm_write(ipu, disp_gen, IPU_DISP_GEN);
+
+}
+
+
+static struct clk_ops clk_gate_di_ops = {
+       .enable = _ipu_pixel_clk_enable,
+       .disable = _ipu_pixel_clk_disable,
+};
+
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_gate_flags)
+{
+       struct clk_di_gate *gate;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       gate = kzalloc(sizeof(struct clk_di_gate), GFP_KERNEL);
+       if (!gate)
+               return ERR_PTR(-ENOMEM);
+
+       gate->ipu_id = ipu_id;
+       gate->di_id = di_id;
+       gate->flags = clk_gate_flags;
+
+       init.name = name;
+       init.ops = &clk_gate_di_ops;
+       init.flags = flags | CLK_SET_RATE_PARENT;
+       init.parent_names = parent_name ? &parent_name : NULL;
+       init.num_parents = parent_name ? 1 : 0;
+
+       gate->hw.init = &init;
+
+       clk = clk_register(dev, &gate->hw);
+       if (IS_ERR(clk))
+               kfree(clk);
+
+       return clk;
+}
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
new file mode 100644 (file)
index 0000000..5956321
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2005-2013 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/clkdev.h>
+#include <linux/device.h>
+#include <linux/fsl_devices.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+
+#define MXC_IPU_MAX_NUM                2
+#define MXC_DI_NUM_PER_IPU     2
+
+/* Globals */
+extern int dmfc_type_setup;
+
+#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
+};
+
+enum imx_ipu_type {
+       IMX6Q_IPU,
+};
+
+struct ipu_pltfm_data {
+       u32 id;
+       u32 devtype;
+       int (*init) (int);
+       void (*pg) (int);
+
+       /*
+        * Bypass reset to avoid display channel being
+        * stopped by probe since it may starts to work
+        * in bootloader.
+        */
+       bool bypass_reset;
+};
+
+struct ipu_soc {
+       bool online;
+       struct ipu_pltfm_data *pdata;
+
+       /*clk*/
+       struct clk *ipu_clk;
+       struct clk *di_clk[2];
+       struct clk *di_clk_sel[2];
+       struct clk *pixel_clk[2];
+       struct clk *pixel_clk_sel[2];
+       struct clk *csi_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 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 int_reg_spin_lock;
+       spinlock_t rdy_reg_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;
+       struct completion csi_comp;
+
+       struct rot_mem {
+               void *vaddr;
+               dma_addr_t paddr;
+               int size;
+       } rot_dma[2];
+
+       int     vdoa_en;
+       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);
+int _ipu_csi_set_mipi_di(struct ipu_soc *ipu, uint32_t num, uint32_t di_val, 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_csi_wait4eof(struct ipu_soc *ipu, ipu_channel_t channel);
+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);
+
+struct clk *clk_register_mux_pix_clk(struct device *dev, const char *name,
+               const char **parent_names, u8 num_parents, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_mux_flags);
+struct clk *clk_register_div_pix_clk(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_div_flags);
+struct clk *clk_register_gate_pix_clk(struct device *dev, const char *name,
+               const char *parent_name, unsigned long flags,
+               u8 ipu_id, u8 di_id, u8 clk_gate_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 (file)
index 0000000..94c587e
--- /dev/null
@@ -0,0 +1,719 @@
+/*
+ * Copyright (C) 2005-2013 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__
+
+enum imx_ipu_rev {
+       IPU_V3DEX = 2,
+       IPU_V3M,
+       IPU_V3H,
+};
+
+/*
+ * hw_rev 2: IPUV3DEX
+ * hw_rev 3: IPUV3M
+ * hw_rev 4: IPUV3H
+ */
+extern int g_ipu_hw_rev;
+
+#define IPU_MAX_VDI_IN_WIDTH   ({g_ipu_hw_rev >= 3 ? \
+                                  (968) : \
+                                  (720); })
+#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_VDOA = 0x00008000,
+       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_VDOA = 0x20000000,
+       FS_VDOA_DEST_SEL_MASK = 0x00030000,
+       FS_VDOA_DEST_SEL_VDI = 0x00020000,
+       FS_VDOA_DEST_SEL_IC = 0x00010000,
+       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_RSZ_MAX_RESIZE_RATIO = 0x00004000,
+
+       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_BURST_SIZE_MASK = 0xF,
+       VDI_C_BURST_SIZE1_OFFSET = 4,
+       VDI_C_BURST_SIZE2_OFFSET = 8,
+       VDI_C_BURST_SIZE3_OFFSET = 12,
+       VDI_C_VWM1_SET_1 = 0x00000000,
+       VDI_C_VWM1_SET_2 = 0x00010000,
+       VDI_C_VWM1_CLR_2 = 0x00080000,
+       VDI_C_VWM3_SET_1 = 0x00000000,
+       VDI_C_VWM3_SET_2 = 0x00400000,
+       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/drivers/mxc/ipu3/vdoa.c b/drivers/mxc/ipu3/vdoa.c
new file mode 100644 (file)
index 0000000..c6cb9f1
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * Copyright (C) 2012-2013 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 <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/genalloc.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "vdoa.h"
+/* 6band(3field* double buffer) * (width*2) * bandline(8)
+       = 6x1024x2x8 = 96k or 72k(1.5byte) */
+#define MAX_VDOA_IRAM_SIZE     (1024*96)
+#define VDOA_IRAM_SIZE         (1024*72)
+
+#define VDOAC_BAND_HEIGHT_32LINES      (32)
+#define VDOAC_BAND_HEIGHT_16LINES      (16)
+#define VDOAC_BAND_HEIGHT_8LINES       (8)
+#define VDOAC_THREE_FRAMES             (0x1 << 2)
+#define VDOAC_SYNC_BAND_MODE           (0x1 << 3)
+#define VDOAC_SCAN_ORDER_INTERLACED    (0x1 << 4)
+#define VDOAC_PFS_YUYV                 (0x1 << 5)
+#define VDOAC_IPU_SEL_1                        (0x1 << 6)
+#define VDOAFP_FH_MASK                 (0x1FFF)
+#define VDOAFP_FH_SHIFT                        (16)
+#define VDOAFP_FW_MASK                 (0x3FFF)
+#define VDOAFP_FW_SHIFT                        (0)
+#define VDOASL_VSLY_MASK               (0x3FFF)
+#define VDOASL_VSLY_SHIFT              (16)
+#define VDOASL_ISLY_MASK               (0x7FFF)
+#define VDOASL_ISLY_SHIFT              (0)
+#define VDOASRR_START_XFER             (0x2)
+#define VDOASRR_SWRST                  (0x1)
+#define VDOAIEIST_TRANSFER_ERR         (0x2)
+#define VDOAIEIST_TRANSFER_END         (0x1)
+
+#define        VDOAC           (0x0)   /* Control Register */
+#define        VDOASRR         (0x4)   /* Start and Reset Register */
+#define        VDOAIE          (0x8)   /* Interrupt Enable Register */
+#define        VDOAIST         (0xc)   /* Interrupt Status Register */
+#define        VDOAFP          (0x10)  /* Frame Parameters Register */
+#define        VDOAIEBA00      (0x14)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA01      (0x18)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA02      (0x1c)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA10      (0x20)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA11      (0x24)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA12      (0x28)  /* External Buffer n Frame m Address Register */
+#define        VDOASL          (0x2c)  /* IPU Stride Line Register */
+#define        VDOAIUBO        (0x30)  /* IPU Chroma Buffer Offset Register */
+#define        VDOAVEBA0       (0x34)  /* External Buffer m Address Register */
+#define        VDOAVEBA1       (0x38)  /* External Buffer m Address Register */
+#define        VDOAVEBA2       (0x3c)  /* External Buffer m Address Register */
+#define        VDOAVUBO        (0x40)  /* VPU Chroma Buffer Offset */
+#define        VDOASR          (0x44)  /* Status Register */
+#define        VDOATD          (0x48)  /* Test Debug Register */
+
+
+enum {
+       VDOA_INIT       = 0x1,
+       VDOA_GET        = 0x2,
+       VDOA_SETUP      = 0x4,
+       VDOA_GET_OBUF   = 0x8,
+       VDOA_START      = 0x10,
+       VDOA_INIRQ      = 0x20,
+       VDOA_STOP       = 0x40,
+       VDOA_PUT        = VDOA_INIT,
+};
+
+enum {
+       VDOA_NULL       = 0,
+       VDOA_FRAME      = 1,
+       VDOA_PREV_FIELD = 2,
+       VDOA_CURR_FIELD = 3,
+       VDOA_NEXT_FIELD = 4,
+};
+
+#define CHECK_STATE(expect, retcode)                                   \
+do {                                                                   \
+       if (!((expect) & vdoa->state)) {                                \
+               dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
+                               __func__, vdoa->state, (expect));       \
+               retcode;                                                \
+       }                                                               \
+} while (0)
+
+#define CHECK_NULL_PTR(ptr)                                            \
+do {                                                                   \
+       pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n",                   \
+                       vdoa, __func__, vdoa->state);                   \
+       if (NULL == (ptr)) {                                            \
+               pr_err("ERR vdoa: %s state:0x%x null ptr.\n",           \
+                               __func__, vdoa->state);                 \
+       }                                                               \
+} while (0)
+
+struct vdoa_info {
+       int             state;
+       struct device   *dev;
+       struct clk      *vdoa_clk;
+       void __iomem    *reg_base;
+       struct gen_pool *iram_pool;
+       unsigned long   iram_base;
+       unsigned long   iram_paddr;
+       int             irq;
+       int             field;
+       struct completion comp;
+};
+
+static struct vdoa_info *g_vdoa;
+static unsigned long iram_size;
+static DEFINE_MUTEX(vdoa_lock);
+
+static inline void vdoa_read_register(struct vdoa_info *vdoa,
+                               u32 reg, u32 *val)
+{
+       *val = ioread32(vdoa->reg_base + reg);
+       dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
+}
+
+static inline void vdoa_write_register(struct vdoa_info *vdoa,
+                               u32 reg, u32 val)
+{
+       iowrite32(val, vdoa->reg_base + reg);
+       dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
+}
+
+static void dump_registers(struct vdoa_info *vdoa)
+{
+       int i;
+       u32 data;
+
+       for (i = VDOAC; i < VDOATD; i += 4)
+               vdoa_read_register(vdoa, i, &data);
+}
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
+{
+       int     band_size;
+       int     total_band_size = 0;
+       int     ipu_stride;
+       u32     data;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return -EINVAL);
+       if (VDOA_GET == vdoa->state) {
+               dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
+                        params->width, params->height);
+               data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
+                       ((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
+                                1 : 0);
+               data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
+               data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
+               data |= params->pfs ? VDOAC_PFS_YUYV : 0;
+               data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
+               vdoa_write_register(vdoa, VDOAC, data);
+
+               data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
+                       ((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
+               vdoa_write_register(vdoa, VDOAFP, data);
+
+               ipu_stride = params->pfs ? params->width << 1 : params->width;
+               data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
+                                                       VDOASL_VSLY_SHIFT) |
+                       ((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
+               vdoa_write_register(vdoa, VDOASL, data);
+
+               dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
+               params->band_mode, params->band_lines, vdoa->iram_paddr);
+       }
+       /*
+        * band size    = (luma_per_line + chroma_per_line) * bandLines
+        *              = width * (3/2 or 2) * bandLines
+        * double buffer mode used.
+        */
+       if (params->pfs)
+               band_size = (params->width << 1) * params->band_lines;
+       else
+               band_size = ((params->width * 3) >> 1) *
+                                               params->band_lines;
+       if (params->interlaced) {
+               total_band_size = 6 * band_size; /* 3 frames*double buffer */
+               if (iram_size < total_band_size) {
+                       dev_err(vdoa->dev, "iram_size:0x%lx is smaller than "
+                               "request:0x%x!\n", iram_size, total_band_size);
+                       return -EINVAL;
+               }
+               if (params->vfield_buf.prev_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA00,
+                                                       vdoa->iram_paddr);
+                               vdoa_write_register(vdoa, VDOAIEBA10,
+                                                vdoa->iram_paddr + band_size);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA00,
+                                                       params->ieba0);
+                       vdoa_write_register(vdoa, VDOAVEBA0,
+                                       params->vfield_buf.prev_veba);
+                       vdoa->field = VDOA_PREV_FIELD;
+               }
+               if (params->vfield_buf.cur_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA01,
+                                        vdoa->iram_paddr + band_size * 2);
+                               vdoa_write_register(vdoa, VDOAIEBA11,
+                                        vdoa->iram_paddr + band_size * 3);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA01,
+                                                       params->ieba1);
+                       vdoa_write_register(vdoa, VDOAVEBA1,
+                                       params->vfield_buf.cur_veba);
+                       vdoa->field = VDOA_CURR_FIELD;
+               }
+               if (params->vfield_buf.next_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA02,
+                                        vdoa->iram_paddr + band_size * 4);
+                               vdoa_write_register(vdoa, VDOAIEBA12,
+                                        vdoa->iram_paddr + band_size * 5);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA02,
+                                                       params->ieba2);
+                       vdoa_write_register(vdoa, VDOAVEBA2,
+                                       params->vfield_buf.next_veba);
+                       vdoa->field = VDOA_NEXT_FIELD;
+                       vdoa_read_register(vdoa, VDOAC, &data);
+                       data |= VDOAC_THREE_FRAMES;
+                       vdoa_write_register(vdoa, VDOAC, data);
+               }
+
+               if (!params->pfs)
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                params->width * params->band_lines);
+               vdoa_write_register(vdoa, VDOAVUBO,
+                                params->vfield_buf.vubo);
+               dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
+       } else if (params->band_mode) {
+               /* used for progressive frame resize on PrP channel */
+               BUG(); /* currently not support */
+               /* progressvie frame: band mode */
+               vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
+               vdoa_write_register(vdoa, VDOAIEBA10,
+                                        vdoa->iram_paddr + band_size);
+               if (!params->pfs)
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                       params->width * params->band_lines);
+               dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
+       } else {
+               /* progressive frame: mem->mem, non-band mode */
+               vdoa->field = VDOA_FRAME;
+               vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
+               vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
+               vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
+               if (!params->pfs)
+                       /* note: iubo is relative value, based on ieba0 */
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                       params->width * params->height);
+       }
+       vdoa->state = VDOA_SETUP;
+       return 0;
+}
+
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
+{
+       u32     data;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_SETUP, return);
+       vdoa->state = VDOA_GET_OBUF;
+       memset(buf, 0, sizeof(*buf));
+
+       vdoa_read_register(vdoa, VDOAC, &data);
+       switch (vdoa->field) {
+       case VDOA_FRAME:
+       case VDOA_PREV_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
+               if (data & VDOAC_SYNC_BAND_MODE)
+                       vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
+               break;
+       case VDOA_CURR_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
+               vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
+               break;
+       case VDOA_NEXT_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
+               vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
+               break;
+       default:
+               BUG();
+               break;
+       }
+       if (!(data & VDOAC_PFS_YUYV))
+               vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
+}
+
+int vdoa_start(vdoa_handle_t handle, int timeout_ms)
+{
+       int ret;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
+       vdoa->state = VDOA_START;
+       init_completion(&vdoa->comp);
+       vdoa_write_register(vdoa, VDOAIST,
+                       VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+       vdoa_write_register(vdoa, VDOAIE,
+                       VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+
+       enable_irq(vdoa->irq);
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
+       dump_registers(vdoa);
+
+       ret = wait_for_completion_timeout(&vdoa->comp,
+                       msecs_to_jiffies(timeout_ms));
+
+       return ret > 0 ? 0 : -ETIMEDOUT;
+}
+
+void vdoa_stop(vdoa_handle_t handle)
+{
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_GET | VDOA_START | VDOA_INIRQ, return);
+       vdoa->state = VDOA_STOP;
+
+       disable_irq(vdoa->irq);
+
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+}
+
+void vdoa_get_handle(vdoa_handle_t *handle)
+{
+       struct vdoa_info *vdoa = g_vdoa;
+
+       CHECK_NULL_PTR(handle);
+       *handle = (vdoa_handle_t *)NULL;
+       CHECK_STATE(VDOA_INIT, return);
+       mutex_lock(&vdoa_lock);
+       clk_prepare_enable(vdoa->vdoa_clk);
+       vdoa->state = VDOA_GET;
+       vdoa->field = VDOA_NULL;
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+
+       *handle = (vdoa_handle_t *)vdoa;
+}
+
+void vdoa_put_handle(vdoa_handle_t *handle)
+{
+       struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_STOP, return);
+       if (vdoa != g_vdoa)
+               BUG();
+
+       clk_disable_unprepare(vdoa->vdoa_clk);
+       vdoa->state = VDOA_PUT;
+       *handle = (vdoa_handle_t *)NULL;
+       mutex_unlock(&vdoa_lock);
+}
+
+static irqreturn_t vdoa_irq_handler(int irq, void *data)
+{
+       u32 status, mask, val;
+       struct vdoa_info *vdoa = data;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_START, return IRQ_HANDLED);
+       vdoa->state = VDOA_INIRQ;
+       vdoa_read_register(vdoa, VDOAIST, &status);
+       vdoa_read_register(vdoa, VDOAIE, &mask);
+       val = status & mask;
+       vdoa_write_register(vdoa, VDOAIST, val);
+       if (VDOAIEIST_TRANSFER_ERR & val)
+               dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
+       if (VDOAIEIST_TRANSFER_END & val)
+               dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
+       if (0 == val) {
+               dev_err(vdoa->dev, "vdoa unknown irq!\n");
+               BUG();
+       }
+
+       complete(&vdoa->comp);
+       return IRQ_HANDLED;
+}
+
+/* IRAM Size in Kbytes, example:vdoa_iram_size=64, 64KBytes */
+static int __init vdoa_iram_size_setup(char *options)
+{
+       int ret;
+
+       ret = strict_strtoul(options, 0, &iram_size);
+       if (ret)
+               iram_size = 0;
+       else
+               iram_size *= SZ_1K;
+
+       return 1;
+}
+__setup("vdoa_iram_size=", vdoa_iram_size_setup);
+
+static const struct of_device_id imx_vdoa_dt_ids[] = {
+       { .compatible = "fsl,imx6q-vdoa", },
+       { /* sentinel */ }
+};
+
+static int vdoa_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct vdoa_info *vdoa;
+       struct resource *res;
+       struct resource *res_irq;
+       struct device   *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "can't get device resources\n");
+               return -ENOENT;
+       }
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res_irq) {
+               dev_err(dev, "failed to get irq resource\n");
+               return -ENOENT;
+       }
+
+       vdoa = devm_kzalloc(dev, sizeof(struct vdoa_info), GFP_KERNEL);
+       if (!vdoa)
+               return -ENOMEM;
+       vdoa->dev = dev;
+
+       vdoa->reg_base = devm_request_and_ioremap(&pdev->dev, res);
+       if (!vdoa->reg_base)
+               return -EBUSY;
+
+       vdoa->irq = res_irq->start;
+       ret = devm_request_irq(dev, vdoa->irq, vdoa_irq_handler, 0,
+                               "vdoa", vdoa);
+       if (ret) {
+               dev_err(dev, "can't claim irq %d\n", vdoa->irq);
+               return ret;
+       }
+       disable_irq(vdoa->irq);
+
+       vdoa->vdoa_clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(vdoa->vdoa_clk)) {
+               dev_err(dev, "failed to get vdoa_clk\n");
+               return PTR_ERR(vdoa->vdoa_clk);
+       }
+
+       vdoa->iram_pool = of_get_named_gen_pool(np, "iram", 0);
+       if (!vdoa->iram_pool) {
+               dev_err(&pdev->dev, "iram pool not available\n");
+               return -ENOMEM;
+       }
+
+       if ((iram_size == 0) || (iram_size > MAX_VDOA_IRAM_SIZE))
+               iram_size = VDOA_IRAM_SIZE;
+
+       vdoa->iram_base = gen_pool_alloc(vdoa->iram_pool, iram_size);
+       if (!vdoa->iram_base) {
+               dev_err(&pdev->dev, "unable to alloc iram\n");
+               return -ENOMEM;
+       }
+
+       vdoa->iram_paddr = gen_pool_virt_to_phys(vdoa->iram_pool,
+                                                vdoa->iram_base);
+
+       dev_dbg(dev, "iram_base:0x%lx,iram_paddr:0x%lx,size:0x%lx\n",
+                vdoa->iram_base, vdoa->iram_paddr, iram_size);
+
+       vdoa->state = VDOA_INIT;
+       dev_set_drvdata(dev, vdoa);
+       g_vdoa = vdoa;
+       dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
+       return 0;
+}
+
+static int vdoa_remove(struct platform_device *pdev)
+{
+       struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
+
+       gen_pool_free(vdoa->iram_pool, vdoa->iram_base, iram_size);
+       kfree(vdoa);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver vdoa_driver = {
+       .driver = {
+               .name = "mxc_vdoa",
+               .of_match_table = imx_vdoa_dt_ids,
+       },
+       .probe = vdoa_probe,
+       .remove = vdoa_remove,
+};
+
+static int __init vdoa_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&vdoa_driver);
+       if (err) {
+               pr_err("vdoa_driver register failed\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit vdoa_cleanup(void)
+{
+       platform_driver_unregister(&vdoa_driver);
+}
+
+module_init(vdoa_init);
+module_exit(vdoa_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/ipu3/vdoa.h b/drivers/mxc/ipu3/vdoa.h
new file mode 100644 (file)
index 0000000..b9482ff
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012-2013 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.
+ */
+
+#ifndef __VDOA_H__
+#define __VDOA_H__
+
+#define VDOA_PFS_YUYV (1)
+#define VDOA_PFS_NV12 (0)
+
+
+struct vfield_buf {
+       u32     prev_veba;
+       u32     cur_veba;
+       u32     next_veba;
+       u32     vubo;
+};
+
+struct vframe_buf {
+       u32     veba;
+       u32     vubo;
+};
+
+struct vdoa_params {
+       u32     width;
+       u32     height;
+       int     vpu_stride;
+       int     interlaced;
+       int     scan_order;
+       int     ipu_num;
+       int     band_lines;
+       int     band_mode;
+       int     pfs;
+       u32     ieba0;
+       u32     ieba1;
+       u32     ieba2;
+       struct  vframe_buf vframe_buf;
+       struct  vfield_buf vfield_buf;
+};
+struct vdoa_ipu_buf {
+       u32     ieba0;
+       u32     ieba1;
+       u32     iubo;
+};
+
+struct vdoa_info;
+typedef void *vdoa_handle_t;
+
+int vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
+int  vdoa_start(vdoa_handle_t handle, int timeout_ms);
+void vdoa_stop(vdoa_handle_t handle);
+void vdoa_get_handle(vdoa_handle_t *handle);
+void vdoa_put_handle(vdoa_handle_t *handle);
+#endif
diff --git a/include/linux/ipu-v3.h b/include/linux/ipu-v3.h
new file mode 100644 (file)
index 0000000..9381395
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de>
+ * Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 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),
+
+       /* for vdi mem->vdi->ic->mem , add graphics plane and alpha*/
+       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),
+
+       /* for vdi mem->vdi->mem */
+       MEM_VDI_MEM_P = _MAKE_CHAN(24, 8, NO_DMA, NO_DMA, 5),
+       MEM_VDI_MEM = _MAKE_CHAN(25, 9, NO_DMA, NO_DMA, 5),
+       MEM_VDI_MEM_N = _MAKE_CHAN(26, 10, NO_DMA, NO_DMA, 5),
+
+       /* fake channel for vdoa to link with IPU */
+       MEM_VDOA_MEM =  _MAKE_CHAN(27, NO_DMA, NO_DMA, NO_DMA, NO_DMA),
+
+       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;
+               uint32_t mipi_vc;
+               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 outh_resize_ratio;
+               uint32_t outv_resize_ratio;
+               uint32_t csi;
+               uint32_t mipi_id;
+               uint32_t mipi_vc;
+               bool mipi_en;
+       } 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;
+               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;
+               uint32_t csi;
+               uint32_t mipi_id;
+               uint32_t mipi_vc;
+               bool mipi_en;
+       } 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;
+
+/*
+ * IPU_IRQF_ONESHOT - Interrupt is not reenabled after the irq handler finished.
+ */
+#define IPU_IRQF_NONE          0x00000000
+#define IPU_IRQF_ONESHOT       0x00000001
+
+/*!
+ * 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_VDIC_OUT_EOF = 5,
+       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_BG_SYNC_NFACK = 64 + 23,
+       IPU_IRQ_FG_SYNC_NFACK = 64 + 27,
+       IPU_IRQ_DC_SYNC_NFACK = 64 + 28,
+
+       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 = 0,
+       IPU_CSI_DATA_WIDTH_8 = 1,
+       IPU_CSI_DATA_WIDTH_10 = 3,
+       IPU_CSI_DATA_WIDTH_16 = 9,
+};
+
+/*!
+ * 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);
+void ipu_disable_hsp_clk(struct ipu_soc *ipu);
+
+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);
+uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel);
+
+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);
+
+int 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]);
+int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
+                                ipu_buffer_t type, uint32_t band_height);
+
+/* 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[2];
+       resource_size_t                 res_size[2];
+
+       /*
+        * Late init to avoid display channel being
+        * re-initialized as we've probably setup the
+        * channel in bootloader.
+        */
+       bool                            late_init;
+};
+
+#endif /* __MACH_IPU_V3_H_ */
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
new file mode 100644 (file)
index 0000000..358d315
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2005-2013 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_GENERIC_16 fourcc('I', 'P', 'U', '2')      /*!< 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  */
+/* two planes -- 12  tiled Y/CbCr 4:2:0  */
+#define IPU_PIX_FMT_TILED_NV12    fourcc('T', 'N', 'V', 'P')
+#define IPU_PIX_FMT_TILED_NV12F   fourcc('T', 'N', 'V', 'F')
+
+/*! @} */
+/*! @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 */
+/* non-interleaved 4:4:4 */
+#define IPU_PIX_FMT_YUV444P fourcc('4', '4', '4', 'P') /*!< 24 YUV 4:4:4 */
+/*! @} */
+#define IPU_PIX_FMT_TILED_NV12_MBALIGN (16)
+#define TILED_NV12_FRAME_SIZE(w, h)    \
+               (ALIGN((w) * (h), SZ_4K) + ALIGN((w) * (h) / 2, SZ_4K))
+/* IPU device */
+typedef enum {
+       RGB_CS,
+       YUV_CS,
+       NULL_CS
+} cs_t;
+
+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
+#define IPU_DEINTERLACE_FIELD_MASK     \
+               (IPU_DEINTERLACE_FIELD_TOP | IPU_DEINTERLACE_FIELD_BOTTOM)
+       /* deinterlace frame rate double flags */
+#define IPU_DEINTERLACE_RATE_EN                0x80
+#define IPU_DEINTERLACE_RATE_FRAME1    0x40
+#define IPU_DEINTERLACE_RATE_MASK      \
+               (IPU_DEINTERLACE_RATE_EN | IPU_DEINTERLACE_RATE_FRAME1)
+#define IPU_DEINTERLACE_MAX_FRAME      2
+       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,
+       IPU_CHECK_ERR_SPLIT_WITH_ROT,
+       IPU_CHECK_ERR_NOT_SUPPORT,
+       IPU_CHECK_ERR_NOT16ALIGN,
+};
+
+/* 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)
+
+/* export functions */
+#ifdef __KERNEL__
+unsigned int fmt_to_bpp(unsigned int pixelformat);
+cs_t colorspaceofpixel(int fmt);
+int need_csc(int ifmt, int ofmt);
+
+int ipu_queue_task(struct ipu_task *task);
+int ipu_check_task(struct ipu_task *task);
+#endif
+
+#endif