]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00178875-3 VDOA: Add VDOA driver support on i.MX6
authorWayne Zou <b36644@freescale.com>
Thu, 5 Apr 2012 12:03:29 +0000 (20:03 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:34:23 +0000 (08:34 +0200)
VDOA needs to sync with IPU.
Add VDOA driver support under IPU drivers.

Signed-off-by: Wayne Zou <b36644@freescale.com>
drivers/mxc/ipu3/Makefile
drivers/mxc/ipu3/ipu_common.c
drivers/mxc/ipu3/ipu_device.c
drivers/mxc/ipu3/ipu_ic.c
drivers/mxc/ipu3/ipu_param_mem.h
drivers/mxc/ipu3/ipu_prv.h
drivers/mxc/ipu3/ipu_regs.h
drivers/mxc/ipu3/vdoa.c [new file with mode: 0644]
drivers/mxc/ipu3/vdoa.h [new file with mode: 0644]

index aa3e7b1bb501d4cfae00c73db523559a14d0b958..8dcad3cdf83601dfe0d113ed552d4d23dfaaf86d 100644 (file)
@@ -1,4 +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_device.o ipu_calc_stripes_sizes.o vdoa.o
 
index d10befcfa405d791620d6fdbf7554b1731aced86..f03980bdc81950d92f3701c27c1928fd8bae4add 100644 (file)
@@ -53,7 +53,13 @@ static inline uint32_t channel_2_dma(ipu_channel_t ch, ipu_buffer_t type)
 
 static inline int _ipu_is_ic_chan(uint32_t dma_chan)
 {
-       return ((dma_chan >= 11) && (dma_chan <= 22) && (dma_chan != 17) && (dma_chan != 18));
+       return (((dma_chan >= 11) && (dma_chan <= 22) && (dma_chan != 17) &&
+               (dma_chan != 18)));
+}
+
+static inline int _ipu_is_vdi_out_chan(uint32_t dma_chan)
+{
+       return (dma_chan == 5);
 }
 
 static inline int _ipu_is_ic_graphic_chan(uint32_t dma_chan)
@@ -611,6 +617,12 @@ void ipu_dump_registers(struct ipu_soc *ipu)
               ipu_cm_read(ipu, IPU_FS_PROC_FLOW3));
        dev_dbg(ipu->dev, "IPU_FS_DISP_FLOW1 = \t0x%08X\n",
               ipu_cm_read(ipu, IPU_FS_DISP_FLOW1));
