]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00155135-3 ipuv3 dev: add processing driver support
authorJason Chen <b02280@freescale.com>
Mon, 22 Aug 2011 02:46:22 +0000 (10:46 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:33:12 +0000 (08:33 +0200)
IPU's IC/IRT/VDI modules provide resizing/CSC/combination/de-interlacing
support, this patch make all these features into one processing driver.
A struct ipu_task is the interface between user and this driver, user
just need fill his task struct and queue it through ioctl, then wait
ipu hardware finish its job (now only support BLOCKING operation, not
support NO_BLOCK operation).
Pls refer to inlcude/linux/ipu.h for structure information and unit test
for usage.

This patch is for ipu driver changes.

Signed-off-by: Jason Chen <b02280@freescale.com>
drivers/mxc/ipu3/Makefile
drivers/mxc/ipu3/ipu_common.c
drivers/mxc/ipu3/ipu_device.c
drivers/mxc/ipu3/ipu_disp.c
drivers/mxc/ipu3/ipu_prv.h

index 022541115dd873db2a8f243b8f0882b013c32561..aa3e7b1bb501d4cfae00c73db523559a14d0b958 100644 (file)
@@ -1,5 +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
-mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_calc_stripes_sizes.o
+mxc_ipu-objs := ipu_common.o ipu_ic.o ipu_disp.o ipu_capture.o ipu_device.o ipu_calc_stripes_sizes.o
 
index 5cb9dc0b474e9f4c9237775ef02a1820967e4499..4ee5d97d6a0ef668286195b574a0e85d516b7ef2 100644 (file)
 #include "ipu_regs.h"
 #include "ipu_param_mem.h"
 
-#ifdef CONFIG_MXC_IPU_V3H
-#define MXC_IPU_MAX_NUM        2
-#else
-#define MXC_IPU_MAX_NUM        1
-#endif
 static struct ipu_soc ipu_array[MXC_IPU_MAX_NUM];
 int g_ipu_hw_rev;
 
@@ -624,7 +619,7 @@ static int __devinit ipu_probe(struct platform_device *pdev)
 
        clk_disable(ipu->ipu_clk);
 
-       /*register_ipu_device();*/
+       register_ipu_device(ipu, pdev->id);
 
        return ret;
 
@@ -659,6 +654,8 @@ int __devexit ipu_remove(struct platform_device *pdev)
 {
        struct ipu_soc *ipu = platform_get_drvdata(pdev);
 
+       unregister_ipu_device(ipu, pdev->id);
+
        if (ipu->irq_sync)
                free_irq(ipu->irq_sync, ipu);
        if (ipu->irq_err)
@@ -2275,6 +2272,8 @@ int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wai
                                break;
                        }
 
+                       dev_err(ipu->dev, "warning: channel %d busy, need wait\n", irq);
+
                        ret = ipu_request_irq(ipu, irq, disable_chan_irq_handler, 0, NULL, &disable_comp);
                        if (ret < 0) {
                                dev_err(ipu->dev, "irq %d in use\n", irq);
index 316207a288fadf826bdc215a50b518aa92f8adf2..c00f0df98595b72b0bd5318d028243108c0ac98a 100644 (file)
@@ -18,7 +18,6 @@
  *
  * @ingroup IPU
  */
-
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/sched.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/slab.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/ipu.h>
+#include <linux/kthread.h>
 #include <asm/cacheflush.h>
 
-#include "ipu_prv.h"
-#include "ipu_regs.h"
-#include "ipu_param_mem.h"
+#include "ipu_prv.h"
+#include "ipu_regs.h"
+#include "ipu_param_mem.h"
+
+/* Strucutures and variables for exporting MXC IPU as device*/
+typedef enum {
+       RGB_CS,
+       YUV_CS,
+       NULL_CS
+} cs_t;
+
+typedef enum {
+       STATE_OK = 0,
+       STATE_NO_IPU,
+       STATE_NO_IRQ,
+       STATE_IRQ_FAIL,
+       STATE_IRQ_TIMEOUT,
+       STATE_INIT_CHAN_FAIL,
+       STATE_LINK_CHAN_FAIL,
+       STATE_INIT_CHAN_BUF_FAIL,
+} ipu_state_t;
+
+struct ipu_state_msg {
+       int state;
+       char *msg;
+} state_msg[] = {
+       {STATE_OK, "ok"},
+       {STATE_NO_IPU, "no ipu found"},
+       {STATE_NO_IRQ, "no irq found for task"},
+       {STATE_IRQ_FAIL, "request irq failed"},
+       {STATE_IRQ_TIMEOUT, "wait for irq timeout"},
+       {STATE_INIT_CHAN_FAIL, "ipu init channel fail"},
+       {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
+       {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+};
+
+struct stripe_setting {
+       u32 iw;
+       u32 ih;
+       u32 ow;
+       u32 oh;
+       u32 outh_resize_ratio;
+       u32 outv_resize_ratio;
+       u32 i_left_pos;
+       u32 i_right_pos;
+       u32 i_top_pos;
+       u32 i_bottom_pos;
+       u32 o_left_pos;
+       u32 o_right_pos;
+       u32 o_top_pos;
+       u32 o_bottom_pos;
+};
+
+struct task_set {
+#define        NULL_MODE       0x0
+#define        IC_MODE         0x1
+#define        ROT_MODE        0x2
+#define        VDI_MODE        0x4
+       u8      mode;
+#define IC_VF  0x1
+#define IC_PP  0x2
+#define ROT_VF 0x4
+#define ROT_PP 0x8
+#define VDI_VF 0x10
+       u8      task;
+
+       ipu_channel_t ic_chan;
+       ipu_channel_t rot_chan;
+       ipu_channel_t vdi_ic_p_chan;
+       ipu_channel_t vdi_ic_n_chan;
+
+       u32 i_off;
+       u32 i_uoff;
+       u32 i_voff;
+       u32 istride;
+
+       u32 ov_off;
+       u32 ov_uoff;
+       u32 ov_voff;
+       u32 ovstride;
+
+       u32 ov_alpha_off;
+       u32 ov_alpha_stride;
+
+       u32 o_off;
+       u32 o_uoff;
+       u32 o_voff;
+       u32 ostride;
+
+       u32 r_fmt;
+       u32 r_width;
+       u32 r_height;
+       u32 r_stride;
+       dma_addr_t r_paddr;
+
+#define NO_SPLIT       0x0
+#define RL_SPLIT       0x1
+#define UD_SPLIT       0x2
+#define LEFT_STRIPE    0x1
+#define RIGHT_STRIPE   0x2
+#define UP_STRIPE      0x4
+#define DOWN_STRIPE    0x8
+       u8 split_mode;
+       struct stripe_setting sp_setting;
+};
+
+struct ipu_split_task {
+       struct ipu_task task;
+       struct ipu_task_entry *parent_task;
+       struct task_struct *thread;
+       bool could_finish;
+       wait_queue_head_t waitq;
+       int ret;
+};
+
+struct ipu_task_entry {
+       struct ipu_input input;
+       struct ipu_output output;
+
+       bool overlay_en;
+       struct ipu_overlay overlay;
+
+       u8      priority;
+       u8      task_id;
+#define DEF_TIMEOUT_MS 1000
+       int     timeout;
+
+       struct list_head node;
+       struct device *dev;
+       struct task_set set;
+       struct completion comp;
+       ipu_state_t state;
+};
+
+struct ipu_alloc_list {
+       struct list_head list;
+       dma_addr_t phy_addr;
+       void *cpu_addr;
+       u32 size;
+};
+LIST_HEAD(ipu_alloc_list);
+
+static int major;
+static struct class *ipu_class;
+static struct device *ipu_dev;
+
+int ipu_queue_sp_task(struct ipu_split_task *sp_task);
+
+static bool deinterlace_3_field(struct ipu_task_entry *t)
+{
+       return ((t->set.mode & VDI_MODE) &&
+               (t->input.deinterlace.motion != HIGH_MOTION));
+}
+
+static u32 fmt_to_bpp(u32 pixelformat)
+{
+       u32 bpp;
+
+       switch (pixelformat) {
+       case IPU_PIX_FMT_RGB565:
+       /*interleaved 422*/
+       case IPU_PIX_FMT_YUYV:
+       case IPU_PIX_FMT_UYVY:
+       /*non-interleaved 422*/
+       case IPU_PIX_FMT_YUV422P:
+       case IPU_PIX_FMT_YVU422P:
+               bpp = 16;
+               break;
+       case IPU_PIX_FMT_BGR24:
+       case IPU_PIX_FMT_RGB24:
+       case IPU_PIX_FMT_YUV444:
+               bpp = 24;
+               break;
+       case IPU_PIX_FMT_BGR32:
+       case IPU_PIX_FMT_BGRA32:
+       case IPU_PIX_FMT_RGB32:
+       case IPU_PIX_FMT_RGBA32:
+       case IPU_PIX_FMT_ABGR32:
+               bpp = 32;
+               break;
+       /*non-interleaved 420*/
+       case IPU_PIX_FMT_YUV420P:
+       case IPU_PIX_FMT_YVU420P:
+       case IPU_PIX_FMT_YUV420P2:
+       case IPU_PIX_FMT_NV12:
+               bpp = 12;
+               break;
+       default:
+               bpp = 8;
+               break;
+       }
+       return bpp;
+}
+
+static cs_t colorspaceofpixel(int fmt)
+{
+       switch (fmt) {
+       case IPU_PIX_FMT_RGB565:
+       case IPU_PIX_FMT_BGR24:
+       case IPU_PIX_FMT_RGB24:
+       case IPU_PIX_FMT_BGRA32:
+       case IPU_PIX_FMT_BGR32:
+       case IPU_PIX_FMT_RGBA32:
+       case IPU_PIX_FMT_RGB32:
+       case IPU_PIX_FMT_ABGR32:
+               return RGB_CS;
+               break;
+       case IPU_PIX_FMT_UYVY:
+       case IPU_PIX_FMT_YUYV:
+       case IPU_PIX_FMT_YUV420P2:
+       case IPU_PIX_FMT_YUV420P:
+       case IPU_PIX_FMT_YVU420P:
+       case IPU_PIX_FMT_YVU422P:
+       case IPU_PIX_FMT_YUV422P:
+       case IPU_PIX_FMT_YUV444:
+       case IPU_PIX_FMT_NV12:
+               return YUV_CS;
+               break;
+       default:
+               return NULL_CS;
+       }
+}
+
+static int need_csc(int ifmt, int ofmt)
+{
+       cs_t ics, ocs;
+
+       ics = colorspaceofpixel(ifmt);
+       ocs = colorspaceofpixel(ofmt);
+
+       if ((ics == NULL_CS) || (ocs == NULL_CS))
+               return -1;
+       else if (ics != ocs)
+               return 1;
+
+       return 0;
+}
+
+static int soc_max_in_width(void)
+{
+       return 4096;
+}
+
+static int soc_max_in_height(void)
+{
+       return 4096;
+}
+
+static int soc_max_out_width(void)
+{
+       /* mx51/mx53/mx6q is 1024*/
+       return 1024;
+}
+
+static int soc_max_out_height(void)
+{
+       /* mx51/mx53/mx6q is 1024*/
+       return 1024;
+}
+
+static int list_size(struct list_head *head)
+{
+       struct list_head *p, *n;
+       int size = 0;
+
+       list_for_each_safe(p, n, head)
+               size++;
+
+       return size;
+}
+
+static int get_task_size(struct ipu_soc *ipu, int id)
+{
+       struct list_head *task_list;
+
+       if (id == IPU_TASK_ID_VF)
+               task_list = &ipu->task_list[0];
+       else if (id == IPU_TASK_ID_PP)
+               task_list = &ipu->task_list[1];
+       else {
+               printk(KERN_ERR "query error task id\n");
+               return -EINVAL;
+       }
+
+       return list_size(task_list);
+}
+
+static struct ipu_soc *most_free_ipu_task(struct ipu_task_entry *t)
+{
+       unsigned int task_num[2][2] = {
+               {0xffffffff, 0xffffffff},
+               {0xffffffff, 0xffffffff} };
+       struct ipu_soc *ipu;
+       int ipu_idx, task_id;
+       int i;
+
+       /* decide task_id */
+       if (t->task_id >= IPU_TASK_ID_MAX)
+               t->task_id %= IPU_TASK_ID_MAX;
+       /* must use task_id VF for VDI task*/
+       if ((t->set.mode & VDI_MODE) &&
+               (t->task_id != IPU_TASK_ID_VF))
+               t->task_id = IPU_TASK_ID_VF;
+
+       for (i = 0; i < MXC_IPU_MAX_NUM; i++) {
+               ipu = ipu_get_soc(i);
+               if (!IS_ERR(ipu)) {
+                       task_num[i][0] = get_task_size(ipu, IPU_TASK_ID_VF);
+                       task_num[i][1] = get_task_size(ipu, IPU_TASK_ID_PP);
+               }
+       }
+
+       task_id = t->task_id;
+       if (t->task_id == IPU_TASK_ID_VF) {
+               if (task_num[0][0] < task_num[1][0])
+                       ipu_idx = 0;
+               else
+                       ipu_idx = 1;
+       } else if (t->task_id == IPU_TASK_ID_PP) {
+               if (task_num[0][1] < task_num[1][1])
+                       ipu_idx = 0;
+               else
+                       ipu_idx = 1;
+       } else {
+               unsigned int min;
+               ipu_idx = 0;
+               task_id = IPU_TASK_ID_VF;
+               min = task_num[0][0];
+               if (task_num[0][1] < min) {
+                       min = task_num[0][1];
+                       task_id = IPU_TASK_ID_PP;
+               }
+               if (task_num[1][0] < min) {
+                       min = task_num[1][0];
+                       ipu_idx = 1;
+                       task_id = IPU_TASK_ID_VF;
+               }
+               if (task_num[1][1] < min) {
+                       ipu_idx = 1;
+                       task_id = IPU_TASK_ID_PP;
+               }
+       }
+
+       t->task_id = task_id;
+       ipu = ipu_get_soc(ipu_idx);
+
+       return ipu;
+}
+
+static void dump_task_info(struct ipu_task_entry *t)
+{
+       dev_dbg(t->dev, "[0x%p]input:\n", (void *)t);
+       dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->input.format);
+       dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->input.width);
+       dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->input.height);
+       dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->input.crop.w);
+       dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->input.crop.h);
+       dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+                       (void *)t, t->input.crop.pos.x);
+       dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+                       (void *)t, t->input.crop.pos.y);
+       dev_dbg(t->dev, "[0x%p]input buffer:\n", (void *)t);
+       dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->input.paddr);
+       dev_dbg(t->dev, "[0x%p]\ti_off = 0x%x\n", (void *)t, t->set.i_off);
+       dev_dbg(t->dev, "[0x%p]\ti_uoff = 0x%x\n", (void *)t, t->set.i_uoff);
+       dev_dbg(t->dev, "[0x%p]\ti_voff = 0x%x\n", (void *)t, t->set.i_voff);
+       dev_dbg(t->dev, "[0x%p]\tistride = %d\n", (void *)t, t->set.istride);
+       if (t->input.deinterlace.enable) {
+               dev_dbg(t->dev, "[0x%p]deinterlace enabled with:\n", (void *)t);
+               if (t->input.deinterlace.motion != HIGH_MOTION) {
+                       dev_dbg(t->dev, "[0x%p]\tlow/medium motion\n", (void *)t);
+                       dev_dbg(t->dev, "[0x%p]\tpaddr_n = 0x%x\n",
+                               (void *)t, t->input.paddr_n);
+               } else
+                       dev_dbg(t->dev, "[0x%p]\thigh motion\n", (void *)t);
+       }
+
+       dev_dbg(t->dev, "[0x%p]output:\n", (void *)t);
+       dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->output.format);
+       dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->output.width);
+       dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->output.height);
+       dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n", (void *)t, t->output.crop.w);
+       dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n", (void *)t, t->output.crop.h);
+       dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+                       (void *)t, t->output.crop.pos.x);
+       dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+                       (void *)t, t->output.crop.pos.y);
+       dev_dbg(t->dev, "[0x%p]\trotate = %d\n", (void *)t, t->output.rotate);
+       dev_dbg(t->dev, "[0x%p]output buffer:\n", (void *)t);
+       dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->output.paddr);
+       dev_dbg(t->dev, "[0x%p]\to_off = 0x%x\n", (void *)t, t->set.o_off);
+       dev_dbg(t->dev, "[0x%p]\to_uoff = 0x%x\n", (void *)t, t->set.o_uoff);
+       dev_dbg(t->dev, "[0x%p]\to_voff = 0x%x\n", (void *)t, t->set.o_voff);
+       dev_dbg(t->dev, "[0x%p]\tostride = %d\n", (void *)t, t->set.ostride);
+
+       if (t->overlay_en) {
+               dev_dbg(t->dev, "[0x%p]overlay:\n", (void *)t);
+               dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n",
+                               (void *)t, t->overlay.format);
+               dev_dbg(t->dev, "[0x%p]\twidth = %d\n",
+                               (void *)t, t->overlay.width);
+               dev_dbg(t->dev, "[0x%p]\theight = %d\n",
+                               (void *)t, t->overlay.height);
+               dev_dbg(t->dev, "[0x%p]\tcrop.w = %d\n",
+                               (void *)t, t->overlay.crop.w);
+               dev_dbg(t->dev, "[0x%p]\tcrop.h = %d\n",
+                               (void *)t, t->overlay.crop.h);
+               dev_dbg(t->dev, "[0x%p]\tcrop.pos.x = %d\n",
+                               (void *)t, t->overlay.crop.pos.x);
+               dev_dbg(t->dev, "[0x%p]\tcrop.pos.y = %d\n",
+                               (void *)t, t->overlay.crop.pos.y);
+               dev_dbg(t->dev, "[0x%p]overlay buffer:\n", (void *)t);
+               dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+                               (void *)t, t->overlay.paddr);
+               dev_dbg(t->dev, "[0x%p]\tov_off = 0x%x\n",
+                               (void *)t, t->set.ov_off);
+               dev_dbg(t->dev, "[0x%p]\tov_uoff = 0x%x\n",
+                               (void *)t, t->set.ov_uoff);
+               dev_dbg(t->dev, "[0x%p]\tov_voff = 0x%x\n",
+                               (void *)t, t->set.ov_voff);
+               dev_dbg(t->dev, "[0x%p]\tovstride = %d\n",
+                               (void *)t, t->set.ovstride);
+               if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+                       dev_dbg(t->dev, "[0x%p]local alpha enabled with:\n",
+                                       (void *)t);
+                       dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n",
+                                       (void *)t, t->overlay.alpha.loc_alp_paddr);
+                       dev_dbg(t->dev, "[0x%p]\tov_alpha_off = 0x%x\n",
+                                       (void *)t, t->set.ov_alpha_off);
+                       dev_dbg(t->dev, "[0x%p]\tov_alpha_stride = %d\n",
+                                       (void *)t, t->set.ov_alpha_stride);
+               } else
+                       dev_dbg(t->dev, "[0x%p]globle alpha enabled with value 0x%x\n",
+                                       (void *)t, t->overlay.alpha.gvalue);
+               if (t->overlay.colorkey.enable)
+                       dev_dbg(t->dev, "[0x%p]colorkey enabled with value 0x%x\n",
+                                       (void *)t, t->overlay.colorkey.value);
+       }
+
+       dev_dbg(t->dev, "[0x%p]want task_id = %d\n", (void *)t, t->task_id);
+       dev_dbg(t->dev, "[0x%p]want task mode is 0x%x\n",
+                               (void *)t, t->set.mode);
+       dev_dbg(t->dev, "[0x%p]\tIC_MODE = 0x%x\n", (void *)t, IC_MODE);
+       dev_dbg(t->dev, "[0x%p]\tROT_MODE = 0x%x\n", (void *)t, ROT_MODE);
+       dev_dbg(t->dev, "[0x%p]\tVDI_MODE = 0x%x\n", (void *)t, VDI_MODE);
+}
+
+static void dump_check_err(struct device *dev, int err)
+{
+       switch (err) {
+       case IPU_CHECK_ERR_INPUT_CROP:
+               dev_err(dev, "input crop setting error\n");
+               break;
+       case IPU_CHECK_ERR_OUTPUT_CROP:
+               dev_err(dev, "output crop setting error\n");
+               break;
+       case IPU_CHECK_ERR_OVERLAY_CROP:
+               dev_err(dev, "overlay crop setting error\n");
+               break;
+       case IPU_CHECK_ERR_INPUT_OVER_LIMIT:
+               dev_err(dev, "input over limitation\n");
+               break;
+       case IPU_CHECK_ERR_OVERLAY_WITH_VDI:
+               dev_err(dev, "do not support overlay with deinterlace\n");
+               break;
+       case IPU_CHECK_ERR_OV_OUT_NO_FIT:
+               dev_err(dev,
+                       "width/height of overlay and ic output should be same\n");
+               break;
+       case IPU_CHECK_ERR_PROC_NO_NEED:
+               dev_err(dev, "no ipu processing need\n");
+               break;
+       case IPU_CHECK_ERR_SPLIT_INPUTW_OVER:
+               dev_err(dev, "split mode input width overflow\n");
+               break;
+       case IPU_CHECK_ERR_SPLIT_INPUTH_OVER:
+               dev_err(dev, "split mode input height overflow\n");
+               break;
+       case IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER:
+               dev_err(dev, "split mode output width overflow\n");
+               break;
+       case IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER:
+               dev_err(dev, "split mode output height overflow\n");
+               break;
+       default:
+               break;
+       }
+}
+
+static void dump_check_warn(struct device *dev, int warn)
+{
+       if (warn & IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN)
+               dev_warn(dev, "input u/v offset not 8 align\n");
+       if (warn & IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN)
+               dev_warn(dev, "output u/v offset not 8 align\n");
+       if (warn & IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN)
+               dev_warn(dev, "overlay u/v offset not 8 align\n");
+}
+
+static int set_crop(struct ipu_crop *crop, int width, int height)
+{
+       if (crop->w || crop->h) {
+               if (((crop->w + crop->pos.x) > width)
+               || ((crop->h + crop->pos.y) > height))
+                       return -EINVAL;
+       } else {
+               crop->pos.x = 0;
+               crop->pos.y = 0;
+               crop->w = width;
+               crop->h = height;
+       }
+       crop->w -= crop->w%8;
+       crop->h -= crop->h%8;
+
+       return 0;
+}
+
+static void update_offset(unsigned int fmt,
+                               unsigned int width, unsigned int height,
+                               unsigned int pos_x, unsigned int pos_y,
+                               int *off, int *uoff, int *voff, int *stride)
+{
+       /* NOTE: u v offset should based on start point of off*/
+       switch (fmt) {
+       case IPU_PIX_FMT_YUV420P2:
+       case IPU_PIX_FMT_YUV420P:
+               *off = pos_y * width + pos_x;
+               *uoff = (width * (height - pos_y) - pos_x)
+                       + ((width/2 * pos_y/2) + pos_x/2);
+               *voff = *uoff + (width/2 * height/2);
+               break;
+       case IPU_PIX_FMT_YVU420P:
+               *off = pos_y * width + pos_x;
+               *voff = (width * (height - pos_y) - pos_x)
+                       + ((width/2 * pos_y/2) + pos_x/2);
+               *uoff = *voff + (width/2 * height/2);
+               break;
+       case IPU_PIX_FMT_YVU422P:
+               *off = pos_y * width + pos_x;
+               *voff = (width * (height - pos_y) - pos_x)
+                       + ((width * pos_y)/2 + pos_x/2);
+               *uoff = *voff + (width * height)/2;
+               break;
+       case IPU_PIX_FMT_YUV422P:
+               *off = pos_y * width + pos_x;
+               *uoff = (width * (height - pos_y) - pos_x)
+                       + (width * pos_y)/2 + pos_x/2;
+               *voff = *uoff + (width * height)/2;
+               break;
+       case IPU_PIX_FMT_NV12:
+               *off = pos_y * width + pos_x;
+               *uoff = (width * (height - pos_y) - pos_x)
+                       + width * pos_y/2 + pos_x;
+               break;
+       default:
+               *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
+               break;
+       }
+       *stride = width * bytes_per_pixel(fmt);
+}
+
+static int update_split_setting(struct ipu_task_entry *t)
+{
+       struct stripe_param left_stripe;
+       struct stripe_param right_stripe;
+       struct stripe_param up_stripe;
+       struct stripe_param down_stripe;
+       u32 iw, ih, ow, oh;
+
+       iw = t->input.crop.w;
+       ih = t->input.crop.h;
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+               ow = t->output.crop.h;
+               oh = t->output.crop.w;
+       } else {
+               ow = t->output.crop.w;
+               oh = t->output.crop.h;
+       }
+
+       if (t->set.split_mode & RL_SPLIT) {
+               ipu_calc_stripes_sizes(iw,
+                               ow,
+                               soc_max_out_width(),
+                               (((unsigned long long)1) << 32), /* 32bit for fractional*/
+                               1, /* equal stripes */
+                               t->input.format,
+                               t->output.format,
+                               &left_stripe,
+                               &right_stripe);
+               t->set.sp_setting.iw = left_stripe.input_width;
+               t->set.sp_setting.ow = left_stripe.output_width;
+               t->set.sp_setting.outh_resize_ratio = left_stripe.irr;
+               t->set.sp_setting.i_left_pos = left_stripe.input_column;
+               t->set.sp_setting.o_left_pos = left_stripe.output_column;
+               t->set.sp_setting.i_right_pos = right_stripe.input_column;
+               t->set.sp_setting.o_right_pos = right_stripe.output_column;
+       } else {
+               t->set.sp_setting.iw = iw;
+               t->set.sp_setting.ow = ow;
+               t->set.sp_setting.outh_resize_ratio = 0;
+               t->set.sp_setting.i_left_pos = 0;
+               t->set.sp_setting.o_left_pos = 0;
+               t->set.sp_setting.i_right_pos = 0;
+               t->set.sp_setting.o_right_pos = 0;
+       }
+       if ((t->set.sp_setting.iw + t->set.sp_setting.i_right_pos) > iw)
+               return IPU_CHECK_ERR_SPLIT_INPUTW_OVER;
+       if (((t->set.sp_setting.ow + t->set.sp_setting.o_right_pos) > ow)
+               || (t->set.sp_setting.ow > soc_max_out_width()))
+               return IPU_CHECK_ERR_SPLIT_OUTPUTW_OVER;
+
+       if (t->set.split_mode & UD_SPLIT) {
+               ipu_calc_stripes_sizes(ih,
+                               oh,
+                               soc_max_out_height(),
+                               (((unsigned long long)1) << 32), /* 32bit for fractional*/
+                               1, /* equal stripes */
+                               t->input.format,
+                               t->output.format,
+                               &up_stripe,
+                               &down_stripe);
+               t->set.sp_setting.ih = up_stripe.input_width;
+               t->set.sp_setting.oh = up_stripe.output_width;
+               t->set.sp_setting.outv_resize_ratio = up_stripe.irr;
+               t->set.sp_setting.i_top_pos = up_stripe.input_column;
+               t->set.sp_setting.o_top_pos = up_stripe.output_column;
+               t->set.sp_setting.i_bottom_pos = down_stripe.input_column;
+               t->set.sp_setting.o_bottom_pos = down_stripe.output_column;
+       } else {
+               t->set.sp_setting.ih = ih;
+               t->set.sp_setting.oh = oh;
+               t->set.sp_setting.outv_resize_ratio = 0;
+               t->set.sp_setting.i_top_pos = 0;
+               t->set.sp_setting.o_top_pos = 0;
+               t->set.sp_setting.i_bottom_pos = 0;
+               t->set.sp_setting.o_bottom_pos = 0;
+       }
+       if ((t->set.sp_setting.ih + t->set.sp_setting.i_bottom_pos) > ih)
+               return IPU_CHECK_ERR_SPLIT_INPUTH_OVER;
+       if (((t->set.sp_setting.oh + t->set.sp_setting.o_bottom_pos) > oh)
+               || (t->set.sp_setting.oh > soc_max_out_height()))
+               return IPU_CHECK_ERR_SPLIT_OUTPUTH_OVER;
+
+       return IPU_CHECK_OK;
+}
+
+static int check_task(struct ipu_task_entry *t)
+{
+       int tmp;
+       int ret = IPU_CHECK_OK;
+
+       /* check input */
+       ret = set_crop(&t->input.crop, t->input.width, t->input.height);
+       if (ret < 0) {
+               ret = IPU_CHECK_ERR_INPUT_CROP;
+               goto done;
+       } else
+               update_offset(t->input.format, t->input.width, t->input.height,
+                               t->input.crop.pos.x, t->input.crop.pos.y,
+                               &t->set.i_off, &t->set.i_uoff,
+                               &t->set.i_voff, &t->set.istride);
+
+       /* check output */
+       ret = set_crop(&t->output.crop, t->output.width, t->output.height);
+       if (ret < 0) {
+               ret = IPU_CHECK_ERR_OUTPUT_CROP;
+               goto done;
+       } else
+               update_offset(t->output.format,
+                               t->output.width, t->output.height,
+                               t->output.crop.pos.x, t->output.crop.pos.y,
+                               &t->set.o_off, &t->set.o_uoff,
+                               &t->set.o_voff, &t->set.ostride);
+
+       /* check overlay if there is */
+       if (t->overlay_en) {
+               if (t->input.deinterlace.enable) {
+                       ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
+                       goto done;
+               }
+               ret = set_crop(&t->overlay.crop, t->overlay.width, t->overlay.height);
+               if (ret < 0) {
+                       ret = IPU_CHECK_ERR_OVERLAY_CROP;
+                       goto done;
+               } else {
+                       int ow = t->output.crop.w;
+                       int oh = t->output.crop.h;
+
+                       if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+                               ow = t->output.crop.h;
+                               oh = t->output.crop.w;
+                       }
+                       if ((t->overlay.crop.w != ow) || (t->overlay.crop.h != oh)) {
+                               ret = IPU_CHECK_ERR_OV_OUT_NO_FIT;
+                               goto done;
+                       }
+
+                       update_offset(t->overlay.format,
+                                       t->overlay.width, t->overlay.height,
+                                       t->overlay.crop.pos.x, t->overlay.crop.pos.y,
+                                       &t->set.ov_off, &t->set.ov_uoff,
+                                       &t->set.ov_voff, &t->set.ovstride);
+                       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+                               t->set.ov_alpha_stride = t->overlay.width;
+                               t->set.ov_alpha_off = t->overlay.crop.pos.y *
+                                       t->overlay.width + t->overlay.crop.pos.x;
+                       }
+               }
+       }
+
+       /* input overflow? */
+       if ((t->input.crop.w > soc_max_in_width()) ||
+               (t->input.crop.h > soc_max_in_height())) {
+               ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+               goto done;
+       }
+
+       /* check task mode */
+       t->set.mode = NULL_MODE;
+       t->set.split_mode = NO_SPLIT;
+
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+               /*output swap*/
+               tmp = t->output.crop.w;
+               t->output.crop.w = t->output.crop.h;
+               t->output.crop.h = tmp;
+       }
+
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT)
+               t->set.mode |= ROT_MODE;
+
+       /*need resize or CSC?*/
+       if ((t->input.crop.w != t->output.crop.w) ||
+                       (t->input.crop.h != t->output.crop.h) ||
+                       need_csc(t->input.format, t->output.format))
+               t->set.mode |= IC_MODE;
+
+       /*need flip?*/
+       if ((t->set.mode == NULL_MODE) && (t->output.rotate > IPU_ROTATE_NONE))
+               t->set.mode |= IC_MODE;
+
+       /*need IDMAC do format(same color space)?*/
+       if ((t->set.mode == NULL_MODE) && (t->input.format != t->output.format))
+               t->set.mode |= IC_MODE;
+
+       /*overlay support*/
+       if (t->overlay_en)
+               t->set.mode |= IC_MODE;
+
+       /*deinterlace*/
+       if (t->input.deinterlace.enable) {
+               t->set.mode &= ~IC_MODE;
+               t->set.mode |= VDI_MODE;
+       }
+
+       if (t->set.mode & (IC_MODE | VDI_MODE)) {
+               if (t->output.crop.w > soc_max_out_width())
+                       t->set.split_mode |= RL_SPLIT;
+               if (t->output.crop.h > soc_max_out_height())
+                       t->set.split_mode |= UD_SPLIT;
+               ret = update_split_setting(t);
+               if (ret > IPU_CHECK_ERR_MIN)
+                       goto done;
+       }
+
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+               /*output swap*/
+               tmp = t->output.crop.w;
+               t->output.crop.w = t->output.crop.h;
+               t->output.crop.h = tmp;
+       }
+
+       if (t->set.mode == NULL_MODE) {
+               ret = IPU_CHECK_ERR_PROC_NO_NEED;
+               goto done;
+       }
+
+       if ((t->set.i_uoff % 8) || (t->set.i_voff % 8))
+               ret |= IPU_CHECK_WARN_INPUT_OFFS_NOT8ALIGN;
+       if ((t->set.o_uoff % 8) || (t->set.o_voff % 8))
+               ret |= IPU_CHECK_WARN_OUTPUT_OFFS_NOT8ALIGN;
+       if (t->overlay_en && ((t->set.ov_uoff % 8) || (t->set.ov_voff % 8)))
+               ret |= IPU_CHECK_WARN_OVERLAY_OFFS_NOT8ALIGN;
+
+done:
+       /* dump msg */
+       if (ret > IPU_CHECK_ERR_MIN)
+               dump_check_err(t->dev, ret);
+       else if (ret != IPU_CHECK_OK)
+               dump_check_warn(t->dev, ret);
+
+       return ret;
+}
+
+static int prepare_task(struct ipu_task_entry *t)
+{
+       int ret = 0;
+
+       ret = check_task(t);
+       if (ret > IPU_CHECK_ERR_MIN)
+               return -EINVAL;
+
+       dump_task_info(t);
+
+       return ret;
+}
+
+/* should call from a process context */
+static int queue_task(struct ipu_task_entry *t)
+{
+       int ret = 0;
+       struct ipu_soc *ipu;
+       struct list_head *task_list = NULL;
+       struct mutex *task_lock = NULL;
+       wait_queue_head_t *waitq = NULL;
+
+       ipu = most_free_ipu_task(t);
+       t->dev = ipu->dev;
+
+       dev_dbg(t->dev, "[0x%p]Queue task: id %d\n", (void *)t, t->task_id);
+
+       init_completion(&t->comp);
+
+       t->set.task = 0;
+       switch (t->task_id) {
+       case IPU_TASK_ID_VF:
+               task_list = &ipu->task_list[0];
+               task_lock = &ipu->task_lock[0];
+               waitq = &ipu->waitq[0];
+               if (t->set.mode & IC_MODE)
+                       t->set.task |= IC_VF;
+               else if (t->set.mode & VDI_MODE)
+                       t->set.task |= VDI_VF;
+               if (t->set.mode & ROT_MODE)
+                       t->set.task |= ROT_VF;
+               break;
+       case IPU_TASK_ID_PP:
+               task_list = &ipu->task_list[1];
+               task_lock = &ipu->task_lock[1];
+               waitq = &ipu->waitq[1];
+               if (t->set.mode & IC_MODE)
+                       t->set.task |= IC_PP;
+               if (t->set.mode & ROT_MODE)
+                       t->set.task |= ROT_PP;
+               break;
+       default:
+               dev_err(t->dev, "[0x%p]should never come here\n", (void *)t);
+       }
+
+       dev_dbg(t->dev, "[0x%p]choose task_id[%d] mode[0x%x]\n",
+                       (void *)t, t->task_id, t->set.task);
+       dev_dbg(t->dev, "[0x%p]\tIPU_TASK_ID_VF = %d\n",
+                               (void *)t, IPU_TASK_ID_VF);
+       dev_dbg(t->dev, "[0x%p]\tIPU_TASK_ID_PP = %d\n",
+                               (void *)t, IPU_TASK_ID_PP);
+       dev_dbg(t->dev, "[0x%p]\tIC_VF = 0x%x\n", (void *)t, IC_VF);
+       dev_dbg(t->dev, "[0x%p]\tIC_PP = 0x%x\n", (void *)t, IC_PP);
+       dev_dbg(t->dev, "[0x%p]\tROT_VF = 0x%x\n", (void *)t, ROT_VF);
+       dev_dbg(t->dev, "[0x%p]\tROT_PP = 0x%x\n", (void *)t, ROT_PP);
+       dev_dbg(t->dev, "[0x%p]\tVDI_VF = 0x%x\n", (void *)t, VDI_VF);
+
+       /* add and wait task */
+       mutex_lock(task_lock);
+       list_add_tail(&t->node, task_list);
+       mutex_unlock(task_lock);
+
+       wake_up_interruptible(waitq);
+
+       wait_for_completion(&t->comp);
+
+       dev_dbg(t->dev, "[0x%p]Queue task finished\n", (void *)t);
+
+       if (t->state != STATE_OK) {
+               dev_err(t->dev, "[0x%p]state %d: %s\n",
+                       (void *)t, t->state, state_msg[t->state].msg);
+               ret = -ECANCELED;
+       }
+
+       return ret;
+}
+
+static bool need_split(struct ipu_task_entry *t)
+{
+       return (t->set.split_mode != NO_SPLIT);
+}
+
+static int split_task_thread(void *data)
+{
+       struct ipu_split_task *t = data;
+
+       t->ret = ipu_queue_sp_task(t);
+
+       while (!kthread_should_stop())
+               wait_event_interruptible(t->waitq, t->could_finish);
+
+       return 0;
+}
+
+static int create_split_task(
+               int stripe,
+               struct ipu_split_task *sp_task)
+{
+       struct ipu_task *task = &(sp_task->task);
+       struct ipu_task_entry *t = sp_task->parent_task;
+
+       task->input = t->input;
+       task->output = t->output;
+       task->overlay_en = t->overlay_en;
+       if (task->overlay_en)
+               task->overlay = t->overlay;
+       task->priority = t->priority;
+       task->task_id = t->task_id;
+       task->timeout = t->timeout;
+
+       task->input.crop.w = t->set.sp_setting.iw;
+       task->input.crop.h = t->set.sp_setting.ih;
+       if (task->overlay_en) {
+               task->overlay.crop.w = t->set.sp_setting.ow;
+               task->overlay.crop.h = t->set.sp_setting.oh;
+       }
+       if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+               task->output.crop.w = t->set.sp_setting.oh;
+               task->output.crop.h = t->set.sp_setting.ow;
+       } else {
+               task->output.crop.w = t->set.sp_setting.ow;
+               task->output.crop.h = t->set.sp_setting.oh;
+       }
+
+       if (stripe & LEFT_STRIPE)
+               task->input.crop.pos.x += t->set.sp_setting.i_left_pos;
+       else if (stripe & RIGHT_STRIPE)
+               task->input.crop.pos.x += t->set.sp_setting.i_right_pos;
+       if (stripe & UP_STRIPE)
+               task->input.crop.pos.y += t->set.sp_setting.i_top_pos;
+       else if (stripe & DOWN_STRIPE)
+               task->input.crop.pos.y += t->set.sp_setting.i_bottom_pos;
+
+       if (task->overlay_en) {
+               if (stripe & LEFT_STRIPE)
+                       task->overlay.crop.pos.x += t->set.sp_setting.o_left_pos;
+               else if (stripe & RIGHT_STRIPE)
+                       task->overlay.crop.pos.x += t->set.sp_setting.o_right_pos;
+               if (stripe & UP_STRIPE)
+                       task->overlay.crop.pos.y += t->set.sp_setting.o_top_pos;
+               else if (stripe & DOWN_STRIPE)
+                       task->overlay.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+       }
+
+       switch (t->output.rotate) {
+       case IPU_ROTATE_NONE:
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+               break;
+       case IPU_ROTATE_VERT_FLIP:
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_left_pos;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_right_pos;
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+               break;
+       case IPU_ROTATE_HORIZ_FLIP:
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_top_pos;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_bottom_pos;
+               break;
+       case IPU_ROTATE_180:
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+               break;
+       case IPU_ROTATE_90_RIGHT:
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+               break;
+       case IPU_ROTATE_90_RIGHT_HFLIP:
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_left_pos;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.y += t->set.sp_setting.o_right_pos;
+               break;
+       case IPU_ROTATE_90_RIGHT_VFLIP:
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_top_pos - t->set.sp_setting.oh;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.x =
+                                       t->output.crop.pos.x + t->output.crop.w
+                                       - t->set.sp_setting.o_bottom_pos - t->set.sp_setting.oh;
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+               break;
+       case IPU_ROTATE_90_LEFT:
+               if (stripe & UP_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_top_pos;
+               else if (stripe & DOWN_STRIPE)
+                       task->output.crop.pos.x += t->set.sp_setting.o_bottom_pos;
+               if (stripe & LEFT_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_left_pos - t->set.sp_setting.ow;
+               else if (stripe & RIGHT_STRIPE)
+                       task->output.crop.pos.y =
+                                       t->output.crop.pos.y + t->output.crop.h
+                                       - t->set.sp_setting.o_right_pos - t->set.sp_setting.ow;
+               break;
+       default:
+               dev_err(t->dev, "should not be here\n");
+               break;
+       }
+
+       sp_task->thread = kthread_run(split_task_thread, sp_task,
+                                       "ipu_split_task");
+       if (IS_ERR(sp_task->thread)) {
+               dev_err(t->dev, "split thread can not create\n");
+               return PTR_ERR(sp_task->thread);
+       }
+
+       return 0;
+}
+
+static int queue_split_task(struct ipu_task_entry *t)
+{
+       struct ipu_split_task sp_task[4];
+       int i, ret = 0, size;
+
+       dev_dbg(t->dev, "Split task 0x%p\n", (void *)t);
+
+       if ((t->set.split_mode == RL_SPLIT) || (t->set.split_mode == UD_SPLIT))
+               size = 2;
+       else
+               size = 4;
+
+       for (i = 0; i < size; i++) {
+               memset(&sp_task[i], 0, sizeof(struct ipu_split_task));
+               init_waitqueue_head(&(sp_task[i].waitq));
+               sp_task[i].could_finish = false;
+               sp_task[i].parent_task = t;
+       }
+
+       if (t->set.split_mode == RL_SPLIT) {
+               create_split_task(LEFT_STRIPE, &sp_task[0]);
+               create_split_task(RIGHT_STRIPE, &sp_task[1]);
+       } else if (t->set.split_mode == UD_SPLIT) {
+               create_split_task(UP_STRIPE, &sp_task[0]);
+               create_split_task(DOWN_STRIPE, &sp_task[1]);
+       } else {
+               create_split_task(LEFT_STRIPE | UP_STRIPE, &sp_task[0]);
+               create_split_task(RIGHT_STRIPE | UP_STRIPE, &sp_task[1]);
+               create_split_task(LEFT_STRIPE | DOWN_STRIPE, &sp_task[2]);
+               create_split_task(RIGHT_STRIPE | DOWN_STRIPE, &sp_task[3]);
+       }
+
+       for (i = 0; i < size; i++) {
+               sp_task[i].could_finish = true;
+               wake_up_interruptible(&sp_task[i].waitq);
+               kthread_stop(sp_task[i].thread);
+               if (sp_task[i].ret < 0) {
+                       ret = sp_task[i].ret;
+                       dev_err(t->dev,
+                               "split task %d fail with ret %d\n",
+                               i, ret);
+               }
+       }
+
+       return ret;
+}
+
+static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
+{
+       struct ipu_task_entry *tsk;
+
+       tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
+       if (!tsk)
+               return ERR_PTR(-ENOMEM);
+
+       tsk->dev = ipu_dev;
+       tsk->input = task->input;
+       tsk->output = task->output;
+       tsk->overlay_en = task->overlay_en;
+       if (tsk->overlay_en)
+               tsk->overlay = task->overlay;
+       tsk->priority = task->priority;
+       tsk->task_id = task->task_id;
+       if (task->timeout && (task->timeout > DEF_TIMEOUT_MS))
+               tsk->timeout = task->timeout;
+       else
+               tsk->timeout = DEF_TIMEOUT_MS;
+
+       return tsk;
+}
+
+int ipu_check_task(struct ipu_task *task)
+{
+       struct ipu_task_entry *tsk;
+       int ret = 0;
+
+       tsk = create_task_entry(task);
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
+
+       ret = check_task(tsk);
+
+       task->input = tsk->input;
+       task->output = tsk->output;
+       task->overlay = tsk->overlay;
 
-/* Strucutures and variables for exporting MXC IPU as device*/
+       kfree(tsk);
 
-static int mxc_ipu_major;
-static struct class *mxc_ipu_class;
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ipu_check_task);
 
-DEFINE_SPINLOCK(event_lock);
+int ipu_queue_sp_task(struct ipu_split_task *sp_task)
+{
+       struct ipu_task_entry *tsk;
+       int ret;
 
-struct ipu_dev_irq_info {
-       wait_queue_head_t waitq;
-       int irq_pending;
-} irq_info[480];
+       tsk = create_task_entry(&sp_task->task);
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
 
-int register_ipu_device(void);
+       ret = prepare_task(tsk);
+       if (ret < 0)
+               goto done;
 
-/* Static functions */
+       tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
+       tsk->set.sp_setting = sp_task->parent_task->set.sp_setting;
 
-int get_events(ipu_event_info *p)
+       ret = queue_task(tsk);
+done:
+       kfree(tsk);
+       return ret;
+}
+
+int ipu_queue_task(struct ipu_task *task)
 {
-       unsigned long flags;
-       int ret = 0;
+       struct ipu_task_entry *tsk;
+       int ret;
 
-       spin_lock_irqsave(&event_lock, flags);
-       if (irq_info[p->irq].irq_pending > 0)
-               irq_info[p->irq].irq_pending--;
-       else
-               ret = -1;
-       spin_unlock_irqrestore(&event_lock, flags);
+       tsk = create_task_entry(task);
+       if (IS_ERR(tsk))
+               return PTR_ERR(tsk);
+
+       ret = prepare_task(tsk);
+       if (ret < 0)
+               goto done;
 
+       if (need_split(tsk))
+               ret = queue_split_task(tsk);
+       else
+               ret = queue_task(tsk);
+done:
+       kfree(tsk);
        return ret;
 }
+EXPORT_SYMBOL_GPL(ipu_queue_task);
 
-static irqreturn_t mxc_ipu_generic_handler(int irq, void *dev_id)
+static bool only_ic(u8 mode)
 {
-       irq_info[irq].irq_pending++;
+       return ((mode == IC_MODE) || (mode == VDI_MODE));
+}
 
-       /* Wakeup any blocking user context */
-       wake_up_interruptible(&(irq_info[irq].waitq));
-       return IRQ_HANDLED;
+static bool only_rot(u8 mode)
+{
+       return (mode == ROT_MODE);
 }
 
-static int mxc_ipu_open(struct inode *inode, struct file *file)
+static bool ic_and_rot(u8 mode)
 {
-       int ret = 0;
-       return ret;
+       return ((mode == (IC_MODE | ROT_MODE)) ||
+                (mode == (VDI_MODE | ROT_MODE)));
 }
 
-static long mxc_ipu_ioctl(struct file *file,
-               unsigned int cmd, unsigned long arg)
+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;
 
-       switch (cmd) {
-       case IPU_INIT_CHANNEL:
-               {
-                       ipu_channel_parm parm;
+       memset(&params, 0, sizeof(params));
 
-                       if (copy_from_user
-                                       (&parm, (ipu_channel_parm *) arg,
-                                        sizeof(ipu_channel_parm)))
-                               return -EFAULT;
+       /* 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;
+       }
 
-                       if (!parm.flag) {
-                               ret =
-                                       ipu_init_channel(parm.channel,
-                                                       &parm.params);
-                       } else {
-                               ret = ipu_init_channel(parm.channel, NULL);
-                       }
-               }
-               break;
-       case IPU_UNINIT_CHANNEL:
-               {
-               ipu_channel_t ch;
-               int __user *argp = (void __user *)arg;
-               if (get_user(ch, argp))
-                               return -EFAULT;
-                       ipu_uninit_channel(ch);
-               }
-               break;
-       case IPU_INIT_CHANNEL_BUFFER:
-               {
-                       ipu_channel_buf_parm parm;
-                       if (copy_from_user
-                               (&parm, (ipu_channel_buf_parm *) arg,
-                               sizeof(ipu_channel_buf_parm)))
-                               return -EFAULT;
+       /* 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;
 
-                       ret =
-                               ipu_init_channel_buffer(
-                                               parm.channel, parm.type,
-                                               parm.pixel_fmt,
-                                               parm.width, parm.height,
-                                               parm.stride,
-                                               parm.rot_mode,
-                                               parm.phyaddr_0,
-                                               parm.phyaddr_1,
-                                               parm.phyaddr_2,
-                                               parm.u_offset,
-                                               parm.v_offset);
+       params.mem_prp_vf_mem.outh_resize_ratio =
+                       t->set.sp_setting.outh_resize_ratio;
+       params.mem_prp_vf_mem.outv_resize_ratio =
+                       t->set.sp_setting.outv_resize_ratio;
 
+       if (t->overlay_en) {
+               params.mem_prp_vf_mem.in_g_pixel_fmt = t->overlay.format;
+               params.mem_prp_vf_mem.graphics_combine_en = 1;
+               if (t->overlay.alpha.mode == IPU_ALPHA_MODE_GLOBAL)
+                       params.mem_prp_vf_mem.global_alpha_en = 1;
+               else
+                       params.mem_prp_vf_mem.alpha_chan_en = 1;
+               params.mem_prp_vf_mem.alpha = t->overlay.alpha.gvalue;
+               if (t->overlay.colorkey.enable) {
+                       params.mem_prp_vf_mem.key_color_en = 1;
+                       params.mem_prp_vf_mem.key_color = t->overlay.colorkey.value;
                }
-               break;
-       case IPU_UPDATE_CHANNEL_BUFFER:
-               {
-                       ipu_channel_buf_parm parm;
-                       if (copy_from_user
-                               (&parm, (ipu_channel_buf_parm *) arg,
-                               sizeof(ipu_channel_buf_parm)))
-                               return -EFAULT;
+       }
 
-                       if ((parm.phyaddr_0 != (dma_addr_t) NULL)
-                               && (parm.phyaddr_1 == (dma_addr_t) NULL)) {
-                               ret =
-                                       ipu_update_channel_buffer(
-                                                       parm.channel,
-                                                       parm.type,
-                                                       parm.bufNum,
-                                                       parm.phyaddr_0);
-                       } else if ((parm.phyaddr_0 == (dma_addr_t) NULL)
-                               && (parm.phyaddr_1 != (dma_addr_t) NULL)) {
-                               ret =
-                                       ipu_update_channel_buffer(
-                                                       parm.channel,
-                                                       parm.type,
-                                                       parm.bufNum,
-                                                       parm.phyaddr_1);
-                       } else {
-                               ret = -1;
-                       }
+       /* init channels */
+       ret = ipu_init_channel(ipu, t->set.ic_chan, &params);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_FAIL;
+               goto done;
+       }
 
+       if (deinterlace_3_field(t)) {
+               ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, &params);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_FAIL;
+                       goto done;
                }
-               break;
-       case IPU_SELECT_CHANNEL_BUFFER:
-               {
-                       ipu_channel_buf_parm parm;
-                       if (copy_from_user
-                               (&parm, (ipu_channel_buf_parm *) arg,
-                               sizeof(ipu_channel_buf_parm)))
-                               return -EFAULT;
+               ret = ipu_init_channel(ipu, t->set.vdi_ic_n_chan, &params);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_FAIL;
+                       goto done;
+               }
+       }
+
+       /* init channel bufs */
+       if (deinterlace_3_field(t)) {
+               inbuf_p = t->input.paddr + t->set.istride + t->set.i_off;
+               inbuf = t->input.paddr_n + t->set.i_off;
+               inbuf_n = t->input.paddr_n + t->set.istride + t->set.i_off;
+       } else
+               inbuf = t->input.paddr + t->set.i_off;
 