+       dev_dbg(ipu->dev, "IPU_VDIC_VDI_FSIZE = \t0x%08X\n",
+              ipu_vdi_read(ipu, VDI_FSIZE));
+       dev_dbg(ipu->dev, "IPU_VDIC_VDI_C = \t0x%08X\n",
+              ipu_vdi_read(ipu, VDI_C));
+       dev_dbg(ipu->dev, "IPU_IC_CONF = \t0x%08X\n",
+              ipu_ic_read(ipu, IC_CONF));
 }
 
 /*!
@@ -691,7 +703,8 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
                        ret = -EINVAL;
                        goto err;
                }
-               if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) {
+               if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
                        ret = -EINVAL;
                        goto err;
                }
@@ -731,7 +744,8 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
                        ret = -EINVAL;
                        goto err;
                }
-               if (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) {
+               if ((ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_MEM)) {
                        ret = -EINVAL;
                        goto err;
                }
@@ -780,6 +794,7 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
                break;
        case MEM_VDI_PRP_VF_MEM:
                if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_MEM) ||
                     (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
                        ret = -EINVAL;
                        goto err;
@@ -797,9 +812,22 @@ int32_t ipu_init_channel(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel
                _ipu_vdi_init(ipu, channel, params);
                break;
        case MEM_VDI_PRP_VF_MEM_P:
+       case MEM_VDI_PRP_VF_MEM_N:
+       case MEM_VDI_MEM_P:
+       case MEM_VDI_MEM_N:
                _ipu_vdi_init(ipu, channel, params);
                break;
-       case MEM_VDI_PRP_VF_MEM_N:
+       case MEM_VDI_MEM:
+               if ((ipu->using_ic_dirct_ch == CSI_PRP_VF_MEM) ||
+                       (ipu->using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM) ||
+                    (ipu->using_ic_dirct_ch == CSI_PRP_ENC_MEM)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+               ipu->using_ic_dirct_ch = MEM_VDI_MEM;
+               ipu->ic_use_count++;
+               ipu->vdi_use_count++;
+               _ipu_ic_init_prpvf(ipu, params, false);
                _ipu_vdi_init(ipu, channel, params);
                break;
        case MEM_ROT_VF_MEM:
@@ -1017,8 +1045,18 @@ void ipu_uninit_channel(struct ipu_soc *ipu, ipu_channel_t channel)
                reg = ipu_cm_read(ipu, IPU_FS_PROC_FLOW1);
                ipu_cm_write(ipu, reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
                break;
+       case MEM_VDI_MEM:
+               ipu->ic_use_count--;
+               ipu->vdi_use_count--;
+               if (ipu->using_ic_dirct_ch == MEM_VDI_MEM)
+                       ipu->using_ic_dirct_ch = 0;
+               _ipu_ic_uninit_prpvf(ipu);
+               _ipu_vdi_uninit(ipu);
+               break;
        case MEM_VDI_PRP_VF_MEM_P:
        case MEM_VDI_PRP_VF_MEM_N:
+       case MEM_VDI_MEM_P:
+       case MEM_VDI_MEM_N:
                break;
        case MEM_ROT_VF_MEM:
                ipu->rot_use_count--;
@@ -1198,6 +1236,12 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
                return -EINVAL;
        }
 
+       if (_ipu_is_vdi_out_chan(dma_chan) &&
+               ((width < 16) || (height < 16) || (width % 2) || (height % 4))) {
+               dev_err(ipu->dev, "vdi width/height limited err\n");
+               return -EINVAL;
+       }
+
        /* IPUv3EX and IPUv3M support triple buffer */
        if ((!_ipu_is_trb_chan(dma_chan)) && phyaddr_2) {
                dev_err(ipu->dev, "Chan%d doesn't support triple buffer "
@@ -1234,7 +1278,7 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
                _ipu_ch_param_set_rotation(ipu, dma_chan, rot_mode);
 
        /* IC and ROT channels have restriction of 8 or 16 pix burst length */
-       if (_ipu_is_ic_chan(dma_chan)) {
+       if (_ipu_is_ic_chan(dma_chan) || _ipu_is_vdi_out_chan(dma_chan)) {
                if ((width % 16) == 0)
                        _ipu_ch_param_set_burst_size(ipu, dma_chan, 16);
                else
@@ -1252,7 +1296,8 @@ int32_t ipu_init_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
                ipu->chan_is_interlaced[dma_chan])
                _ipu_ch_param_set_interlaced_scan(ipu, dma_chan);
 
-       if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan)) {
+       if (_ipu_is_ic_chan(dma_chan) || _ipu_is_irt_chan(dma_chan) ||
+               _ipu_is_vdi_out_chan(dma_chan)) {
                burst_size = _ipu_ch_param_get_burst_size(ipu, dma_chan);
                _ipu_ic_idma_init(ipu, dma_chan, width, height, burst_size,
                        rot_mode);
@@ -1434,6 +1479,46 @@ int32_t ipu_update_channel_buffer(struct ipu_soc *ipu, ipu_channel_t channel,
 }
 EXPORT_SYMBOL(ipu_update_channel_buffer);
 
+/*!
+ * This function is called to update the band mode setting for
+ * a logical IPU channel.
+ *
+ * @param      ipu             ipu handler
+ *
+ * @param       channel         Input parameter for the logical channel ID.
+ *
+ * @param       type            Input parameter which buffer to initialize.
+ *
+ * @param       band_height     Input parameter for band lines:
+ *                             shoule be log2(4/8/16/32/64/128/256).
+ *
+ * @return      This function returns 0 on success or negative error code on
+ *              fail.
+ */
+int32_t ipu_set_channel_bandmode(struct ipu_soc *ipu, ipu_channel_t channel,
+                                ipu_buffer_t type, uint32_t band_height)
+{
+       uint32_t reg;
+       int ret = 0;
+       uint32_t dma_chan = channel_2_dma(channel, type);
+
+       if ((2 > band_height) || (8 < band_height))
+               return -EINVAL;
+
+       _ipu_lock(ipu);
+
+       reg = ipu_idmac_read(ipu, IDMAC_BAND_EN(dma_chan));
+       reg |= 1 << (dma_chan % 32);
+       ipu_idmac_write(ipu, reg, IDMAC_BAND_EN(dma_chan));
+
+       _ipu_ch_param_set_bandmode(ipu, dma_chan, band_height);
+       dev_dbg(ipu->dev, "dma_chan:%d, band_height:%d.\n\n",
+                               dma_chan, 1 << band_height);
+       _ipu_unlock(ipu);
+
+       return ret;
+}
+EXPORT_SYMBOL(ipu_set_channel_bandmode);
 
 /*!
  * This function is called to initialize a buffer for logical IPU channel.
@@ -1688,6 +1773,17 @@ int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel
                    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
                    FS_PRPVF_ROT_DEST_SEL_OFFSET;
                break;
+       case MEM_VDOA_MEM:
+               fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+               if (MEM_VDI_MEM == dest_ch)
+                       fs_proc_flow3 |= FS_VDOA_DEST_SEL_VDI;
+               else if (MEM_PP_MEM == dest_ch)
+                       fs_proc_flow3 |= FS_VDOA_DEST_SEL_IC;
+               else {
+                       retval = -EINVAL;
+                       goto err;
+               }
+               break;
        default:
                retval = -EINVAL;
                goto err;
@@ -1696,8 +1792,11 @@ int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel
        switch (dest_ch) {
        case MEM_PP_MEM:
                fs_proc_flow1 &= ~FS_PP_SRC_SEL_MASK;
-               fs_proc_flow1 |=
-                   proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PP_SRC_SEL_OFFSET;
+               if (MEM_VDOA_MEM == src_ch)
+                       fs_proc_flow1 |= FS_PP_SRC_SEL_VDOA;
+               else
+                       fs_proc_flow1 |= proc_src_sel[IPU_CHAN_ID(src_ch)] <<
+                                               FS_PP_SRC_SEL_OFFSET;
                break;
        case MEM_ROT_PP_MEM:
                fs_proc_flow1 &= ~FS_PP_ROT_SRC_SEL_MASK;
@@ -1766,6 +1865,15 @@ int32_t ipu_link_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_channel
                    disp_src_sel[IPU_CHAN_ID(src_ch)] <<
                    FS_DP_ASYNC1_SRC_SEL_OFFSET;
                break;
+       case MEM_VDI_MEM:
+               fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+               if (MEM_VDOA_MEM == src_ch)
+                       fs_proc_flow1 |= FS_VDI_SRC_SEL_VDOA;
+               else {
+                       retval = -EINVAL;
+                       goto err;
+               }
+               break;
        default:
                retval = -EINVAL;
                goto err;
@@ -1851,6 +1959,9 @@ int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_chann
        case MEM_ROT_VF_MEM:
                fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
                break;
+       case MEM_VDOA_MEM:
+               fs_proc_flow3 &= ~FS_VDOA_DEST_SEL_MASK;
+               break;
        default:
                retval = -EINVAL;
                goto err;
@@ -1896,6 +2007,9 @@ int32_t ipu_unlink_channels(struct ipu_soc *ipu, ipu_channel_t src_ch, ipu_chann
        case MEM_FG_ASYNC0:
                fs_disp_flow1 &= ~FS_DP_ASYNC1_SRC_SEL_MASK;
                break;
+       case MEM_VDI_MEM:
+               fs_proc_flow1 &= ~FS_VDI_SRC_SEL_MASK;
+               break;
        default:
                retval = -EINVAL;
                goto err;
@@ -2040,7 +2154,8 @@ int32_t ipu_enable_channel(struct ipu_soc *ipu, ipu_channel_t channel)
        }
 
        if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
-               _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
+               _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+               _ipu_is_vdi_out_chan(out_dma))
                _ipu_ic_enable_task(ipu, channel);
 
        ipu->channel_enable_mask |= 1L << IPU_CHAN_ID(channel);
@@ -2262,7 +2377,8 @@ int32_t ipu_disable_channel(struct ipu_soc *ipu, ipu_channel_t channel, bool wai
 
        /* Disable IC task */
        if (_ipu_is_ic_chan(in_dma) || _ipu_is_ic_chan(out_dma) ||
-               _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma))
+               _ipu_is_irt_chan(in_dma) || _ipu_is_irt_chan(out_dma) ||
+               _ipu_is_vdi_out_chan(out_dma))
                _ipu_ic_disable_task(ipu, channel);
 
        /* Disable DMA channel(s) */
@@ -2715,7 +2831,9 @@ uint32_t ipu_channel_status(struct ipu_soc *ipu, ipu_channel_t channel)
        uint32_t dma_status;
 
        _ipu_lock(ipu);
+       _ipu_get(ipu);
        dma_status = ipu_is_channel_busy(ipu, channel);
+       _ipu_put(ipu);
        _ipu_unlock(ipu);
 
        dev_dbg(ipu->dev, "%s, dma_status:%d.\n", __func__, dma_status);
index ddfab2df3fd0f9e7ec65e6606c253ce3cfa97e9f..c7d37df019ed85d6ad9d0c41ce5defce6daffd5d 100644 (file)
@@ -42,6 +42,7 @@
 #include "ipu_prv.h"
 #include "ipu_regs.h"
 #include "ipu_param_mem.h"
+#include "vdoa.h"
 
 #define CHECK_RETCODE(cont, str, err, label, ret)                      \
 do {                                                                   \
@@ -113,6 +114,7 @@ do {                                                                        \
 #define        IPU_PP_CH_VF    (IPU_TASK_ID_VF - 1)
 #define        IPU_PP_CH_PP    (IPU_TASK_ID_PP - 1)
 #define MAX_PP_CH      (IPU_TASK_ID_MAX - 1)
+#define VDOA_DEF_TIMEOUT_MS    (HZ/2)
 
 /* Strucutures and variables for exporting MXC IPU as device*/
 typedef enum {
@@ -134,9 +136,19 @@ typedef enum {
        STATE_LINK_CHAN_FAIL,
        STATE_UNLINK_CHAN_FAIL,
        STATE_INIT_CHAN_BUF_FAIL,
+       STATE_INIT_CHAN_BAND_FAIL,
        STATE_SYS_NO_MEM,
+       STATE_VDOA_IRQ_TIMEOUT,
+       STATE_VDOA_IRQ_FAIL,
+       STATE_VDOA_TASK_FAIL,
 } ipu_state_t;
 
+enum {
+       INPUT_CHAN_VDI_P = 1,
+       INPUT_CHAN,
+       INPUT_CHAN_VDI_N,
+};
+
 struct ipu_state_msg {
        int state;
        char *msg;
@@ -159,7 +171,11 @@ struct ipu_state_msg {
        {STATE_LINK_CHAN_FAIL, "ipu link channel fail"},
        {STATE_UNLINK_CHAN_FAIL, "ipu unlink channel fail"},
        {STATE_INIT_CHAN_BUF_FAIL, "ipu init channel buffer fail"},
+       {STATE_INIT_CHAN_BAND_FAIL, "ipu init channel band mode fail"},
        {STATE_SYS_NO_MEM, "sys no mem: -ENOMEM"},
+       {STATE_VDOA_IRQ_TIMEOUT, "wait for vdoa irq timeout"},
+       {STATE_VDOA_IRQ_FAIL, "vdoa irq fail"},
+       {STATE_VDOA_TASK_FAIL, "vdoa task fail"},
 };
 
 struct stripe_setting {
@@ -186,14 +202,32 @@ struct task_set {
 #define        IC_MODE         0x1
 #define        ROT_MODE        0x2
 #define        VDI_MODE        0x4
+#define IPU_PREPROCESS_MODE_MASK       (IC_MODE | ROT_MODE | VDI_MODE)
+/* VDOA_MODE means this task use vdoa, and VDOA has two modes:
+ * BAND MODE and non-BAND MODE. Non-band mode will do transfer data
+ * to memory. BAND mode needs hareware sync with IPU, it is used default
+ * if connected to VDIC.
+ */
+#define        VDOA_MODE       0x8
+#define        VDOA_BAND_MODE  0x10
        u8      mode;
 #define IC_VF  0x1
 #define IC_PP  0x2
 #define ROT_VF 0x4
 #define ROT_PP 0x8
 #define VDI_VF 0x10
+#define        VDOA_ONLY       0x20
        u8      task;
-
+#define NO_SPLIT       0x0
+#define RL_SPLIT       0x1
+#define UD_SPLIT       0x2
+#define LEFT_STRIPE    0x1
+#define RIGHT_STRIPE   0x2
+#define UP_STRIPE      0x4
+#define DOWN_STRIPE    0x8
+#define SPLIT_MASK     0xF
+       u8      split_mode;
+       u8      band_lines;
        ipu_channel_t ic_chan;
        ipu_channel_t rot_chan;
        ipu_channel_t vdi_ic_p_chan;
@@ -223,15 +257,6 @@ struct task_set {
        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
-#define SPLIT_MASK     0xF
-       u8 split_mode;
        struct stripe_setting sp_setting;
 };
 
@@ -276,10 +301,17 @@ struct ipu_task_entry {
 
        struct ipu_task_entry *parent;
        char *vditmpbuf[2];
-       bool buf1filled;
-       bool buf0filled;
        u32 old_save_lines;
        u32 old_size;
+       bool buf1filled;
+       bool buf0filled;
+
+       vdoa_handle_t vdoa_handle;
+       struct vdoa_output_mem {
+               void *vaddr;
+               dma_addr_t paddr;
+               int size;
+       } vdoa_dma;
 
 #ifdef DBG_IPU_PERF
        struct timespec ts_queue;
@@ -294,6 +326,7 @@ struct ipu_task_entry {
 struct ipu_channel_tabel {
        struct mutex    lock;
        u8              used[MXC_IPU_MAX_NUM][MAX_PP_CH];
+       u8              vdoa_used;
 };
 
 struct ipu_thread_data {
@@ -336,18 +369,33 @@ static bool deinterlace_3_field(struct ipu_task_entry *t)
                (t->input.deinterlace.motion != HIGH_MOTION));
 }
 
+static u32 tiled_filed_size(struct ipu_task_entry *t)
+{
+       u32 y_size;
+       u32 field_size;
+
+       /* note: page_align is required by VPU hw ouput buffer */
+       y_size = t->input.width * t->input.height/2;
+       field_size = ALIGN(y_size, SZ_4K) + ALIGN(y_size/2, SZ_4K);
+
+       return field_size;
+}
+
 static bool only_ic(u8 mode)
 {
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
        return ((mode == IC_MODE) || (mode == VDI_MODE));
 }
 
 static bool only_rot(u8 mode)
 {
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
        return (mode == ROT_MODE);
 }
 
 static bool ic_and_rot(u8 mode)
 {
+       mode = mode & IPU_PREPROCESS_MODE_MASK;
        return ((mode == (IC_MODE | ROT_MODE)) ||
                 (mode == (VDI_MODE | ROT_MODE)));
 }
@@ -420,6 +468,8 @@ cs_t colorspaceofpixel(int fmt)
        case IPU_PIX_FMT_YUV422P:
        case IPU_PIX_FMT_YUV444:
        case IPU_PIX_FMT_NV12:
+       case IPU_PIX_FMT_TILED_NV12:
+       case IPU_PIX_FMT_TILED_NV12F:
                return YUV_CS;
                break;
        default:
@@ -444,9 +494,9 @@ int need_csc(int ifmt, int ofmt)
 }
 EXPORT_SYMBOL_GPL(need_csc);
 
-static int soc_max_in_width(void)
+static int soc_max_in_width(u32 is_vdoa)
 {
-       return 4096;
+       return is_vdoa ? 8192 : 4096;
 }
 
 static int soc_max_in_height(void)
@@ -622,20 +672,46 @@ static void dump_check_warn(struct device *dev, int warn)
                dev_warn(dev, "overlay u/v offset not 8 align\n");
 }
 
-static int set_crop(struct ipu_crop *crop, int width, int height)
+static int set_crop(struct ipu_crop *crop, int width, int height, int fmt)
 {
-       if (crop->w || crop->h) {
-               if (((crop->w + crop->pos.x) > width)
-               || ((crop->h + crop->pos.y) > height))
-                       return -EINVAL;
+       if ((IPU_PIX_FMT_TILED_NV12 == fmt) ||
+               (IPU_PIX_FMT_TILED_NV12F == fmt)) {
+               if (crop->w || crop->h) {
+                       if (((crop->w + crop->pos.x) > width)
+                       || ((crop->h + crop->pos.y) > height)
+                       || (0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->pos.x % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->pos.y % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       ) {
+                               pr_err("set_crop error MB align.\n");
+                               return -EINVAL;
+                       }
+               } else {
+                       crop->pos.x = 0;
+                       crop->pos.y = 0;
+                       crop->w = width;
+                       crop->h = height;
+                       if ((0 != (crop->w % IPU_PIX_FMT_TILED_NV12_MBALIGN))
+                       || (0 != (crop->h % IPU_PIX_FMT_TILED_NV12_MBALIGN))) {
+                               pr_err("set_crop error w/h MB align.\n");
+                               return -EINVAL;
+                       }
+               }
        } else {
-               crop->pos.x = 0;
-               crop->pos.y = 0;
-               crop->w = width;
-               crop->h = 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;
        }
-       crop->w -= crop->w%8;
-       crop->h -= crop->h%8;
 
        return 0;
 }
@@ -677,6 +753,26 @@ static void update_offset(unsigned int fmt,
                *uoff = (width * (height - pos_y) - pos_x)
                        + width * pos_y/2 + pos_x;
                break;
+       case IPU_PIX_FMT_TILED_NV12:
+               /*
+                * tiled format, progressive:
+                * assuming that line is aligned with MB height (aligned to 16)
+                * offset = line * stride + (pixel / MB_width) * pixels_in_MB
+                * = line * stride + (pixel / 16) * 256
+                * = line * stride + pixel * 16
+                */
+               *off = pos_y * width + (pos_x << 4);
+               *uoff = ALIGN(width * height, SZ_4K) + (*off >> 1);
+               break;
+       case IPU_PIX_FMT_TILED_NV12F:
+               /*
+                * tiled format, interlaced:
+                * same as above, only number of pixels in MB is 128,
+                * instead of 256
+                */
+               *off = (pos_y >> 1) * width + (pos_x << 3);
+               *uoff = ALIGN(width * height/2, SZ_4K) + (*off >> 1);
+               break;
        default:
                *off = (pos_y * width + pos_x) * fmt_to_bpp(fmt)/8;
                break;
@@ -774,8 +870,19 @@ static int check_task(struct ipu_task_entry *t)
        int ret = IPU_CHECK_OK;
        int timeout;
 
+       if ((IPU_PIX_FMT_TILED_NV12 == t->overlay.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->overlay.format) ||
+               (IPU_PIX_FMT_TILED_NV12 == t->output.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->output.format) ||
+               ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+                       !t->input.deinterlace.enable)) {
+               ret = IPU_CHECK_ERR_NOT_SUPPORT;
+               goto done;
+       }
+
        /* check input */
-       ret = set_crop(&t->input.crop, t->input.width, t->input.height);
+       ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+               t->input.format);
        if (ret < 0) {
                ret = IPU_CHECK_ERR_INPUT_CROP;
                goto done;
@@ -786,7 +893,8 @@ static int check_task(struct ipu_task_entry *t)
                                &t->set.i_voff, &t->set.istride);
 
        /* check output */
-       ret = set_crop(&t->output.crop, t->output.width, t->output.height);
+       ret = set_crop(&t->output.crop, t->output.width, t->output.height,
+               t->output.format);
        if (ret < 0) {
                ret = IPU_CHECK_ERR_OUTPUT_CROP;
                goto done;
@@ -797,13 +905,32 @@ static int check_task(struct ipu_task_entry *t)
                                &t->set.o_off, &t->set.o_uoff,
                                &t->set.o_voff, &t->set.ostride);
 
+       if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               if ((t->input.crop.w > soc_max_in_width(1)) ||
+                       (t->input.crop.h > soc_max_in_height())) {
+                       ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+                       goto done;
+               }
+               /* output fmt: NV12 and YUYV, now don't support resize */
+               if (((IPU_PIX_FMT_NV12 != t->output.format) &&
+                               (IPU_PIX_FMT_YUYV != t->output.format)) ||
+                       (t->input.crop.w != t->output.crop.w) ||
+                       (t->input.crop.h != t->output.crop.h)) {
+                       ret = IPU_CHECK_ERR_NOT_SUPPORT;
+                       goto done;
+               }
+       }
+
        /* check overlay if there is */
        if (t->overlay_en) {
                if (t->input.deinterlace.enable) {
                        ret = IPU_CHECK_ERR_OVERLAY_WITH_VDI;
                        goto done;
                }
-               ret = set_crop(&t->overlay.crop, t->overlay.width, t->overlay.height);
+
+               ret = set_crop(&t->overlay.crop, t->overlay.width,
+                       t->overlay.height, t->overlay.format);
                if (ret < 0) {
                        ret = IPU_CHECK_ERR_OVERLAY_CROP;
                        goto done;
@@ -834,10 +961,13 @@ static int check_task(struct ipu_task_entry *t)
        }
 
        /* 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;
+       if (!((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format))) {
+               if ((t->input.crop.w > soc_max_in_width(0)) ||
+                       (t->input.crop.h > soc_max_in_height())) {
+                               ret = IPU_CHECK_ERR_INPUT_OVER_LIMIT;
+                               goto done;
+               }
        }
 
        /* check task mode */
@@ -877,8 +1007,20 @@ static int check_task(struct ipu_task_entry *t)
                t->set.mode &= ~IC_MODE;
                t->set.mode |= VDI_MODE;
        }
+       if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               if (t->set.mode & ROT_MODE) {
+                       ret = IPU_CHECK_ERR_NOT_SUPPORT;
+                       goto done;
+               }
+               t->set.mode |= VDOA_MODE;
+               if (IPU_PIX_FMT_TILED_NV12F == t->input.format)
+                       t->set.mode |= VDOA_BAND_MODE;
+               t->set.mode &= ~IC_MODE;
+       }
 
-       if (t->set.mode & (IC_MODE | VDI_MODE)) {
+       if ((t->set.mode & (IC_MODE | VDI_MODE)) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
                if (t->output.crop.w > soc_max_out_width())
                        t->set.split_mode |= RL_SPLIT;
                if (t->output.crop.h > soc_max_out_height())
@@ -945,12 +1087,26 @@ static int prepare_task(struct ipu_task_entry *t)
                        t->set.task |= ROT_VF;
        }
 
+       if (VDOA_MODE == t->set.mode) {
+               if (t->set.task != 0) {
+                       dev_err(t->dev, "ERR: vdoa only task:0x%x, [0x%p].\n",
+                                       t->set.task, t);
+                       BUG();
+               }
+               t->set.task |= VDOA_ONLY;
+       }
+
+       if (VDOA_BAND_MODE & t->set.mode) {
+               /* to save band size: 1<<3 = 8 lines */
+               t->set.band_lines = 3;
+       }
+
        dump_task_info(t);
 
        return ret;
 }
 
-static uint32_t ipu_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
+static uint32_t ic_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
 {
        uint32_t        status;
        uint32_t        status_vf;
@@ -968,32 +1124,32 @@ static uint32_t ipu_vf_pp_is_busy(struct ipu_soc *ipu, bool is_vf)
        }
 }
 
-static void put_ipu_res(struct ipu_task_entry *tsk)
-{
-       int ret;
-       struct ipu_channel_tabel        *tbl = &ipu_ch_tbl;
-
-       if (!tsk)
-               BUG();
-       mutex_lock(&tbl->lock);
-       if (tsk) {
-               tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
-               ret = atomic_inc_return(&tsk->res_free);
-               if (ret == 2)
-                       BUG();
-       }
-       mutex_unlock(&tbl->lock);
-}
-
-static int get_ipu_res(struct ipu_task_entry *t)
+static int _get_vdoa_ipu_res(struct ipu_task_entry *t)
 {
        int             i;
        struct ipu_soc  *ipu;
        u8              *used;
-       uint32_t        found = 0;
+       uint32_t        found_ipu = 0;
+       uint32_t        found_vdoa = 0;
        struct ipu_channel_tabel        *tbl = &ipu_ch_tbl;
 
        mutex_lock(&tbl->lock);
+       if (t->set.mode & VDOA_MODE) {
+               if (NULL != t->vdoa_handle)
+                       found_vdoa = 1;
+               else {
+                       found_vdoa = tbl->vdoa_used ? 0 : 1;
+                       if (found_vdoa) {
+                               tbl->vdoa_used = 1;
+                               vdoa_get_handle(&t->vdoa_handle);
+                       } else
+                               /* first get vdoa->ipu resource sequence */
+                               goto out;
+                       if (t->set.task & VDOA_ONLY)
+                               goto out;
+               }
+       }
+
        for (i = 0; i < MXC_IPU_MAX_NUM; i++) {
                ipu = ipu_get_soc(i);
                if (IS_ERR(ipu))
@@ -1003,7 +1159,7 @@ static int get_ipu_res(struct ipu_task_entry *t)
                if (t->set.mode & VDI_MODE) {
                        if (0 == *used) {
                                *used = 1;
-                               found = 1;
+                               found_ipu = 1;
                                break;
                        }
                } else if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
@@ -1014,13 +1170,13 @@ static int get_ipu_res(struct ipu_task_entry *t)
                                if (t->set.mode & ROT_MODE)
                                        t->set.task |= ROT_VF;
                                *used = 1;
-                               found = 1;
+                               found_ipu = 1;
                                break;
                        }
                } else
                        BUG();
        }
-       if (found)
+       if (found_ipu)
                goto next;
 
        for (i = 0; i < MXC_IPU_MAX_NUM; i++) {
@@ -1028,8 +1184,8 @@ static int get_ipu_res(struct ipu_task_entry *t)
                if (IS_ERR(ipu))
                        BUG();
 
-               used = &tbl->used[i][IPU_PP_CH_PP];
                if ((t->set.mode & IC_MODE) || only_rot(t->set.mode)) {
+                       used = &tbl->used[i][IPU_PP_CH_PP];
                        if (0 == *used) {
                                t->task_id = IPU_TASK_ID_PP;
                                if (t->set.mode & IC_MODE)
@@ -1037,28 +1193,68 @@ static int get_ipu_res(struct ipu_task_entry *t)
                                if (t->set.mode & ROT_MODE)
                                        t->set.task |= ROT_PP;
                                *used = 1;
-                               found = 1;
+                               found_ipu = 1;
                                break;
                        }
                }
        }
 
 next:
-       if (found) {
+       if (found_ipu) {
                t->ipu = ipu;
                t->ipu_id = i;
                t->dev = ipu->dev;
                if (atomic_inc_return(&t->res_get) == 2)
                        BUG();
        }
+out:
+       dev_dbg(t->dev,
+               "%s:no:0x%x,found_vdoa:%d, found_ipu:%d\n",
+                __func__, t->task_no, found_vdoa, found_ipu);
        mutex_unlock(&tbl->lock);
-
-       return found;
+       if (t->set.task & VDOA_ONLY)
+               return found_vdoa;
+       else if (t->set.mode & VDOA_MODE)
+               return found_vdoa && found_ipu;
+       else
+               return found_ipu;
 }
 
-static void put_vdoa_ipu_res(struct ipu_task_entry *tsk)
+static void put_vdoa_ipu_res(struct ipu_task_entry *tsk, int vdoa_only)
 {
-       put_ipu_res(tsk);
+       int ret;
+       int rel_vdoa = 0, rel_ipu = 0;
+       struct ipu_channel_tabel        *tbl = &ipu_ch_tbl;
+
+       if (!tsk)
+               BUG();
+       mutex_lock(&tbl->lock);
+       if (tsk->set.mode & VDOA_MODE) {
+               if (!tbl->vdoa_used && tsk->vdoa_handle)
+                       BUG();
+               if (tbl->vdoa_used && tsk->vdoa_handle) {
+                       tbl->vdoa_used = 0;
+                       vdoa_put_handle(&tsk->vdoa_handle);
+                       if (tsk->ipu)
+                               tsk->ipu->vdoa_en = 0;
+                       rel_vdoa = 1;
+                       if (vdoa_only || (tsk->set.task & VDOA_ONLY))
+                               goto out;
+               }
+       }
+
+       if (tsk) {
+               tbl->used[tsk->ipu_id][tsk->task_id - 1] = 0;
+               rel_ipu = 1;
+               ret = atomic_inc_return(&tsk->res_free);
+               if (ret == 2)
+                       BUG();
+       }
+out:
+       dev_dbg(tsk->dev,
+               "%s:no:0x%x,rel_vdoa:%d, rel_ipu:%d\n",
+                __func__, tsk->task_no, rel_vdoa, rel_ipu);
+       mutex_unlock(&tbl->lock);
 }
 
 static int get_vdoa_ipu_res(struct ipu_task_entry *t)
@@ -1066,7 +1262,7 @@ static int get_vdoa_ipu_res(struct ipu_task_entry *t)
        int             ret;
        uint32_t        found = 0;
 
-       found = get_ipu_res(t);
+       found = _get_vdoa_ipu_res(t);
        if (!found) {
                t->ipu_id = -1;
                t->ipu = NULL;
@@ -1074,7 +1270,7 @@ static int get_vdoa_ipu_res(struct ipu_task_entry *t)
                ret = atomic_inc_return(&req_cnt);
                dev_dbg(t->dev,
                        "wait_res:no:0x%x,req_cnt:%d\n", t->task_no, ret);
-               ret = wait_event_timeout(res_waitq, get_ipu_res(t),
+               ret = wait_event_timeout(res_waitq, _get_vdoa_ipu_res(t),
                                 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
                if (ret == 0) {
                        dev_err(t->dev, "ERR[0x%p,no-0x%x] wait_res timeout:%dms!\n",
@@ -1083,7 +1279,7 @@ static int get_vdoa_ipu_res(struct ipu_task_entry *t)
                        t->state = STATE_RES_TIMEOUT;
                        goto out;
                } else {
-                       if (!t->ipu)
+                       if (!(t->set.task & VDOA_ONLY) && (!t->ipu))
                                BUG();
                        ret = atomic_read(&req_cnt);
                        if (ret > 0)
@@ -1107,7 +1303,6 @@ static struct ipu_task_entry *create_task_entry(struct ipu_task *task)
        tsk = kzalloc(sizeof(struct ipu_task_entry), GFP_KERNEL);
        if (!tsk)
                return ERR_PTR(-ENOMEM);
-
        kref_init(&tsk->refcount);
        tsk->state = -EINVAL;
        tsk->ipu_id = -1;
@@ -1134,7 +1329,7 @@ static void task_mem_free(struct kref *ref)
        kfree(tsk);
 }
 
-int ipu_queue_sp_task(struct ipu_split_task *sp_task)
+int create_split_child_task(struct ipu_split_task *sp_task)
 {
        int ret = 0;
        struct ipu_task_entry *tsk;
@@ -1364,9 +1559,9 @@ static int create_split_task(
                break;
        }
 
-       ret = ipu_queue_sp_task(sp_task);
+       ret = create_split_child_task(sp_task);
        if (ret < 0)
-               dev_err(t->dev, "ERR:ipu_queue_sp_task() ret:%d\n", ret);
+               dev_err(t->dev, "ERR:create_split_child_task() ret:%d\n", ret);
        return ret;
 }
 
@@ -1426,13 +1621,13 @@ err_start:
                if (err[j] < 0) {
                        if (sp_task[j].child_task)
                                dev_err(t->dev,
-                                "sp_task[%d],no-0x%x state:%d, Q err:%d.\n",
+                                "sp_task[%d],no-0x%x fail state:%d, queue err:%d.\n",
                                j, sp_task[j].child_task->task_no,
                                sp_task[j].child_task->state, err[j]);
                        goto err_exit;
                }
-               dev_dbg(t->dev, "sp_tsk[%d], no-0x%x state:%s, queue ret:%d.\n",
-                       j, sp_task[j].child_task->task_no,
+               dev_dbg(t->dev, "[0x%p] sp_task[%d], no-0x%x state:%s, queue ret:%d.\n",
+                       sp_task[j].child_task, j, sp_task[j].child_task->task_no,
                        state_msg[sp_task[j].child_task->state].msg, err[j]);
        }
 
@@ -1453,6 +1648,170 @@ err_exit:
 
 }
 
+static int init_tiled_buf(struct ipu_soc *ipu, struct ipu_task_entry *t,
+                               ipu_channel_t channel, uint32_t ch_type)
+{
+       int ret = 0;
+       int i;
+       uint32_t ipu_fmt;
+       dma_addr_t inbuf_base = 0;
+       u32 field_size;
+       struct vdoa_params param;
+       struct vdoa_ipu_buf buf;
+       struct ipu_soc *ipu_idx;
+       u32 ipu_stride, obuf_size;
+       u32 height, width;
+       ipu_buffer_t type;
+
+       if ((IPU_PIX_FMT_YUYV != t->output.format) &&
+               (IPU_PIX_FMT_NV12 != t->output.format)) {
+               dev_err(t->dev, "ERR:[0x%d] output format\n", t->task_no);
+               return -EINVAL;
+       }
+
+       memset(&param, 0, sizeof(param));
+       /* init channel tiled bufs */
+       if (deinterlace_3_field(t) &&
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               field_size = tiled_filed_size(t);
+               if (INPUT_CHAN_VDI_P == ch_type) {
+                       inbuf_base = t->input.paddr + field_size;
+                       param.vfield_buf.prev_veba = inbuf_base + t->set.i_off;
+               } else if (INPUT_CHAN == ch_type) {
+                       inbuf_base = t->input.paddr_n;
+                       param.vfield_buf.cur_veba = inbuf_base + t->set.i_off;
+               } else if (INPUT_CHAN_VDI_N == ch_type) {
+                       inbuf_base = t->input.paddr_n + field_size;
+                       param.vfield_buf.next_veba = inbuf_base + t->set.i_off;
+               } else
+                       return -EINVAL;
+               height = t->input.crop.h >> 1; /* field format for vdoa */
+               width = t->input.crop.w;
+               param.vfield_buf.vubo = t->set.i_uoff;
+               param.interlaced = 1;
+               param.scan_order = 1;
+               type = IPU_INPUT_BUFFER;
+       } else if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) &&
+                       (INPUT_CHAN == ch_type)) {
+               height = t->input.crop.h;
+               width = t->input.crop.w;
+               param.vframe_buf.veba = t->input.paddr + t->set.i_off;
+               param.vframe_buf.vubo = t->set.i_uoff;
+               type = IPU_INPUT_BUFFER;
+       } else
+               return -EINVAL;
+
+       param.band_mode = (t->set.mode & VDOA_BAND_MODE) ? 1 : 0;
+       if (param.band_mode && (t->set.band_lines != 3) &&
+                (t->set.band_lines != 4) && (t->set.band_lines != 5))
+               return -EINVAL;
+       else if (param.band_mode)
+               param.band_lines = (1 << t->set.band_lines);
+       for (i = 0; i < MXC_IPU_MAX_NUM; i++) {
+               ipu_idx = ipu_get_soc(i);
+               if (!IS_ERR(ipu_idx) && ipu_idx == ipu)
+                       break;
+       }
+       if (t->set.task & VDOA_ONLY)
+               /* dummy, didn't need ipu res */
+               i = 0;
+       if (MXC_IPU_MAX_NUM == i) {
+               dev_err(t->dev, "ERR:[0x%p] get ipu num\n", t);
+               return -EINVAL;
+       }
+
+       param.ipu_num = i;
+       param.vpu_stride = t->input.width;
+       param.height = height;
+       param.width = width;
+       if (IPU_PIX_FMT_NV12 == t->output.format)
+               param.pfs = VDOA_PFS_NV12;
+       else
+               param.pfs = VDOA_PFS_YUYV;
+       ipu_fmt = (param.pfs == VDOA_PFS_YUYV) ? IPU_PIX_FMT_YUYV :
+                               IPU_PIX_FMT_NV12;
+       ipu_stride = param.width * bytes_per_pixel(ipu_fmt);
+       obuf_size = PAGE_ALIGN(param.width * param.height *
+                               fmt_to_bpp(ipu_fmt)/8);
+       dev_dbg(t->dev, "band_mode:%d, band_lines:%d\n",
+                       param.band_mode, param.band_lines);
+       if (!param.band_mode) {
+               /* note: if only for tiled -> raster convert and
+                  no other post-processing, we don't need alloc buf
+                  and use output buffer directly.
+               */
+               if (t->set.task & VDOA_ONLY)
+                       param.ieba0 = t->output.paddr;
+               else {
+                       dev_err(t->dev, "ERR:[0x%d] vdoa task\n", t->task_no);
+                       return -EINVAL;
+               }
+       } else {
+               if (IPU_PIX_FMT_TILED_NV12F != t->input.format) {
+                       dev_err(t->dev, "ERR [0x%d] vdoa task\n", t->task_no);
+                       return -EINVAL;
+               }
+       }
+       vdoa_setup(t->vdoa_handle, &param);
+       vdoa_get_output_buf(t->vdoa_handle, &buf);
+       if (t->set.task & VDOA_ONLY)
+               goto done;
+
+       ret = ipu_init_channel_buffer(ipu,
+                       channel,
+                       type,
+                       ipu_fmt,
+                       width,
+                       height,
+                       ipu_stride,
+                       IPU_ROTATE_NONE,
+                       buf.ieba0,
+                       buf.ieba1,
+                       0,
+                       buf.iubo,
+                       0);
+       if (ret < 0) {
+               t->state = STATE_INIT_CHAN_BUF_FAIL;
+               goto done;
+       }
+
+       if (param.band_mode) {
+               ret = ipu_set_channel_bandmode(ipu, channel,
+                               type, t->set.band_lines);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BAND_FAIL;
+                       goto done;
+               }
+       }
+done:
+       return ret;
+}
+
+static int init_tiled_ch_bufs(struct ipu_soc *ipu, struct ipu_task_entry *t)
+{
+       int ret = 0;
+
+       if (IPU_PIX_FMT_TILED_NV12 == t->input.format) {
+               ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+               CHECK_RETCODE(ret < 0, "init tiled_ch", t->state, done, ret);
+       } else if (IPU_PIX_FMT_TILED_NV12F == t->input.format) {
+               ret = init_tiled_buf(ipu, t, t->set.ic_chan, INPUT_CHAN);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-c", t->state, done, ret);
+               ret = init_tiled_buf(ipu, t, t->set.vdi_ic_p_chan,
+                                       INPUT_CHAN_VDI_P);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-p", t->state, done, ret);
+               ret = init_tiled_buf(ipu, t, t->set.vdi_ic_n_chan,
+                                       INPUT_CHAN_VDI_N);
+               CHECK_RETCODE(ret < 0, "init tiled_ch-n", t->state, done, ret);
+       } else {
+               ret = -EINVAL;
+               BUG();
+       }
+
+done:
+       return ret;
+}
+
 static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
 {
        int ret = 0;
@@ -1515,14 +1874,25 @@ static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
                }
        }
 
+       if (t->set.mode & VDOA_MODE)
+               ipu->vdoa_en = 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 (!(t->set.task & VDOA_ONLY)) {
+               ret = ipu_init_channel(ipu, t->set.ic_chan, &params);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_FAIL;
+                       goto done;
+               }
        }
 
        if (deinterlace_3_field(t)) {
+               if (IPU_DEINTERLACE_FIELD_TOP == t->input.deinterlace.field_fmt)
+                       params.mem_prp_vf_mem.field_fmt = V4L2_FIELD_INTERLACED_TB;
+               else if (IPU_DEINTERLACE_FIELD_BOTTOM == t->input.deinterlace.field_fmt)
+                       params.mem_prp_vf_mem.field_fmt = V4L2_FIELD_INTERLACED_BT;
+               else
+                       BUG();
                ret = ipu_init_channel(ipu, t->set.vdi_ic_p_chan, &params);
                if (ret < 0) {
                        t->state = STATE_INIT_CHAN_FAIL;
@@ -1536,39 +1906,51 @@ static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
        }
 
        /* init channel bufs */
-       if (deinterlace_3_field(t)) {
-               inbuf_p = t->input.paddr + t->set.istride + t->set.i_off;
-               inbuf = t->input.paddr_n + t->set.i_off;
-               inbuf_n = t->input.paddr_n + t->set.istride + t->set.i_off;
-       } else
-               inbuf = t->input.paddr + t->set.i_off;
+       if ((IPU_PIX_FMT_TILED_NV12 == t->input.format) ||
+               (IPU_PIX_FMT_TILED_NV12F == t->input.format)) {
+               ret = init_tiled_ch_bufs(ipu, t);
+               if (ret < 0)
+                       goto done;
+       } else {
+               if ((deinterlace_3_field(t)) &&
+                       (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+                               inbuf_p = t->input.paddr + t->set.istride +
+                                               t->set.i_off;
+                               inbuf = t->input.paddr_n + t->set.i_off;
+                               inbuf_n = t->input.paddr_n + t->set.istride +
+                                               t->set.i_off;
+               } else
+                       inbuf = t->input.paddr + t->set.i_off;
 
-       if (t->overlay_en) {
-               ovbuf = t->overlay.paddr + t->set.ov_off;
-               if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL)
-                       ov_alp_buf = t->overlay.alpha.loc_alp_paddr
-                               + t->set.ov_alpha_off;
+               if (t->overlay_en)
+                       ovbuf = t->overlay.paddr + t->set.ov_off;
        }
+       if (t->overlay_en && (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL))
+               ov_alp_buf = t->overlay.alpha.loc_alp_paddr
+                       + t->set.ov_alpha_off;
 
-       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 ((IPU_PIX_FMT_TILED_NV12 != t->input.format) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
+               ret = ipu_init_channel_buffer(ipu,
+                               t->set.ic_chan,
+                               IPU_INPUT_BUFFER,
+                               t->input.format,
+                               t->input.crop.w,
+                               t->input.crop.h,
+                               t->set.istride,
+                               IPU_ROTATE_NONE,
+                               inbuf,
+                               0,
+                               0,
+                               t->set.i_uoff,
+                               t->set.i_voff);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BUF_FAIL;
+                       goto done;
+               }
        }
-
-       if (deinterlace_3_field(t)) {
+       if (deinterlace_3_field(t) &&
+               (IPU_PIX_FMT_TILED_NV12F != t->input.format)) {
                ret = ipu_init_channel_buffer(ipu,
                                t->set.vdi_ic_p_chan,
                                IPU_INPUT_BUFFER,
@@ -1624,43 +2006,51 @@ static int init_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
                        t->state = STATE_INIT_CHAN_BUF_FAIL;
                        goto done;
                }
+       }
 
-               if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
-                       ret = ipu_init_channel_buffer(ipu,
-                                       t->set.ic_chan,
-                                       IPU_ALPHA_IN_BUFFER,
-                                       IPU_PIX_FMT_GENERIC,
-                                       t->overlay.crop.w,
-                                       t->overlay.crop.h,
-                                       t->set.ov_alpha_stride,
-                                       IPU_ROTATE_NONE,
-                                       ov_alp_buf,
-                                       0,
-                                       0,
-                                       0, 0);
-                       if (ret < 0) {
-                               t->state = STATE_INIT_CHAN_BUF_FAIL;
-                               goto done;
-                       }
+       if (t->overlay.alpha.mode == IPU_ALPHA_MODE_LOCAL) {
+               ret = ipu_init_channel_buffer(ipu,
+                               t->set.ic_chan,
+                               IPU_ALPHA_IN_BUFFER,
+                               IPU_PIX_FMT_GENERIC,
+                               t->overlay.crop.w,
+                               t->overlay.crop.h,
+                               t->set.ov_alpha_stride,
+                               IPU_ROTATE_NONE,
+                               ov_alp_buf,
+                               0,
+                               0,
+                               0, 0);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BUF_FAIL;
+                       goto done;
                }
        }
 
-       ret = ipu_init_channel_buffer(ipu,
-                       t->set.ic_chan,
-                       IPU_OUTPUT_BUFFER,
-                       out_fmt,
-                       out_w,
-                       out_h,
-                       out_stride,
-                       out_rot,
-                       outbuf,
-                       0,
-                       0,
-                       out_uoff,
-                       out_voff);
-       if (ret < 0) {
-               t->state = STATE_INIT_CHAN_BUF_FAIL;
-               goto done;
+       if (!(t->set.task & VDOA_ONLY)) {
+               ret = ipu_init_channel_buffer(ipu,
+                               t->set.ic_chan,
+                               IPU_OUTPUT_BUFFER,
+                               out_fmt,
+                               out_w,
+                               out_h,
+                               out_stride,
+                               out_rot,
+                               outbuf,
+                               0,
+                               0,
+                               out_uoff,
+                               out_voff);
+               if (ret < 0) {
+                       t->state = STATE_INIT_CHAN_BUF_FAIL;
+                       goto done;
+               }
+       }
+
+       if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+               ret = ipu_link_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+               CHECK_RETCODE(ret < 0, "ipu_link_ch vdoa_ic",
+                               STATE_LINK_CHAN_FAIL, done, ret);
        }
 
 done:
@@ -1669,6 +2059,13 @@ done:
 
 static void uninit_ic(struct ipu_soc *ipu, struct ipu_task_entry *t)
 {
+       int ret;
+
+       if ((t->set.mode & VDOA_BAND_MODE) && (t->set.task & VDI_VF)) {
+               ret = ipu_unlink_channels(ipu, MEM_VDOA_MEM, t->set.ic_chan);
+               CHECK_RETCODE_CONT(ret < 0, "ipu_unlink_ch vdoa_ic",
+                               STATE_UNLINK_CHAN_FAIL, ret);
+       }
        ipu_uninit_channel(ipu, t->set.ic_chan);
        if (deinterlace_3_field(t)) {
                ipu_uninit_channel(ipu, t->set.vdi_ic_p_chan);
@@ -1780,6 +2177,9 @@ static int get_irq(struct ipu_task_entry *t)
        case MEM_PP_MEM:
                irq = IPU_IRQ_PP_OUT_EOF;
                break;
+       case MEM_VDI_MEM:
+               irq = IPU_IRQ_VDIC_OUT_EOF;
+               break;
        default:
                irq = -EINVAL;
        }
@@ -1988,6 +2388,12 @@ static void do_task_release(struct ipu_task_entry *t, int fail)
 
        ipu_free_irq(ipu, t->irq, t);
 
+       if (t->vdoa_dma.vaddr)
+               dma_free_coherent(t->dev,
+                       t->vdoa_dma.size,
+                       t->vdoa_dma.vaddr,
+                       t->vdoa_dma.paddr);
+
        if (only_ic(t->set.mode)) {
                ret = ipu_disable_channel(ipu, t->set.ic_chan, true);
                CHECK_RETCODE_CONT(ret < 0, "ipu_disable_ch only_ic",
@@ -2042,6 +2448,22 @@ static void do_task_release(struct ipu_task_entry *t, int fail)
        return;
 }
 
+static void do_task_vdoa_only(struct ipu_task_entry *t)
+{
+       int ret;
+
+       ret = init_tiled_ch_bufs(NULL, t);
+       CHECK_RETCODE(ret < 0, "do_vdoa_only", STATE_ERR, out, ret);
+       ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+       vdoa_stop(t->vdoa_handle);
+       CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_only",
+                       STATE_VDOA_IRQ_TIMEOUT, out, ret);
+
+       t->state = STATE_OK;
+out:
+       return;
+}
+
 static void do_task(struct ipu_task_entry *t)
 {
        int r_size;
@@ -2051,11 +2473,13 @@ static void do_task(struct ipu_task_entry *t)
        struct ipu_soc *ipu = t->ipu;
 
        CHECK_PERF(&t->ts_dotask);
+
        if (!ipu) {
                t->state = STATE_NO_IPU;
                return;
        }
 
+       init_completion(&t->irq_comp);
        dev_dbg(ipu->dev, "[0x%p]Do task no:0x%x: id %d\n", (void *)t,
                 t->task_no, t->task_id);
        dump_task_info(t);
@@ -2067,12 +2491,23 @@ static void do_task(struct ipu_task_entry *t)
                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;
+               if (t->set.mode & VDOA_BAND_MODE) {
+                       t->set.ic_chan = MEM_VDI_MEM;
+                       if (deinterlace_3_field(t)) {
+                               t->set.vdi_ic_p_chan = MEM_VDI_MEM_P;
+                               t->set.vdi_ic_n_chan = MEM_VDI_MEM_N;
+                       }
+                       dev_dbg(ipu->dev, "[0x%p]ic ch MEM_VDI_MEM\n",
+                                        (void *)t);
+               } else {
+                       t->set.ic_chan = MEM_VDI_PRP_VF_MEM;
+                       if (deinterlace_3_field(t)) {
+                               t->set.vdi_ic_p_chan = MEM_VDI_PRP_VF_MEM_P;
+                               t->set.vdi_ic_n_chan = MEM_VDI_PRP_VF_MEM_N;
+                       }
+                       dev_dbg(ipu->dev,
+                               "[0x%p]ic ch MEM_VDI_PRP_VF_MEM\n", t);
                }
-               dev_dbg(ipu->dev, "[0x%p]ic channel MEM_VDI_PRP_VF_MEM\n", (void *)t);
        }
 
        if (t->set.task & ROT_PP) {
@@ -2084,9 +2519,9 @@ static void do_task(struct ipu_task_entry *t)
        }
 
        if (t->task_id == IPU_TASK_ID_VF)
-               busy = ipu_vf_pp_is_busy(ipu, true);
+               busy = ic_vf_pp_is_busy(ipu, true);
        else if (t->task_id == IPU_TASK_ID_PP)
-               busy = ipu_vf_pp_is_busy(ipu, false);
+               busy = ic_vf_pp_is_busy(ipu, false);
        else
                BUG();
        if (busy) {
@@ -2148,7 +2583,7 @@ static void do_task(struct ipu_task_entry *t)
                                                GFP_DMA | GFP_KERNEL);
                        CHECK_RETCODE(ipu->rot_dma[rot_idx].vaddr == NULL,
                                        "ic_and_rot", STATE_SYS_NO_MEM,
-                                       chan_setup, STATE_SYS_NO_MEM);
+                                       chan_setup, -ENOMEM);
                }
                t->set.r_paddr = ipu->rot_dma[rot_idx].paddr;
 
@@ -2211,13 +2646,15 @@ static void do_task(struct ipu_task_entry *t)
                                                ret);
                        }
                }
-               if (deinterlace_3_field(t))
-                       ipu_select_multi_vdi_buffer(ipu, 0);
-               else {
-                       ret = ipu_select_buffer(ipu, t->set.ic_chan,
-                                               IPU_INPUT_BUFFER, 0);
-                       CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
+               if (!(t->set.mode & VDOA_BAND_MODE)) {
+                       if (deinterlace_3_field(t))
+                               ipu_select_multi_vdi_buffer(ipu, 0);
+                       else {
+                               ret = ipu_select_buffer(ipu, t->set.ic_chan,
+                                                       IPU_INPUT_BUFFER, 0);
+                               CHECK_RETCODE(ret < 0, "ipu_sel_buf only_ic_i",
                                        STATE_SEL_BUF_FAIL, chan_buf, ret);
+                       }
                }
        } else if (only_rot(t->set.mode)) {
                ret = ipu_enable_channel(ipu, t->set.rot_chan);
@@ -2281,6 +2718,12 @@ static void do_task(struct ipu_task_entry *t)
        if (need_split(t))
                t->state = STATE_IN_PROGRESS;
 
+       if (t->set.mode & VDOA_BAND_MODE) {
+               ret = vdoa_start(t->vdoa_handle, VDOA_DEF_TIMEOUT_MS);
+               CHECK_RETCODE(ret < 0, "vdoa_wait4complete, do_vdoa_band",
+                               STATE_VDOA_IRQ_TIMEOUT, chan_rel, ret);
+       }
+
        CHECK_PERF(&t->ts_waitirq);
        ret = wait_for_completion_timeout(&t->irq_comp,
                                 msecs_to_jiffies(t->timeout - DEF_DELAY_MS));
@@ -2293,26 +2736,92 @@ chan_rel:
 chan_buf:
 chan_en:
 chan_setup:
+       if (t->set.mode & VDOA_BAND_MODE)
+               vdoa_stop(t->vdoa_handle);
        do_task_release(t, t->state >= STATE_ERR);
        return;
 }
 