-                       ret =
-                               ipu_select_buffer(parm.channel,
-                                       parm.type, parm.bufNum);
+       if (t->overlay_en) {
+               ovbuf = t->overlay.paddr + t->set.ov_off;
+               if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+                       ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+                               + t->set.ov_alpha_off;
+       }
+
+       ret = ipu_init_channel_buffer(ipu,
+                       t->set.ic_chan,
+                       IPU_INPUT_BUFFER,
+                       t->input.format,
+                       t->input.crop.w,
+                       t->input.crop.h,
+                       t->set.istride,
+                       IPU_ROTATE_NONE,
+                       inbuf,
+                       0,
+                       0,
+                       t->set.i_uoff,
+                       t->set.i_voff);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_BUF_FAIL;
+               goto done;
+       }
 
+       if (deinterlace_3_field(t)) {
+               ret = ipu_init_channel_buffer(ipu,
+                               t->set.vdi_ic_p_chan,
+                               IPU_INPUT_BUFFER,
+                               t->input.format,
+                               t->input.crop.w,
+                               t->input.crop.h,
+                               t->set.istride,
+                               IPU_ROTATE_NONE,
+                               inbuf_p,
+                               0,
+                               0,
+                               t->set.i_uoff,
+                               t->set.i_voff);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BUF_FAIL;
+                       goto done;
                }