+static void do_task_vdoa_vdi(struct ipu_task_entry *t)
+{
+       int i;
+       int ret;
+       u32 stripe_width;
+
+       /* FIXME: crop mode not support now */
+       stripe_width = t->input.width >> 1;
+       t->input.crop.pos.x = 0;
+       t->input.crop.pos.y = 0;
+       t->input.crop.w = stripe_width;
+       t->input.crop.h = t->input.height;
+       t->output.crop.w = stripe_width;
+       t->output.crop.h = t->input.height;
+
+       for (i = 0; i < 2; i++) {
+               t->input.crop.pos.x = t->input.crop.pos.x + i * stripe_width;
+               t->output.crop.pos.x = t->output.crop.pos.x + i * stripe_width;
+               /* check input */
+               ret = set_crop(&t->input.crop, t->input.width, t->input.height,
+                       t->input.format);
+               if (ret < 0) {
+                       ret = STATE_ERR;
+                       goto done;
+               } else
+                       update_offset(t->input.format,
+                                       t->input.width, t->input.height,
+                                       t->input.crop.pos.x,
+                                       t->input.crop.pos.y,
+                                       &t->set.i_off, &t->set.i_uoff,
+                                       &t->set.i_voff, &t->set.istride);
+               dev_dbg(t->dev, "i_off:0x%x, i_uoff:0x%x, istride:%d.\n",
+                       t->set.i_off, t->set.i_uoff, t->set.istride);
+               /* check output */
+               ret = set_crop(&t->output.crop, t->input.width,
+                                       t->output.height, t->output.format);
+               if (ret < 0) {
+                       ret = STATE_ERR;
+                       goto done;
+               } else
+                       update_offset(t->output.format,
+                                       t->output.width, t->output.height,
+                                       t->output.crop.pos.x,
+                                       t->output.crop.pos.y,
+                                       &t->set.o_off, &t->set.o_uoff,
+                                       &t->set.o_voff, &t->set.ostride);
+
+               dev_dbg(t->dev, "o_off:0x%x, o_uoff:0x%x, ostride:%d.\n",
+                               t->set.o_off, t->set.o_uoff, t->set.ostride);
+
+               do_task(t);
+       }
+
+       return;
+done:
+       dev_err(t->dev, "ERR %s set_crop.\n", __func__);
+       t->state = ret;
+       return;
+}
+
 static void get_res_do_task(struct ipu_task_entry *t)
 {
        uint32_t        found;
        uint32_t        split_child;
        struct mutex    *lock;
 
-       init_completion(&t->irq_comp);
-
        found = get_vdoa_ipu_res(t);
        if (!found) {
                BUG();
        } else {
-               do_task(t);
-               put_vdoa_ipu_res(t);
+               if (t->set.task & VDOA_ONLY)
+                       do_task_vdoa_only(t);
+               else if ((IPU_PIX_FMT_TILED_NV12F == t->input.format) &&
+                               (t->set.mode & VDOA_BAND_MODE) &&
+                               (t->input.crop.w > soc_max_out_width()))
+                       do_task_vdoa_vdi(t);
+               else
+                       do_task(t);
+               put_vdoa_ipu_res(t, 0);
        }
-
        if (t->state != STATE_OK) {
                dev_err(t->dev, "ERR:[0x%p] no-0x%x state: %s\n",
                        t, t->task_no, state_msg[t->state].msg);
@@ -2382,8 +2891,8 @@ out:
                        if (IS_ERR(ipu)) {
                                BUG();
                        } else {
-                               busy_vf = ipu_vf_pp_is_busy(ipu, true);
-                               busy_pp = ipu_vf_pp_is_busy(ipu, false);
+                               busy_vf = ic_vf_pp_is_busy(ipu, true);
+                               busy_pp = ic_vf_pp_is_busy(ipu, false);
                                dev_err(parent->dev,
                                        "ERR:ipu[%d] busy_vf:%d, busy_pp:%d.\n",
                                        k, busy_vf, busy_pp);
@@ -2411,15 +2920,15 @@ out:
                        list_del(&tsk->node);
                        tsk->task_in_list = 0;
                        dev_dbg(tsk->dev,
-                               "no-0x%x,id:%d sp_tsk timeout list_del.\n",
-                                tsk->task_no, tsk->task_id);
+                               "[0x%p] no-0x%x,id:%d sp_tsk timeout list_del.\n",
+                                tsk, tsk->task_no, tsk->task_id);
                }
                spin_unlock_irqrestore(&ipu_task_list_lock, flags);
                if (!tsk->ipu)
                        continue;
                if (STATE_IN_PROGRESS == tsk->state) {
                        do_task_release(tsk, 1);
-                       put_vdoa_ipu_res(tsk);
+                       put_vdoa_ipu_res(tsk, 0);
                }
                if (tsk->state != STATE_OK) {
                        dev_err(tsk->dev,
@@ -2549,7 +3058,7 @@ static int ipu_task_thread(void *argv)
                                spin_unlock_irqrestore(&ipu_task_list_lock,
                                                                        flags);
                                /* let the parent thread do the first sp_task */
-                               /* note: ensure the correct sequence for split
+                               /* FIXME: ensure the correct sequence for split
                                        4size: 5/6->9/a*/
                                if (!sp_tsk0)
                                        BUG();
@@ -2615,11 +3124,11 @@ int ipu_check_task(struct ipu_task *task)
        task->input = tsk->input;
        task->output = tsk->output;
        task->overlay = tsk->overlay;
-
        dump_task_info(tsk);
 
        kref_put(&tsk->refcount, task_mem_free);
-
+       if (ret != 0)
+               pr_debug("%s ret:%d.\n", __func__, ret);
        return ret;
 }
 EXPORT_SYMBOL_GPL(ipu_check_task);
index e93d2a36ec86b7576377f2268bc8af8a34a31499..e21d6134c84ac78d7e89867101778012a7534473 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -97,6 +97,9 @@ void _ipu_ic_enable_task(struct ipu_soc *ipu, ipu_channel_t channel)
        case MEM_VDI_PRP_VF_MEM:
                ic_conf |= IC_CONF_PRPVF_EN;
                break;
+       case MEM_VDI_MEM:
+               ic_conf |= IC_CONF_PRPVF_EN | IC_CONF_RWS_EN ;
+               break;
        case MEM_ROT_VF_MEM:
                ic_conf |= IC_CONF_PRPVF_ROT_EN;
                break;
@@ -132,6 +135,9 @@ void _ipu_ic_disable_task(struct ipu_soc *ipu, ipu_channel_t channel)
        case MEM_VDI_PRP_VF_MEM:
                ic_conf &= ~IC_CONF_PRPVF_EN;
                break;
+       case MEM_VDI_MEM:
+               ic_conf &= ~(IC_CONF_PRPVF_EN | IC_CONF_RWS_EN);
+               break;
        case MEM_ROT_VF_MEM:
                ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
                break;
@@ -158,6 +164,7 @@ void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_param
 {
        uint32_t reg;
        uint32_t pixel_fmt;
+       uint32_t pix_per_burst;
 
        reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
          (params->mem_prp_vf_mem.in_width-1);
@@ -168,10 +175,13 @@ void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_param
        if (params->mem_prp_vf_mem.in_pixel_fmt ==
             IPU_PIX_FMT_UYVY ||
             params->mem_prp_vf_mem.in_pixel_fmt ==
-            IPU_PIX_FMT_YUYV)
+            IPU_PIX_FMT_YUYV) {
                pixel_fmt = VDI_C_CH_422;
-       else
+               pix_per_burst = 32;
+        } else {
                pixel_fmt = VDI_C_CH_420;
+               pix_per_burst = 64;
+       }
 
        reg = ipu_vdi_read(ipu, VDI_C);
        reg |= pixel_fmt;
@@ -185,6 +195,21 @@ void _ipu_vdi_init(struct ipu_soc *ipu, ipu_channel_t channel, ipu_channel_param
        case MEM_VDI_PRP_VF_MEM_N:
                reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
                break;
+
+       case MEM_VDI_MEM:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE2_OFFSET;
+               break;
+       case MEM_VDI_MEM_P:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE1_OFFSET;
+               reg |= VDI_C_VWM1_SET_2 | VDI_C_VWM1_CLR_2;
+               break;
+       case MEM_VDI_MEM_N:
+               reg |= (((pix_per_burst >> 2) - 1) & VDI_C_BURST_SIZE_MASK)
+                               << VDI_C_BURST_SIZE3_OFFSET;
+               reg |= VDI_C_VWM3_SET_2 | VDI_C_VWM3_CLR_2;
+               break;
        default:
                break;
        }
@@ -644,12 +669,16 @@ int _ipu_ic_idma_init(struct ipu_soc *ipu, int dma_chan,
                        ic_idmac_1 |= IC_IDMAC_1_CB4_BURST_16;
                else
                        ic_idmac_1 &= ~IC_IDMAC_1_CB4_BURST_16;
+       } else if (dma_chan == 5) {     /* VDIC OUTPUT - CB7 */
+               if (burst_size == 16)
+                       ic_idmac_1 |= IC_IDMAC_1_CB7_BURST_16;
+               else
+                       ic_idmac_1 &= ~IC_IDMAC_1_CB7_BURST_16;
        }
 
        ipu_ic_write(ipu, ic_idmac_1, IC_IDMAC_1);
        ipu_ic_write(ipu, ic_idmac_2, IC_IDMAC_2);
        ipu_ic_write(ipu, ic_idmac_3, IC_IDMAC_3);
-
        return 0;
 }
 
index 223a1cdf5fa4852b5c044baffe60d02fc6534e40..8ae0a5edd269a67618d5e1aaf3512a7f0d091cba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -194,8 +194,20 @@ static inline void _ipu_ch_param_dump(struct ipu_soc *ipu, int ch)
                 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 125, 13));
        dev_dbg(ipu->dev, "FH %d, ",
                 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 138, 12));
+       dev_dbg(ipu->dev, "EBA0 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 0, 29) << 3);
+       dev_dbg(ipu->dev, "EBA1 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 29, 29) << 3);
        dev_dbg(ipu->dev, "Stride %d\n",
                 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 102, 14));
+       dev_dbg(ipu->dev, "scan_order %d\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 113, 1));
+       dev_dbg(ipu->dev, "uv_stride %d\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 128, 14));
+       dev_dbg(ipu->dev, "u_offset 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 46, 22) << 3);
+       dev_dbg(ipu->dev, "v_offset 0x%x\n",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 68, 22) << 3);
 
        dev_dbg(ipu->dev, "Width0 %d+1, ",
                 ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 1, 116, 3));
@@ -246,10 +258,11 @@ static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
 
        ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
 
-       if ((ch == 8) || (ch == 9) || (ch == 10)) {
+       if (((ch == 8) || (ch == 9) || (ch == 10)) && !ipu->vdoa_en) {
                ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
                ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
        } else {
+               /* note: for vdoa+vdi- ch8/9/10, always use band mode */
                ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
                ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
        }
@@ -340,7 +353,11 @@ static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
                ipu_ch_param_set_field(&params, 0, 107, 3, 3);  /* bits/pixel */
                ipu_ch_param_set_field(&params, 1, 85, 4, 0x8); /* pix format */
                if ((ch == 8) || (ch == 9) || (ch == 10)) {
-                       ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+                       if (ipu->vdoa_en) {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 31);
+                       } else {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+                       }
                } else {
                        ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
                }
@@ -404,8 +421,14 @@ static inline void _ipu_ch_param_init(struct ipu_soc *ipu, int ch,
                uv_stride = stride;
                u_offset = (u == 0) ? stride * height : u;
                if ((ch == 8) || (ch == 9) || (ch == 10)) {
-                       ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
-                       uv_stride = uv_stride*2;
+                       if (ipu->vdoa_en) {
+                                /* one field buffer, memory width 64bits */
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 63);
+                       } else {
+                               ipu_ch_param_set_field(&params, 1, 78, 7, 15);
+                                /* top/bottom field in one buffer*/
+                               uv_stride = uv_stride*2;
+                       }
                } else {
                        ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
                }
@@ -819,4 +842,20 @@ static inline void _ipu_ch_params_set_alpha_width(struct ipu_soc *ipu, uint32_t
        ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch), 1, 125, 3, alpha_width - 1);
 };
 