-               break;
-       case IPU_SELECT_MULTI_VDI_BUFFER:
-               {
-                       uint32_t parm;
-                       if (copy_from_user
-                               (&parm, (uint32_t *) arg,
-                               sizeof(uint32_t)))
-                               return -EFAULT;
 
-                       ret = ipu_select_multi_vdi_buffer(parm);
+               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;
                }
-               break;
-       case IPU_LINK_CHANNELS:
-               {
-                       ipu_channel_link link;
-                       if (copy_from_user
-                               (&link, (ipu_channel_link *) arg,
-                               sizeof(ipu_channel_link)))
-                               return -EFAULT;
+       }
 
-                       ret = ipu_link_channels(link.src_ch,
-                               link.dest_ch);
+       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;
+                       }
                }
-               break;
-       case IPU_UNLINK_CHANNELS:
-               {
-                       ipu_channel_link link;
-                       if (copy_from_user
-                               (&link, (ipu_channel_link *) arg,
-                               sizeof(ipu_channel_link)))
-                               return -EFAULT;
+       }
+
+       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;
+       }
 
-                       ret = ipu_unlink_channels(link.src_ch,
-                               link.dest_ch);
+done:
+       return ret;
+}
 
-               }
+static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       ipu_uninit_channel(ipu, t->set.ic_chan);
+       if (deinterlace_3_field(t)) {
+               ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
+               ipu_uninit_channel(ipu, t->set.vdi_ic_n_chan);
+       }
+}
+
+static int init_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       int ret = 0;
+       dma_addr_t inbuf = 0, outbuf = 0;
+       int in_uoff = 0, in_voff = 0;
+       int in_fmt, in_width, in_height, in_stride;
+
+       /* init channel */
+       ret = ipu_init_channel(ipu, t->set.rot_chan, NULL);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_FAIL;
+               goto done;
+       }
+
+       /* init channel buf */
+       /* is it need link to a ic channel */
+       if (ic_and_rot(t->set.mode)) {
+               in_fmt = t->set.r_fmt;
+               in_width = t->set.r_width;
+               in_height = t->set.r_height;
+               in_stride = t->set.r_stride;
+               inbuf = t->set.r_paddr;
+               in_uoff = 0;
+               in_voff = 0;
+       } else {
+               in_fmt = t->input.format;
+               in_width = t->input.crop.w;
+               in_height = t->input.crop.h;
+               in_stride = t->set.istride;
+               inbuf = t->input.paddr + t->set.i_off;
+               in_uoff = t->set.i_uoff;
+               in_voff = t->set.i_voff;
+       }
+       outbuf = t->output.paddr + t->set.o_off;
+
+       ret = ipu_init_channel_buffer(ipu,
+                       t->set.rot_chan,
+                       IPU_INPUT_BUFFER,
+                       in_fmt,
+                       in_width,
+                       in_height,
+                       t->set.istride,
+                       t->output.rotate,
+                       inbuf,
+                       0,
+                       0,
+                       in_uoff,
+                       in_voff);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_BUF_FAIL;
+               goto done;
+       }
+
+       ret = ipu_init_channel_buffer(ipu,
+                       t->set.rot_chan,
+                       IPU_OUTPUT_BUFFER,
+                       t->output.format,
+                       t->output.crop.w,
+                       t->output.crop.h,
+                       t->set.ostride,
+                       IPU_ROTATE_NONE,
+                       outbuf,
+                       0,
+                       0,
+                       t->set.o_uoff,
+                       t->set.o_voff);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_BUF_FAIL;
+               goto done;
+       }
+
+done:
+       return ret;
+}
+
+static void uninit_rot(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       ipu_uninit_channel(ipu, t->set.rot_chan);
+}
+
+static int get_irq(struct ipu_task_entry *t)
+{
+       int irq;
+       ipu_channel_t chan;
+
+       if (only_ic(t->set.mode))
+               chan = t->set.ic_chan;
+       else
+               chan = t->set.rot_chan;
+
+       switch (chan) {
+       case MEM_ROT_VF_MEM:
+               irq = IPU_IRQ_PRP_VF_ROT_OUT_EOF;
                break;
-       case IPU_ENABLE_CHANNEL:
-               {
-                       ipu_channel_t ch;
-                       int __user *argp = (void __user *)arg;
-                       if (get_user(ch, argp))
-                               return -EFAULT;
-                       ipu_enable_channel(ch);
-               }
+       case MEM_ROT_PP_MEM:
+               irq = IPU_IRQ_PP_ROT_OUT_EOF;
                break;
-       case IPU_DISABLE_CHANNEL:
-               {
-                       ipu_channel_info info;
-                       if (copy_from_user
-                               (&info, (ipu_channel_info *) arg,
-                                sizeof(ipu_channel_info)))
-                               return -EFAULT;
+       case MEM_VDI_PRP_VF_MEM:
+       case MEM_PRP_VF_MEM:
+               irq = IPU_IRQ_PRP_VF_OUT_EOF;
+               break;
+       case MEM_PP_MEM:
+               irq = IPU_IRQ_PP_OUT_EOF;
+               break;
+       default:
+               irq = -EINVAL;
+       }
+
+       return irq;
+}
+
+static irqreturn_t task_irq_handler(int irq, void *dev_id)
+{
+       struct completion *comp = dev_id;
+       complete(comp);
+       return IRQ_HANDLED;
+}
+
+static void do_task(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       struct completion comp;
+       void *r_vaddr;
+       int r_size;
+       int irq;
+       int ret;
+
+       if (!ipu) {
+               t->state = STATE_NO_IPU;
+               return;
+       }
+
+       dev_dbg(ipu->dev, "[0x%p]Do task: id %d\n", (void *)t, t->task_id);
+       dump_task_info(t);
 
-                       ret = ipu_disable_channel(info.channel,
-                               info.stop);
+       if (t->set.task & IC_PP) {
+               t->set.ic_chan = MEM_PP_MEM;
+               dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PP_MEM\n", (void *)t);
+       } else if (t->set.task & IC_VF) {
+               t->set.ic_chan = MEM_PRP_VF_MEM;
+               dev_dbg(ipu->dev, "[0x%p]ic channel MEM_PRP_VF_MEM\n", (void *)t);
+       } else if (t->set.task & VDI_VF) {
+               t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
+               if (deinterlace_3_field(t)) {
+                       t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
+                       t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
                }
-               break;
-       case IPU_ENABLE_IRQ:
-               {
-                       uint32_t irq;
-                       int __user *argp = (void __user *)arg;
-                       if (get_user(irq, argp))
-                               return -EFAULT;
-                       ipu_enable_irq(irq);
+               dev_dbg(ipu->dev, "[0x%p]ic channel MEM_VDI_PRP_VF_MEM\n", (void *)t);
+       }
+
+       if (t->set.task & ROT_PP) {
+               t->set.rot_chan = MEM_ROT_PP_MEM;
+               dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_PP_MEM\n", (void *)t);
+       } else if (t->set.task & ROT_VF) {
+               t->set.rot_chan = MEM_ROT_VF_MEM;
+               dev_dbg(ipu->dev, "[0x%p]rot channel MEM_ROT_VF_MEM\n", (void *)t);
+       }
+
+       /* channel setup */
+       if (only_ic(t->set.mode)) {
+               dev_dbg(t->dev, "[0x%p]only ic mode\n", (void *)t);
+               ret = init_ic(ipu, t);
+               if (ret < 0)
+                       goto chan_done;
+       } else if (only_rot(t->set.mode)) {
+               dev_dbg(t->dev, "[0x%p]only rot mode\n", (void *)t);
+               ret = init_rot(ipu, t);
+               if (ret < 0)
+                       goto chan_done;
+       } else if (ic_and_rot(t->set.mode)) {
+               dev_dbg(t->dev, "[0x%p]ic + rot mode\n", (void *)t);
+               t->set.r_fmt = t->output.format;
+               if (t->output.rotate >= IPU_ROTATE_90_RIGHT) {
+                       t->set.r_width = t->output.crop.h;
+                       t->set.r_height = t->output.crop.w;
+               } else {
+                       t->set.r_width = t->output.crop.w;
+                       t->set.r_height = t->output.crop.h;
                }
-               break;
-       case IPU_DISABLE_IRQ:
-               {
-                       uint32_t irq;
-                       int __user *argp = (void __user *)arg;
-                       if (get_user(irq, argp))
-                               return -EFAULT;
-                       ipu_disable_irq(irq);
+               t->set.r_stride = t->set.r_width *
+                       bytes_per_pixel(t->set.r_fmt);
+               r_size = t->set.r_width * t->set.r_height
+                       * fmt_to_bpp(t->set.r_fmt)/8;
+               r_vaddr = dma_alloc_coherent(t->dev,
+                                         r_size,
+                                         &t->set.r_paddr,
+                                         GFP_DMA | GFP_KERNEL);
+               if (r_vaddr == NULL) {
+                       ret = -ENOMEM;
+                       goto chan_done;
                }
-               break;
-       case IPU_CLEAR_IRQ:
-               {
-                       uint32_t irq;
-                       int __user *argp = (void __user *)arg;
-                       if (get_user(irq, argp))
-                               return -EFAULT;
-                       ipu_clear_irq(irq);
+
+               dev_dbg(t->dev, "[0x%p]rotation:\n", (void *)t);
+               dev_dbg(t->dev, "[0x%p]\tformat = 0x%x\n", (void *)t, t->set.r_fmt);
+               dev_dbg(t->dev, "[0x%p]\twidth = %d\n", (void *)t, t->set.r_width);
+               dev_dbg(t->dev, "[0x%p]\theight = %d\n", (void *)t, t->set.r_height);
+               dev_dbg(t->dev, "[0x%p]\tpaddr = 0x%x\n", (void *)t, t->set.r_paddr);
+               dev_dbg(t->dev, "[0x%p]\trstride = %d\n", (void *)t, t->set.r_stride);
+
+               ret = init_ic(ipu, t);
+               if (ret < 0)
+                       goto chan_done;
+               ret = init_rot(ipu, t);
+               if (ret < 0)
+                       goto chan_done;
+               ret = ipu_link_channels(ipu, t->set.ic_chan,
+                               t->set.rot_chan);
+               if (ret < 0) {
+                       t->state = STATE_LINK_CHAN_FAIL;
+                       goto chan_done;
                }
-               break;
-       case IPU_FREE_IRQ:
-               {
-                       ipu_irq_info info;
+       } else {
+               dev_err(t->dev, "[0x%p]do_task: should not be here\n", (void *)t);
+               return;
+       }
 
-                       if (copy_from_user
-                                       (&info, (ipu_irq_info *) arg,
-                                        sizeof(ipu_irq_info)))
-                               return -EFAULT;
+       /* irq setup */
+       irq = get_irq(t);
+       if (irq < 0) {
+               t->state = STATE_NO_IRQ;
+               goto chan_done;
+       }
+
+       dev_dbg(t->dev, "[0x%p]task irq is %d\n", (void *)t, irq);
 
-                       ipu_free_irq(info.irq, info.dev_id);
-                       irq_info[info.irq].irq_pending = 0;
+       init_completion(&comp);
+       ipu_clear_irq(ipu, irq);
+       ret = ipu_request_irq(ipu, irq, task_irq_handler, 0, NULL, &comp);
+       if (ret < 0) {
+               t->state = STATE_IRQ_FAIL;
+               goto chan_done;
+       }
+
+       /* enable/start channel */
+       if (only_ic(t->set.mode)) {
+               ipu_enable_channel(ipu, t->set.ic_chan);
+               if (deinterlace_3_field(t)) {
+                       ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+                       ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
                }
-               break;
-       case IPU_REQUEST_IRQ_STATUS:
-               {
-                       uint32_t irq;
-                       int __user *argp = (void __user *)arg;
-                       if (get_user(irq, argp))
-                               return -EFAULT;
-                       ret = ipu_get_irq_status(irq);
+
+               ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0);
+               if (t->overlay_en) {
+                       ipu_select_buffer(ipu, t->set.ic_chan, IPU_GRAPH_IN_BUFFER, 0);
+                       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+                               ipu_select_buffer(ipu, t->set.ic_chan, IPU_ALPHA_IN_BUFFER, 0);
+               }
+               if (deinterlace_3_field(t))
+                       ipu_select_multi_vdi_buffer(ipu, 0);
+               else
+                       ipu_select_buffer(ipu, t->set.ic_chan, IPU_INPUT_BUFFER, 0);
+       } else if (only_rot(t->set.mode)) {
+               ipu_enable_channel(ipu, t->set.rot_chan);
+               ipu_select_buffer(ipu, t->set.rot_chan, IPU_OUTPUT_BUFFER, 0);
+               ipu_select_buffer(ipu, t->set.rot_chan, IPU_INPUT_BUFFER, 0);
+       } else if (ic_and_rot(t->set.mode)) {
+               ipu_enable_channel(ipu, t->set.rot_chan);
+               ipu_enable_channel(ipu, t->set.ic_chan);
+               if (deinterlace_3_field(t)) {
+                       ipu_enable_channel(ipu, t->set.vdi_ic_p_chan);
+                       ipu_enable_channel(ipu, t->set.vdi_ic_n_chan);
                }
-               break;
-       case IPU_REGISTER_GENERIC_ISR:
-               {
-                       ipu_event_info info;
-                       if (copy_from_user
-                                       (&info, (ipu_event_info *) arg,
-                                        sizeof(ipu_event_info)))
-                               return -EFAULT;
 
-                       ret =
-                               ipu_request_irq(info.irq,
-                                       mxc_ipu_generic_handler,
-                                       0, "video_sink", info.dev);
-                       if (ret == 0)
-                               init_waitqueue_head(&(irq_info[info.irq].waitq));
+               ipu_select_buffer(ipu, t->set.rot_chan, IPU_OUTPUT_BUFFER, 0);
+               if (t->overlay_en) {
+                       ipu_select_buffer(ipu, t->set.ic_chan, IPU_GRAPH_IN_BUFFER, 0);
+                       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
+                               ipu_select_buffer(ipu, t->set.ic_chan, IPU_ALPHA_IN_BUFFER, 0);
                }
-               break;
-       case IPU_GET_EVENT:
-               /* User will have to allocate event_type
-               structure and pass the pointer in arg */
-               {
-                       ipu_event_info info;
-                       int r = -1;
+               if (deinterlace_3_field(t))
+                       ipu_select_multi_vdi_buffer(ipu, 0);
+               else
+                       ipu_select_buffer(ipu, t->set.ic_chan, IPU_INPUT_BUFFER, 0);
+               ipu_select_buffer(ipu, t->set.ic_chan, IPU_OUTPUT_BUFFER, 0);
+       }
 
-                       if (copy_from_user
-                                       (&info, (ipu_event_info *) arg,
-                                        sizeof(ipu_event_info)))
-                               return -EFAULT;
+       ret = wait_for_completion_timeout(&comp, msecs_to_jiffies(t->timeout));
+       if (ret == 0)
+               t->state = STATE_IRQ_TIMEOUT;
 
-                       r = get_events(&info);
-                       if (r == -1) {
-                               if ((file->f_flags & O_NONBLOCK) &&
-                                       (irq_info[info.irq].irq_pending == 0))
-                                       return -EAGAIN;
-                               wait_event_interruptible_timeout(irq_info[info.irq].waitq,
-                                               (irq_info[info.irq].irq_pending != 0), 2 * HZ);
-                               r = get_events(&info);
-                       }
-                       ret = -1;
-                       if (r == 0) {
-                               if (!copy_to_user((ipu_event_info *) arg,
-                                       &info, sizeof(ipu_event_info)))
-                                       ret = 0;
-                       }
+       ipu_free_irq(ipu, irq, &comp);
+       if (t->set.task & IC_VF) {
+               ipu_clear_irq(ipu, IPU_IRQ_PRP_IN_EOF);
+               ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+       } else if (t->set.task & IC_PP) {
+               ipu_clear_irq(ipu, IPU_IRQ_PP_IN_EOF);
+               ipu_clear_irq(ipu, IPU_IRQ_PP_OUT_EOF);
+       } else if (t->set.task & VDI_VF) {
+               ipu_clear_irq(ipu, IPU_IRQ_VDI_C_IN_EOF);
+               if (deinterlace_3_field(t)) {
+                       ipu_clear_irq(ipu, IPU_IRQ_VDI_P_IN_EOF);
+                       ipu_clear_irq(ipu, IPU_IRQ_VDI_N_IN_EOF);
                }
-               break;
-       case IPU_ALOC_MEM:
-               {
-                       ipu_mem_info info;
-                       if (copy_from_user
-                                       (&info, (ipu_mem_info *) arg,
-                                        sizeof(ipu_mem_info)))
-                               return -EFAULT;
+               ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_OUT_EOF);
+       }
+       if (t->set.task & ROT_VF) {
+               ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_ROT_IN_EOF);
+               ipu_clear_irq(ipu, IPU_IRQ_PRP_VF_ROT_OUT_EOF);
+       } else if (t->set.task & ROT_PP) {
+               ipu_clear_irq(ipu, IPU_IRQ_PP_ROT_IN_EOF);
+               ipu_clear_irq(ipu, IPU_IRQ_PP_ROT_OUT_EOF);
+       }
+
+       if (only_ic(t->set.mode)) {
+               ipu_disable_channel(ipu, t->set.ic_chan, true);
+               if (deinterlace_3_field(t)) {
+                       ipu_disable_channel(ipu, t->set.vdi_ic_p_chan, true);
+                       ipu_disable_channel(ipu, t->set.vdi_ic_n_chan, true);
+               }
+       } else if (only_rot(t->set.mode))
+               ipu_disable_channel(ipu, t->set.rot_chan, true);
+       else if (ic_and_rot(t->set.mode)) {
+               ipu_disable_channel(ipu, t->set.ic_chan, true);
+               if (deinterlace_3_field(t)) {
+                       ipu_disable_channel(ipu, t->set.vdi_ic_p_chan, true);
+                       ipu_disable_channel(ipu, t->set.vdi_ic_n_chan, true);
+               }
+               ipu_disable_channel(ipu, t->set.rot_chan, true);
+       }
+
+chan_done:
+       if (only_ic(t->set.mode))
+               uninit_ic(ipu, t);
+       else if (only_rot(t->set.mode))
+               uninit_rot(ipu, t);
+       else if (ic_and_rot(t->set.mode)) {
+               ipu_unlink_channels(ipu, t->set.ic_chan,
+                       t->set.rot_chan);
+               uninit_ic(ipu, t);
+               uninit_rot(ipu, t);
+               if (r_vaddr)
+                       dma_free_coherent(t->dev,
+                                       r_size,
+                                       r_vaddr,
+                                       t->set.r_paddr);
+       }
+       return;
+}
 
-                       info.vaddr = dma_alloc_coherent(0,
-                                       PAGE_ALIGN(info.size),
-                                       &info.paddr,
-                                       GFP_DMA | GFP_KERNEL);
-                       if (info.vaddr == 0) {
-                               printk(KERN_ERR "dma alloc failed!\n");
-                               return -ENOBUFS;
+static int thread_loop(struct ipu_soc *ipu, int id)
+{
+       struct ipu_task_entry *tsk;
+       struct list_head *task_list = &ipu->task_list[id];
+       struct mutex *task_lock = &ipu->task_lock[id];
+       int ret;
+
+       while (!kthread_should_stop()) {
+               int found = 0;
+
+               ret = wait_event_interruptible(ipu->waitq[id], !list_empty(task_list));
+               if (0 != ret)
+                       continue;
+
+               mutex_lock(task_lock);
+
+               list_for_each_entry(tsk, task_list, node) {
+                       if (tsk->priority == IPU_TASK_PRIORITY_HIGH) {
+                               found = 1;
+                               break;
                        }
-                       if (copy_to_user((ipu_mem_info *) arg, &info,
-                                       sizeof(ipu_mem_info)) > 0)
-                               return -EFAULT;
                }
-               break;
-       case IPU_FREE_MEM:
+
+               if (!found)
+                       tsk = list_first_entry(task_list, struct ipu_task_entry, node);
+
+               mutex_unlock(task_lock);
+
+               do_task(ipu, tsk);
+
+               mutex_lock(task_lock);
+               list_del(&tsk->node);
+               mutex_unlock(task_lock);
+
+               complete(&tsk->comp);
+       }
+
+       return 0;
+}
+
+static int task_vf_thread(void *data)
+{
+       struct ipu_soc *ipu = data;
+
+       thread_loop(ipu, 0);
+
+       return 0;
+}
+
+static int task_pp_thread(void *data)
+{
+       struct ipu_soc *ipu = data;
+
+       thread_loop(ipu, 1);
+
+       return 0;
+}
+
+static int mxc_ipu_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+
+static long mxc_ipu_ioctl(struct file *file,
+               unsigned int cmd, unsigned long arg)
+{
+       int __user *argp = (void __user *)arg;
+       int ret = 0;
+
+       switch (cmd) {
+       case IPU_CHECK_TASK:
                {
-                       ipu_mem_info info;
+                       struct ipu_task task;
+
                        if (copy_from_user
-                                       (&info, (ipu_mem_info *) arg,
-                                        sizeof(ipu_mem_info)))
+                                       (&task, (struct ipu_task *) arg,
+                                        sizeof(struct ipu_task)))
                                return -EFAULT;
-
-                       if (info.vaddr)
-                               dma_free_coherent(0, PAGE_ALIGN(info.size),
-                                       info.vaddr, info.paddr);
-                       else
+                       ret = ipu_check_task(&task);
+                       if (copy_to_user((struct ipu_task *) arg,
+                               &task, sizeof(struct ipu_task)))
                                return -EFAULT;
+                       break;
                }
-               break;
-       case IPU_IS_CHAN_BUSY:
+       case IPU_QUEUE_TASK:
                {
-                       ipu_channel_t chan;
+                       struct ipu_task task;
+
                        if (copy_from_user
-                                       (&chan, (ipu_channel_t *)arg,
-                                        sizeof(ipu_channel_t)))
+                                       (&task, (struct ipu_task *) arg,
+                                        sizeof(struct ipu_task)))
                                return -EFAULT;
-
-                       if (ipu_is_channel_busy(chan))
-                               ret = 1;
-                       else
-                               ret = 0;
+                       ret = ipu_queue_task(&task);
+                       break;
                }
-               break;
-       case IPU_CALC_STRIPES_SIZE:
+       case IPU_ALLOC:
                {
-                       ipu_stripe_parm stripe_parm;
+                       int size;
+                       struct ipu_alloc_list *mem;
 
-                       if (copy_from_user (&stripe_parm, (ipu_stripe_parm *)arg,
-                                        sizeof(ipu_stripe_parm)))
+                       mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+                       if (mem == NULL)
+                               return -ENOMEM;
+
+                       if (get_user(size, argp))
                                return -EFAULT;
-                       ipu_calc_stripes_sizes(stripe_parm.input_width,
-                                               stripe_parm.output_width,
-                                               stripe_parm.maximal_stripe_width,
-                                               stripe_parm.cirr,
-                                               stripe_parm.equal_stripes,
-                                               stripe_parm.input_pixelformat,
-                                               stripe_parm.output_pixelformat,
-                                               &stripe_parm.left,
-                                               &stripe_parm.right);
-                       if (copy_to_user((ipu_stripe_parm *) arg, &stripe_parm,
-                                       sizeof(ipu_stripe_parm)) > 0)
+
+                       mem->size = PAGE_ALIGN(size);
+
+                       mem->cpu_addr = dma_alloc_coherent(ipu_dev, size,
+                                                          &mem->phy_addr,
+                                                          GFP_DMA);
+                       if (mem->cpu_addr == NULL) {
+                               kfree(mem);
+                               return -ENOMEM;
+                       }
+
+                       list_add(&mem->list, &ipu_alloc_list);
+
+                       dev_dbg(ipu_dev, "allocated %d bytes @ 0x%08X\n",
+                               mem->size, mem->phy_addr);
+
+                       if (put_user(mem->phy_addr, argp))
                                return -EFAULT;
+
+                       break;
                }
-               break;
-       case IPU_UPDATE_BUF_OFFSET:
+       case IPU_FREE:
                {
-                       ipu_buf_offset_parm offset_parm;
+                       unsigned long offset;
+                       struct ipu_alloc_list *mem;
 
-                       if (copy_from_user (&offset_parm, (ipu_buf_offset_parm *)arg,
-                                        sizeof(ipu_buf_offset_parm)))
-                               return -EFAULT;
-                       ret = ipu_update_channel_offset(offset_parm.channel,
-                                                       offset_parm.type,
-                                                       offset_parm.pixel_fmt,
-                                                       offset_parm.width,
-                                                       offset_parm.height,
-                                                       offset_parm.stride,
-                                                       offset_parm.u_offset,
-                                                       offset_parm.v_offset,
-                                                       offset_parm.vertical_offset,
-                                                       offset_parm.horizontal_offset);
-               }
-               break;
-       case IPU_CSC_UPDATE:
-               {
-                       int param[5][3];
-                       ipu_csc_update csc;
-                       if (copy_from_user(&csc, (void *) arg,
-                                          sizeof(ipu_csc_update)))
-                               return -EFAULT;
-                       if (copy_from_user(&param[0][0], (void *) csc.param,
-                                          sizeof(param)))
+                       if (get_user(offset, argp))
                                return -EFAULT;
-                       ipu_set_csc_coefficients(csc.channel, param);
+
+                       ret = -EINVAL;
+                       list_for_each_entry(mem, &ipu_alloc_list, list) {
+                               if (mem->phy_addr == offset) {
+                                       list_del(&mem->list);
+                                       dma_free_coherent(ipu_dev,
+                                                         mem->size,
+                                                         mem->cpu_addr,
+                                                         mem->phy_addr);
+                                       kfree(mem);
+                                       ret = 0;
+                                       break;
+                               }
+                       }
+
+                       break;
                }
-               break;
        default:
                break;
        }
@@ -448,6 +1985,24 @@ static long mxc_ipu_ioctl(struct file *file,
 
 static int mxc_ipu_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       bool found = false;
+       u32 len;
+       unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+       struct ipu_alloc_list *mem;
+
+       list_for_each_entry(mem, &ipu_alloc_list, list) {
+               if (offset == mem->phy_addr) {
+                       found = true;
+                       len = mem->size;
+                       break;
+               }
+       }
+       if (!found)
+               return -EINVAL;
+
+       if (vma->vm_end - vma->vm_start > len)
+               return -EINVAL;
+
        vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
 
        if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
@@ -473,40 +2028,82 @@ static struct file_operations mxc_ipu_fops = {
        .unlocked_ioctl = mxc_ipu_ioctl,
 };
 
-int register_ipu_device()
+int register_ipu_device(struct ipu_soc *ipu, int id)
 {
        int ret = 0;
-       struct device *temp;
-       mxc_ipu_major = register_chrdev(0, "mxc_ipu", &mxc_ipu_fops);
-       if (mxc_ipu_major < 0) {
-               printk(KERN_ERR
-                       "Unable to register Mxc Ipu as a char device\n");
-               return mxc_ipu_major;
-       }
 
-       mxc_ipu_class = class_create(THIS_MODULE, "mxc_ipu");
-       if (IS_ERR(mxc_ipu_class)) {
-               printk(KERN_ERR "Unable to create class for Mxc Ipu\n");
-               ret = PTR_ERR(mxc_ipu_class);
-               goto err1;
+       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);
        }
 
-       temp = device_create(mxc_ipu_class, NULL, MKDEV(mxc_ipu_major, 0),
-                       NULL, "mxc_ipu");
+       INIT_LIST_HEAD(&ipu->task_list[0]);
+       INIT_LIST_HEAD(&ipu->task_list[1]);
+       init_waitqueue_head(&ipu->waitq[0]);
+       init_waitqueue_head(&ipu->waitq[1]);
+       mutex_init(&ipu->task_lock[0]);
+       mutex_init(&ipu->task_lock[1]);
+       ipu->thread[0] = kthread_run(task_vf_thread, ipu,
+                                       "ipu%d_process-vf", id);
+       if (IS_ERR(ipu->thread[0])) {
+               ret = PTR_ERR(ipu->thread[0]);
+               goto kthread0_fail;
+       }
 
-       if (IS_ERR(temp)) {
-               printk(KERN_ERR "Unable to create class device for Mxc Ipu\n");
-               ret = PTR_ERR(temp);
-               goto err2;
+       ipu->thread[1] = kthread_run(task_pp_thread, ipu,
+                               "ipu%d_process-pp", id);
+       if (IS_ERR(ipu->thread[1])) {
+               ret = PTR_ERR(ipu->thread[1]);
+               goto kthread1_fail;
        }
-       spin_lock_init(&event_lock);
 
        return ret;
 
-err2:
-       class_destroy(mxc_ipu_class);
-err1:
-       unregister_chrdev(mxc_ipu_major, "mxc_ipu");
+kthread1_fail:
+       kthread_stop(ipu->thread[0]);
+kthread0_fail:
+       if (id == 0)
+               device_destroy(ipu_class, MKDEV(major, 0));
+dev_create_fail:
+       if (id == 0) {
+               class_destroy(ipu_class);
+               unregister_chrdev(major, "mxc_ipu");
+       }
+ipu_class_fail:
+       if (id == 0)
+               unregister_chrdev(major, "mxc_ipu");
+register_cdev_fail:
        return ret;
+}
 
+void unregister_ipu_device(struct ipu_soc *ipu, int id)
+{
+       kthread_stop(ipu->thread[0]);
+       kthread_stop(ipu->thread[1]);
+       if (major) {
+               device_destroy(ipu_class, MKDEV(major, 0));
+               class_destroy(ipu_class);
+               unregister_chrdev(major, "mxc_ipu");
+               major = 0;
+       }
 }
index e956529dd2cd310f101c208d406593ed4e478ecb..12e36e28c2d091e3a670eed497beec7e57608677 100644 (file)
@@ -1817,7 +1817,7 @@ int32_t ipu_disp_set_window_pos(struct ipu_soc *ipu, ipu_channel_t channel,
        uint32_t flow = 0;
        uint32_t dp_srm_shift;
 
-       if (channel == MEM_FG_SYNC) {
+       if ((channel == MEM_FG_SYNC) || (channel == MEM_BG_SYNC)) {
                flow = DP_SYNC;
                dp_srm_shift = 3;
        } else if (channel == MEM_FG_ASYNC0) {
index 9d009fc02fd8ec5e544877f9a7749f115f36cea2..e0d03fa2b7c71347ad1bec20fd40c59932adca6c 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/fsl_devices.h>
 
+#ifdef CONFIG_MXC_IPU_V3H
+#define MXC_IPU_MAX_NUM        2
+#else
+#define MXC_IPU_MAX_NUM        1
+#endif
+
 /* Globals */
 extern int dmfc_type_setup;
 
@@ -104,6 +110,12 @@ struct ipu_soc {
        bool color_key_4rgb;
        bool dc_swap;
        struct completion dc_comp;
+
+       /*ipu processing driver*/
+       struct list_head task_list[2];
+       struct mutex task_lock[2];
+       wait_queue_head_t waitq[2];
+       struct task_struct *thread[2];
 };
 
 struct ipu_channel {
@@ -241,7 +253,8 @@ static inline void ipu_ic_write(struct ipu_soc *ipu,
        writel(value, ipu->ic_reg + offset);
 }
 
-int register_ipu_device(void);
+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);