+static inline void _ipu_ch_param_set_bandmode(struct ipu_soc *ipu,
+                       uint32_t ch, uint32_t band_height)
+{
+       int32_t sub_ch = 0;
+
+       ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, ch),
+                                       0, 114, 3, band_height - 1);
+       sub_ch = __ipu_ch_get_third_buf_cpmem_num(ch);
+       if (sub_ch <= 0)
+               return;
+       ipu_ch_param_set_field_io(ipu_ch_param_addr(ipu, sub_ch),
+                                       0, 114, 3, band_height - 1);
+
+       dev_dbg(ipu->dev, "BNDM 0x%x, ",
+                ipu_ch_param_read_field_io(ipu_ch_param_addr(ipu, ch), 0, 114, 3));
+}
 #endif
index 68cb87a910fa36b0f571f6571523e995a37e5bbc..526a2c0a36f00988bb2c365dc74db50ff71b10ff 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -128,16 +128,15 @@ struct ipu_soc {
        u32 idma_enable_reg[2];
        u32 buf_ready_reg[10];
 
-       /*ipu processing driver*/
-       struct list_head task_list[2];
-       struct mutex task_lock[2];
-       wait_queue_head_t waitq[2];
-       struct task_struct *thread[2];
        struct rot_mem {
                void *vaddr;
                dma_addr_t paddr;
                int size;
        } rot_dma[2];
+
+       int     vdoa_en;
+       struct task_struct *thread[2];
+
 };
 
 struct ipu_channel {
index c63c93231135743cfb4572bea8e7d157276d50ea..c06ac9ff8486b60393e0ab796dc4adfad9fb04d7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2005-2012 Freescale Semiconductor, Inc. All Rights Reserved.
  */
 
 /*
@@ -368,12 +368,17 @@ enum {
        FS_PP_ROT_SRC_SEL_MASK = 0x000F0000,
        FS_PP_ROT_SRC_SEL_OFFSET = 16,
        FS_PP_SRC_SEL_MASK = 0x0000F000,
+       FS_PP_SRC_SEL_VDOA = 0x00008000,
        FS_PP_SRC_SEL_OFFSET = 12,
        FS_PRP_SRC_SEL_MASK = 0x0F000000,
        FS_PRP_SRC_SEL_OFFSET = 24,
        FS_VF_IN_VALID = 0x80000000,
        FS_ENC_IN_VALID = 0x40000000,
        FS_VDI_SRC_SEL_MASK = 0x30000000,
+       FS_VDI_SRC_SEL_VDOA = 0x20000000,
+       FS_VDOA_DEST_SEL_MASK = 0x00030000,
+       FS_VDOA_DEST_SEL_VDI = 0x00020000,
+       FS_VDOA_DEST_SEL_IC = 0x00010000,
        FS_VDI_SRC_SEL_OFFSET = 28,
 
 
@@ -659,9 +664,15 @@ enum {
        VDI_C_BURST_SIZE1_4 = 0x00000030,
        VDI_C_BURST_SIZE2_4 = 0x00000300,
        VDI_C_BURST_SIZE3_4 = 0x00003000,
+       VDI_C_BURST_SIZE_MASK = 0xF,
+       VDI_C_BURST_SIZE1_OFFSET = 4,
+       VDI_C_BURST_SIZE2_OFFSET = 8,
+       VDI_C_BURST_SIZE3_OFFSET = 12,
        VDI_C_VWM1_SET_1 = 0x00000000,
+       VDI_C_VWM1_SET_2 = 0x00010000,
        VDI_C_VWM1_CLR_2 = 0x00080000,
        VDI_C_VWM3_SET_1 = 0x00000000,
+       VDI_C_VWM3_SET_2 = 0x00400000,
        VDI_C_VWM3_CLR_2 = 0x02000000,
        VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
        VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
diff --git a/drivers/mxc/ipu3/vdoa.c b/drivers/mxc/ipu3/vdoa.c
new file mode 100644 (file)
index 0000000..1a5266d
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/ipu.h>
+#include <linux/iram_alloc.h>
+
+#include "vdoa.h"
+/* FIXME: use cmdline to specify the iram size */
+/* 6band(3field* double buffer) * (width*2) * bandline(8)
+       = 6x1024x2x8 = 96k or 72k(1.5byte) */
+#define VDOA_IRAM_SIZE (1024*96)
+
+#define VDOAC_BAND_HEIGHT_32LINES      (32)
+#define VDOAC_BAND_HEIGHT_16LINES      (16)
+#define VDOAC_BAND_HEIGHT_8LINES       (8)
+#define VDOAC_THREE_FRAMES             (0x1 << 2)
+#define VDOAC_SYNC_BAND_MODE           (0x1 << 3)
+#define VDOAC_SCAN_ORDER_INTERLACED    (0x1 << 4)
+#define VDOAC_PFS_YUYV                 (0x1 << 5)
+#define VDOAC_IPU_SEL_1                        (0x1 << 6)
+#define VDOAFP_FH_MASK                 (0x1FFF)
+#define VDOAFP_FH_SHIFT                        (16)
+#define VDOAFP_FW_MASK                 (0x3FFF)
+#define VDOAFP_FW_SHIFT                        (0)
+#define VDOASL_VSLY_MASK               (0x3FFF)
+#define VDOASL_VSLY_SHIFT              (16)
+#define VDOASL_ISLY_MASK               (0x7FFF)
+#define VDOASL_ISLY_SHIFT              (0)
+#define VDOASRR_START_XFER             (0x2)
+#define VDOASRR_SWRST                  (0x1)
+#define VDOAIEIST_TRANSFER_ERR         (0x2)
+#define VDOAIEIST_TRANSFER_END         (0x1)
+
+#define        VDOAC           (0x0)   /* Control Register */
+#define        VDOASRR         (0x4)   /* Start and Reset Register */
+#define        VDOAIE          (0x8)   /* Interrupt Enable Register */
+#define        VDOAIST         (0xc)   /* Interrupt Status Register */
+#define        VDOAFP          (0x10)  /* Frame Parameters Register */
+#define        VDOAIEBA00      (0x14)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA01      (0x18)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA02      (0x1c)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA10      (0x20)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA11      (0x24)  /* External Buffer n Frame m Address Register */
+#define        VDOAIEBA12      (0x28)  /* External Buffer n Frame m Address Register */
+#define        VDOASL          (0x2c)  /* IPU Stride Line Register */
+#define        VDOAIUBO        (0x30)  /* IPU Chroma Buffer Offset Register */
+#define        VDOAVEBA0       (0x34)  /* External Buffer m Address Register */
+#define        VDOAVEBA1       (0x38)  /* External Buffer m Address Register */
+#define        VDOAVEBA2       (0x3c)  /* External Buffer m Address Register */
+#define        VDOAVUBO        (0x40)  /* VPU Chroma Buffer Offset */
+#define        VDOASR          (0x44)  /* Status Register */
+#define        VDOATD          (0x48)  /* Test Debug Register */
+
+
+enum {
+       VDOA_INIT       = 0x1,
+       VDOA_GET        = 0x2,
+       VDOA_SETUP      = 0x4,
+       VDOA_GET_OBUF   = 0x8,
+       VDOA_START      = 0x10,
+       VDOA_INIRQ      = 0x20,
+       VDOA_STOP       = 0x40,
+       VDOA_PUT        = VDOA_INIT,
+};
+
+enum {
+       VDOA_NULL       = 0,
+       VDOA_FRAME      = 1,
+       VDOA_PREV_FIELD = 2,
+       VDOA_CURR_FIELD = 3,
+       VDOA_NEXT_FIELD = 4,
+};
+
+#define CHECK_STATE(expect, retcode)                                   \
+do {                                                                   \
+       if (!((expect) & vdoa->state)) {                                \
+               dev_err(vdoa->dev, "ERR: %s state:0x%x, expect:0x%x.\n",\
+                               __func__, vdoa->state, (expect));       \
+               retcode;                                                \
+       }                                                               \
+} while (0)
+
+#define CHECK_NULL_PTR(ptr)                                            \
+do {                                                                   \
+       pr_debug("vdoa_ptr:0x%p in %s state:0x%x.\n",                   \
+                       vdoa, __func__, vdoa->state);                   \
+       if (NULL == (ptr)) {                                            \
+               pr_err("ERR vdoa: %s state:0x%x null ptr.\n",           \
+                               __func__, vdoa->state);                 \
+       }                                                               \
+} while (0)
+
+struct vdoa_info {
+       int             state;
+       struct device   *dev;
+       struct clk      *clk;
+       void __iomem    *reg_base;
+       void __iomem    *iram_base;
+       unsigned long   iram_paddr;
+       int             irq;
+       int             field;
+       struct completion comp;
+};
+
+static struct vdoa_info *g_vdoa;
+static DEFINE_MUTEX(vdoa_lock);
+
+static inline void vdoa_read_register(struct vdoa_info *vdoa,
+                               u32 reg, u32 *val)
+{
+       *val = ioread32(vdoa->reg_base + reg);
+       dev_dbg(vdoa->dev, "read_reg:0x%02x, val:0x%08x.\n", reg, *val);
+}
+
+static inline void vdoa_write_register(struct vdoa_info *vdoa,
+                               u32 reg, u32 val)
+{
+       iowrite32(val, vdoa->reg_base + reg);
+       dev_dbg(vdoa->dev, "\t\twrite_reg:0x%02x, val:0x%08x.\n", reg, val);
+}
+
+static void dump_registers(struct vdoa_info *vdoa)
+{
+       int i;
+       u32 data;
+
+       for (i = VDOAC; i < VDOATD; i += 4)
+               vdoa_read_register(vdoa, i, &data);
+}
+
+void vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params)
+{
+       int     band_size;
+       int     ipu_stride;
+       u32     data;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_GET | VDOA_GET_OBUF | VDOA_STOP, return);
+       if (VDOA_GET == vdoa->state) {
+               dev_dbg(vdoa->dev, "w:%d, h:%d.\n",
+                        params->width, params->height);
+               data = (params->band_lines == VDOAC_BAND_HEIGHT_32LINES) ? 2 :
+                       ((params->band_lines == VDOAC_BAND_HEIGHT_16LINES) ?
+                                1 : 0);
+               data |= params->scan_order ? VDOAC_SCAN_ORDER_INTERLACED : 0;
+               data |= params->band_mode ? VDOAC_SYNC_BAND_MODE : 0;
+               data |= params->pfs ? VDOAC_PFS_YUYV : 0;
+               data |= params->ipu_num ? VDOAC_IPU_SEL_1 : 0;
+               vdoa_write_register(vdoa, VDOAC, data);
+
+               data = ((params->width & VDOAFP_FW_MASK) << VDOAFP_FW_SHIFT) |
+                       ((params->height & VDOAFP_FH_MASK) << VDOAFP_FH_SHIFT);
+               vdoa_write_register(vdoa, VDOAFP, data);
+
+               ipu_stride = params->pfs ? params->width << 1 : params->width;
+               data = ((params->vpu_stride & VDOASL_VSLY_MASK) <<
+                                                       VDOASL_VSLY_SHIFT) |
+                       ((ipu_stride & VDOASL_ISLY_MASK) << VDOASL_ISLY_SHIFT);
+               vdoa_write_register(vdoa, VDOASL, data);
+
+               dev_dbg(vdoa->dev, "band_mode:%d, band_line:%d, base:0x%lx.\n",
+               params->band_mode, params->band_lines, vdoa->iram_paddr);
+       }
+       /*
+        * band size    = (luma_per_line + chroma_per_line) * bandLines
+        *              = width * (3/2 or 2) * bandLines
+        * double buffer mode used.
+        */
+       if (params->pfs)
+               band_size = (params->width << 1) * params->band_lines;
+       else
+               band_size = ((params->width * 3) >> 1) *
+                                               params->band_lines;
+       if (params->interlaced) {
+               if (params->vfield_buf.prev_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA00,
+                                                       vdoa->iram_paddr);
+                               vdoa_write_register(vdoa, VDOAIEBA10,
+                                                vdoa->iram_paddr + band_size);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA00,
+                                                       params->ieba0);
+                       vdoa_write_register(vdoa, VDOAVEBA0,
+                                       params->vfield_buf.prev_veba);
+                       vdoa->field = VDOA_PREV_FIELD;
+               }
+               if (params->vfield_buf.cur_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA01,
+                                        vdoa->iram_paddr + band_size * 2);
+                               vdoa_write_register(vdoa, VDOAIEBA11,
+                                        vdoa->iram_paddr + band_size * 3);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA01,
+                                                       params->ieba1);
+                       vdoa_write_register(vdoa, VDOAVEBA1,
+                                       params->vfield_buf.cur_veba);
+                       vdoa->field = VDOA_CURR_FIELD;
+               }
+               if (params->vfield_buf.next_veba) {
+                       if (params->band_mode) {
+                               vdoa_write_register(vdoa, VDOAIEBA02,
+                                        vdoa->iram_paddr + band_size * 4);
+                               vdoa_write_register(vdoa, VDOAIEBA12,
+                                        vdoa->iram_paddr + band_size * 5);
+                       } else
+                               vdoa_write_register(vdoa, VDOAIEBA02,
+                                                       params->ieba2);
+                       vdoa_write_register(vdoa, VDOAVEBA2,
+                                       params->vfield_buf.next_veba);
+                       vdoa->field = VDOA_NEXT_FIELD;
+                       vdoa_read_register(vdoa, VDOAC, &data);
+                       data |= VDOAC_THREE_FRAMES;
+                       vdoa_write_register(vdoa, VDOAC, data);
+               }
+
+               if (!params->pfs)
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                params->width * params->band_lines);
+               vdoa_write_register(vdoa, VDOAVUBO,
+                                params->vfield_buf.vubo);
+               dev_dbg(vdoa->dev, "total band_size:0x%x.\n", band_size*6);
+       } else if (params->band_mode) {
+               /* used for progressive frame resize on PrP channel */
+               BUG(); /* currently not support */
+               /* progressvie frame: band mode */
+               vdoa_write_register(vdoa, VDOAIEBA00, vdoa->iram_paddr);
+               vdoa_write_register(vdoa, VDOAIEBA10,
+                                        vdoa->iram_paddr + band_size);
+               if (!params->pfs)
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                       params->width * params->band_lines);
+               dev_dbg(vdoa->dev, "total band_size:0x%x\n", band_size*2);
+       } else {
+               /* progressive frame: mem->mem, non-band mode */
+               vdoa->field = VDOA_FRAME;
+               vdoa_write_register(vdoa, VDOAVEBA0, params->vframe_buf.veba);
+               vdoa_write_register(vdoa, VDOAVUBO, params->vframe_buf.vubo);
+               vdoa_write_register(vdoa, VDOAIEBA00, params->ieba0);
+               if (!params->pfs)
+                       /* note: iubo is relative value, based on ieba0 */
+                       vdoa_write_register(vdoa, VDOAIUBO,
+                                       params->width * params->height);
+       }
+       vdoa->state = VDOA_SETUP;
+}
+
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf)
+{
+       u32     data;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_SETUP, return);
+       vdoa->state = VDOA_GET_OBUF;
+       memset(buf, 0, sizeof(*buf));
+
+       vdoa_read_register(vdoa, VDOAC, &data);
+       switch (vdoa->field) {
+       case VDOA_FRAME:
+       case VDOA_PREV_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA00, &buf->ieba0);
+               if (data & VDOAC_SYNC_BAND_MODE)
+                       vdoa_read_register(vdoa, VDOAIEBA10, &buf->ieba1);
+               break;
+       case VDOA_CURR_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA01, &buf->ieba0);
+               vdoa_read_register(vdoa, VDOAIEBA11, &buf->ieba1);
+               break;
+       case VDOA_NEXT_FIELD:
+               vdoa_read_register(vdoa, VDOAIEBA02, &buf->ieba0);
+               vdoa_read_register(vdoa, VDOAIEBA12, &buf->ieba1);
+               break;
+       default:
+               BUG();
+               break;
+       }
+       if (!(data & VDOAC_PFS_YUYV))
+               vdoa_read_register(vdoa, VDOAIUBO, &buf->iubo);
+}
+
+int vdoa_start(vdoa_handle_t handle, int timeout_ms)
+{
+       int ret;
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_GET_OBUF, return -EINVAL);
+       init_completion(&vdoa->comp);
+       vdoa_write_register(vdoa, VDOAIST,
+                       VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+       vdoa_write_register(vdoa, VDOAIE,
+                       VDOAIEIST_TRANSFER_ERR | VDOAIEIST_TRANSFER_END);
+
+       enable_irq(vdoa->irq);
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_START_XFER);
+       dump_registers(vdoa);
+
+       vdoa->state = VDOA_START;
+       ret = wait_for_completion_timeout(&vdoa->comp,
+                       msecs_to_jiffies(timeout_ms));
+
+       return ret > 0 ? 0 : -ETIMEDOUT;
+}
+
+void vdoa_stop(vdoa_handle_t handle)
+{
+       struct vdoa_info *vdoa = (struct vdoa_info *)handle;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_START | VDOA_INIRQ, return);
+       vdoa->state = VDOA_STOP;
+
+       disable_irq(vdoa->irq);
+
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+}
+
+void vdoa_get_handle(vdoa_handle_t *handle)
+{
+       struct vdoa_info *vdoa = g_vdoa;
+
+       CHECK_NULL_PTR(handle);
+       *handle = (vdoa_handle_t *)NULL;
+       CHECK_STATE(VDOA_INIT, return);
+       mutex_lock(&vdoa_lock);
+       clk_enable(vdoa->clk);
+       vdoa->state = VDOA_GET;
+       vdoa->field = VDOA_NULL;
+       vdoa_write_register(vdoa, VDOASRR, VDOASRR_SWRST);
+
+       *handle = (vdoa_handle_t *)vdoa;
+}
+
+void vdoa_put_handle(vdoa_handle_t *handle)
+{
+       struct vdoa_info *vdoa = (struct vdoa_info *)(*handle);
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_STOP, return);
+       if (vdoa != g_vdoa)
+               BUG();
+
+       clk_disable(vdoa->clk);
+       vdoa->state = VDOA_PUT;
+       *handle = (vdoa_handle_t *)NULL;
+       mutex_unlock(&vdoa_lock);
+}
+
+static irqreturn_t vdoa_irq_handler(int irq, void *data)
+{
+       u32 status, mask, val;
+       struct vdoa_info *vdoa = data;
+
+       CHECK_NULL_PTR(vdoa);
+       CHECK_STATE(VDOA_START, return IRQ_HANDLED);
+       vdoa->state = VDOA_INIRQ;
+       vdoa_read_register(vdoa, VDOAIST, &status);
+       vdoa_read_register(vdoa, VDOAIE, &mask);
+       val = status & mask;
+       vdoa_write_register(vdoa, VDOAIST, val);
+       if (VDOAIEIST_TRANSFER_ERR & val)
+               dev_err(vdoa->dev, "vdoa Transfer err irq!\n");
+       if (VDOAIEIST_TRANSFER_END & val)
+               dev_dbg(vdoa->dev, "vdoa Transfer end irq!\n");
+       if (0 == val) {
+               dev_err(vdoa->dev, "vdoa unknown irq!\n");
+               BUG();
+       }
+
+       complete(&vdoa->comp);
+       return IRQ_HANDLED;
+}
+
+static int vdoa_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct vdoa_info *vdoa;
+       struct resource *res;
+       struct resource *res_irq;
+       struct device   *dev;
+       char   clk[] = "vdoa";
+
+       vdoa = kzalloc(sizeof(struct vdoa_info), GFP_KERNEL);
+       if (!vdoa) {
+               ret = -ENOMEM;
+               goto alloc_failed;
+       }
+       vdoa->dev = dev = &pdev->dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(dev, "get IORESOURCE_MEM error\n");
+               ret = -ENODEV;
+               goto res_mem_failed;
+       }
+
+       res = request_mem_region(res->start, resource_size(res), pdev->name);
+       if (!res) {
+               dev_err(dev, "request mem region error\n");
+               ret = -EBUSY;
+               goto req_mem_region;
+       }
+       vdoa->reg_base = ioremap(res->start, resource_size(res));
+       if (!vdoa->reg_base) {
+               dev_err(dev, "map vdoa registers error\n");
+               ret = -EIO;
+               goto err_ioremap;
+       }
+
+       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res_irq) {
+               dev_err(dev, "failed to get irq resource\n");
+               ret = -ENODEV;
+               goto err_get_irq;
+       }
+       vdoa->irq = res_irq->start;
+       ret = request_irq(vdoa->irq, vdoa_irq_handler, 0, "vdoa", vdoa);
+       if (ret) {
+               dev_err(dev, "request vdoa interrupt failed\n");
+               ret = -EBUSY;
+               goto err_req_irq;
+       }
+       disable_irq(vdoa->irq);
+
+       vdoa->clk = clk_get(dev, clk);
+       if (IS_ERR(vdoa->clk)) {
+               dev_err(dev, "failed to get vdoa_clk\n");
+               ret = PTR_ERR(vdoa->clk);
+               goto err_clk;
+       }
+       clk_enable(vdoa->clk);
+
+       vdoa->iram_base = iram_alloc(VDOA_IRAM_SIZE, &vdoa->iram_paddr);
+       if (!vdoa->iram_base) {
+               dev_err(dev, "failed to get iram memory:0x%x\n",
+                               VDOA_IRAM_SIZE);
+               ret = -ENOMEM;
+               goto err_iram_alloc;
+       }
+       dev_dbg(dev, "iram_base:0x%p,iram_paddr:0x%lx,size:0x%x\n",
+                vdoa->iram_base, vdoa->iram_paddr, VDOA_IRAM_SIZE);
+
+       vdoa->state = VDOA_INIT;
+       dev_set_drvdata(dev, vdoa);
+       g_vdoa = vdoa;
+       dev_info(dev, "i.MX Video Data Order Adapter(VDOA) driver probed\n");
+       return 0;
+
+err_iram_alloc:
+       clk_put(vdoa->clk);
+err_clk:
+err_req_irq:
+err_get_irq:
+       iounmap(vdoa->reg_base);
+err_ioremap:
+       release_mem_region(res->start, resource_size(res));
+req_mem_region:
+res_mem_failed:
+       kfree(vdoa);
+alloc_failed:
+       return ret;
+}
+
+static int __devexit vdoa_remove(struct platform_device *pdev)
+{
+       int ret = 0;
+       struct resource *res;
+       struct vdoa_info *vdoa = dev_get_drvdata(&pdev->dev);
+
+       clk_put(vdoa->clk);
+       clk_disable(vdoa->clk);
+       iram_free(vdoa->iram_paddr, VDOA_IRAM_SIZE);
+       iounmap(vdoa->reg_base);
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "get IORESOURCE_MEM error\n");
+               ret = -ENODEV;
+               goto res_mem_failed;
+       }
+       release_mem_region(res->start, resource_size(res));
+       kfree(vdoa);
+       dev_set_drvdata(&pdev->dev, NULL);
+
+res_mem_failed:
+       return ret;
+}
+
+static struct platform_driver vdoa_driver = {
+       .driver = {
+                  .name = "mxc_vdoa",
+       },
+       .probe = vdoa_probe,
+       .remove = __devexit_p(vdoa_remove),
+};
+
+static int __init vdoa_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&vdoa_driver);
+       if (err) {
+               pr_err("vdoa_driver register failed\n");
+               return -ENODEV;
+       }
+       return 0;
+}
+
+static void __exit vdoa_cleanup(void)
+{
+       platform_driver_unregister(&vdoa_driver);
+}
+
+module_init(vdoa_init);
+module_exit(vdoa_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("i.MX Video Data Order Adapter(VDOA) driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mxc/ipu3/vdoa.h b/drivers/mxc/ipu3/vdoa.h
new file mode 100644 (file)
index 0000000..82b0ee1
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __VDOA_H__
+#define __VDOA_H__
+
+#define VDOA_PFS_YUYV (1)
+#define VDOA_PFS_NV12 (0)
+
+
+struct vfield_buf {
+       u32     prev_veba;
+       u32     cur_veba;
+       u32     next_veba;
+       u32     vubo;
+};
+
+struct vframe_buf {
+       u32     veba;
+       u32     vubo;
+};
+
+struct vdoa_params {
+       u32     width;
+       u32     height;
+       int     vpu_stride;
+       int     interlaced;
+       int     scan_order;
+       int     ipu_num;
+       int     band_lines;
+       int     band_mode;
+       int     pfs;
+       u32     ieba0;
+       u32     ieba1;
+       u32     ieba2;
+       struct  vframe_buf vframe_buf;
+       struct  vfield_buf vfield_buf;
+};
+struct vdoa_ipu_buf {
+       u32     ieba0;
+       u32     ieba1;
+       u32     iubo;
+};
+
+struct vdoa_info;
+typedef void *vdoa_handle_t;
+
+void vdoa_setup(vdoa_handle_t handle, struct vdoa_params *params);
+void vdoa_get_output_buf(vdoa_handle_t handle, struct vdoa_ipu_buf *buf);
+int  vdoa_start(vdoa_handle_t handle, int timeout_ms);
+void vdoa_stop(vdoa_handle_t handle);
+void vdoa_get_handle(vdoa_handle_t *handle);
+void vdoa_put_handle(vdoa_handle_t *handle);
+#endif