[PATCH 129/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00113176: MX51:Add IPU vdi support

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:49:59 UTC 2009


From: Ran <Ran.Ferderber at freescale.com>

Add IPU vdi support

Signed-off-by: Ran Ferderber <Ran.Ferderber at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 drivers/media/video/mxc/output/mxc_v4l2_output.c |  517 +++++++++++++++-------
 drivers/media/video/mxc/output/mxc_v4l2_output.h |    2 +
 drivers/mxc/ipu3/ipu_common.c                    |   94 ++++-
 drivers/mxc/ipu3/ipu_ic.c                        |   39 ++-
 drivers/mxc/ipu3/ipu_param_mem.h                 |   28 +-
 drivers/mxc/ipu3/ipu_prv.h                       |    2 +
 drivers/mxc/ipu3/ipu_regs.h                      |   23 +
 include/linux/ipu.h                              |    4 +
 8 files changed, 540 insertions(+), 169 deletions(-)

diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index 51b35cd..d83be3f 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -341,7 +341,6 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
 	unsigned long lock_flags = 0;
 	vout_data *vout = (vout_data *) arg;
 
-	dev_dbg(&vout->video_dev->dev, "timer handler: %lu\n", jiffies);
 
 	spin_lock_irqsave(&g_lock, lock_flags);
 
@@ -382,8 +381,8 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
 	}
 	if (ret < 0) {
 		dev_err(&vout->video_dev->dev,
-			"unable to update buffer %d address\n",
-			vout->next_rdy_ipu_buf);
+			"unable to update buffer %d address rc=%d\n",
+			vout->next_rdy_ipu_buf, ret);
 		goto exit0;
 	}
 
@@ -454,6 +453,260 @@ static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id)
 
 	return IRQ_HANDLED;
 }
+/*!
+ * Start the output stream
+ *
+ * @param vout      structure vout_data *
+ * out_width
+ * @return status  0 Success
+ */
+static int init_VDI(ipu_channel_params_t params, vout_data *vout,
+			struct device *dev, struct fb_info *fbi,
+			ipu_channel_t  *display_input_ch, u16 out_width,
+			u16 out_height)
+{
+	params.mem_prp_vf_mem.in_width = vout->v2f.fmt.pix.width;
+	params.mem_prp_vf_mem.in_height = vout->v2f.fmt.pix.height;
+	params.mem_prp_vf_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
+	params.mem_prp_vf_mem.out_width = out_width;
+	params.mem_prp_vf_mem.out_height = out_height;
+	if (vout->display_ch == ADC_SYS2)
+		params.mem_prp_vf_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
+	else
+		params.mem_prp_vf_mem.out_pixel_fmt = bpp_to_fmt(fbi);
+	if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
+		dev_err(dev, "Error initializing PRP channel\n");
+		return -EINVAL;
+	}
+
+	if (ipu_init_channel_buffer(vout->post_proc_ch,
+				    IPU_INPUT_BUFFER,
+				    params.mem_prp_vf_mem.in_pixel_fmt,
+				    params.mem_prp_vf_mem.in_width,
+				    params.mem_prp_vf_mem.in_height,
+				    vout->v2f.fmt.pix.bytesperline /
+				    bytes_per_pixel(params.mem_prp_vf_mem.
+						    in_pixel_fmt),
+				    IPU_ROTATE_NONE,
+				    vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
+				    vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
+				    vout->offset.u_offset,
+				    vout->offset.v_offset) != 0) {
+		dev_err(dev, "Error initializing PRP input buffer\n");
+		return -EINVAL;
+	}
+
+	if (!ipu_can_rotate_in_place(vout->rotate)) {
+		if (vout->rot_pp_bufs[0]) {
+			mxc_free_buffers(vout->rot_pp_bufs,
+					 vout->rot_pp_bufs_vaddr, 2,
+					 vout->display_buf_size);
+		}
+		if (mxc_allocate_buffers
+		    (vout->rot_pp_bufs, vout->rot_pp_bufs_vaddr, 2,
+		     vout->display_buf_size) < 0) {
+			return -ENOBUFS;
+		}
+
+		if (ipu_init_channel_buffer(vout->post_proc_ch,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_prp_vf_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    IPU_ROTATE_NONE,
+					    vout->rot_pp_bufs[0],
+					    vout->rot_pp_bufs[1], 0, 0) != 0) {
+			dev_err(dev, "Error initializing PRP output buffer\n");
+			return -EINVAL;
+		}
+
+		if (ipu_init_channel(MEM_ROT_VF_MEM, NULL) != 0) {
+			dev_err(dev, "Error initializing PP ROT channel\n");
+			return -EINVAL;
+		}
+		if (ipu_init_channel_buffer(MEM_ROT_VF_MEM,
+					    IPU_INPUT_BUFFER,
+					    params.mem_prp_vf_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    vout->rotate,
+					    vout->rot_pp_bufs[0],
+					    vout->rot_pp_bufs[1], 0, 0) != 0) {
+			dev_err(dev,
+				"Error initializing PP ROT input buffer\n");
+			return -EINVAL;
+		}
+
+		/* swap width and height */
+		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
+			out_width = vout->crop_current.width;
+			out_height = vout->crop_current.height;
+		}
+
+		if (ipu_init_channel_buffer(MEM_ROT_VF_MEM,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_prp_vf_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    IPU_ROTATE_NONE,
+					    vout->display_bufs[0],
+					    vout->display_bufs[1], 0, 0) != 0) {
+			dev_err(dev,
+				"Error initializing PP-VDI output buffer\n");
+			return -EINVAL;
+		}
+
+		if (ipu_link_channels(vout->post_proc_ch, MEM_ROT_VF_MEM) < 0)
+			return -EINVAL;
+
+		ipu_select_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, 0);
+		ipu_select_buffer(MEM_ROT_VF_MEM, IPU_OUTPUT_BUFFER, 1);
+
+		ipu_enable_channel(MEM_ROT_VF_MEM);
+		*display_input_ch = MEM_ROT_VF_MEM;
+
+	} else {
+		if (ipu_init_channel_buffer(vout->post_proc_ch,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_prp_vf_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    vout->rotate,
+					    vout->display_bufs[0],
+					    vout->display_bufs[1], 0, 0) != 0) {
+			dev_err(dev,
+				"Error initializing PP-VDI output buffer\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+/*!
+ * Start the output stream
+ *
+ * @param vout      structure vout_data *
+ *
+ * @return status  0 Success
+ */
+static int init_PP(ipu_channel_params_t params, vout_data *vout,
+		   struct device *dev, struct fb_info *fbi,
+		   ipu_channel_t *display_input_ch, u16 out_width,
+		   u16 out_height)
+{
+	params.mem_pp_mem.in_width = vout->v2f.fmt.pix.width;
+	params.mem_pp_mem.in_height = vout->v2f.fmt.pix.height;
+	params.mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
+	params.mem_pp_mem.out_width = out_width;
+	params.mem_pp_mem.out_height = out_height;
+	if (vout->display_ch == ADC_SYS2)
+		params.mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
+	else
+		params.mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi);
+	if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
+		dev_err(dev, "Error initializing PP channel\n");
+		return -EINVAL;
+	}
+
+	if (ipu_init_channel_buffer(vout->post_proc_ch,
+				    IPU_INPUT_BUFFER,
+				    params.mem_pp_mem.in_pixel_fmt,
+				    params.mem_pp_mem.in_width,
+				    params.mem_pp_mem.in_height,
+				    vout->v2f.fmt.pix.bytesperline /
+				    bytes_per_pixel(params.mem_pp_mem.
+						    in_pixel_fmt),
+				    IPU_ROTATE_NONE,
+				    vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
+				    vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
+				    vout->offset.u_offset,
+				    vout->offset.v_offset) != 0) {
+		dev_err(dev, "Error initializing PP input buffer\n");
+		return -EINVAL;
+	}
+
+	if (!ipu_can_rotate_in_place(vout->rotate)) {
+		if (vout->rot_pp_bufs[0]) {
+			mxc_free_buffers(vout->rot_pp_bufs,
+					 vout->rot_pp_bufs_vaddr, 2,
+					 vout->display_buf_size);
+		}
+		if (mxc_allocate_buffers
+		    (vout->rot_pp_bufs, vout->rot_pp_bufs_vaddr, 2,
+		     vout->display_buf_size) < 0) {
+			return -ENOBUFS;
+		}
+
+		if (ipu_init_channel_buffer(vout->post_proc_ch,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_pp_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    IPU_ROTATE_NONE,
+					    vout->rot_pp_bufs[0],
+					    vout->rot_pp_bufs[1], 0, 0) != 0) {
+			dev_err(dev, "Error initializing PP output buffer\n");
+			return -EINVAL;
+		}
+
+		if (ipu_init_channel(MEM_ROT_PP_MEM, NULL) != 0) {
+			dev_err(dev, "Error initializing PP ROT channel\n");
+			return -EINVAL;
+		}
+		if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
+					    IPU_INPUT_BUFFER,
+					    params.mem_pp_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    vout->rotate,
+					    vout->rot_pp_bufs[0],
+					    vout->rot_pp_bufs[1], 0, 0) != 0) {
+			dev_err(dev,
+				"Error initializing PP ROT input buffer\n");
+			return -EINVAL;
+		}
+
+		/* swap width and height */
+		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
+			out_width = vout->crop_current.width;
+			out_height = vout->crop_current.height;
+		}
+
+		if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_pp_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    IPU_ROTATE_NONE,
+					    vout->display_bufs[0],
+					    vout->display_bufs[1], 0, 0) != 0) {
+			dev_err(dev, "Error initializing PP output buffer\n");
+			return -EINVAL;
+		}
+
+		if (ipu_link_channels(vout->post_proc_ch, MEM_ROT_PP_MEM) < 0)
+			return -EINVAL;
+
+		ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0);
+		ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 1);
+
+		ipu_enable_channel(MEM_ROT_PP_MEM);
+		*display_input_ch = MEM_ROT_PP_MEM;
+
+	} else {
+		if (ipu_init_channel_buffer(vout->post_proc_ch,
+					    IPU_OUTPUT_BUFFER,
+					    params.mem_pp_mem.
+					    out_pixel_fmt, out_width,
+					    out_height, out_width,
+					    vout->rotate,
+					    vout->display_bufs[0],
+					    vout->display_bufs[1], 0, 0) != 0) {
+			dev_err(dev, "Error initializing PP output buffer\n");
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
 
 /*!
  * Start the output stream
@@ -473,10 +726,24 @@ static int mxc_v4l2out_streamon(vout_data * vout)
 	u16 out_width;
 	u16 out_height;
 	int disp_irq = 0;
-	ipu_channel_t display_input_ch = MEM_PP_MEM;
+	ipu_channel_t display_input_ch;
 	bool use_direct_adc = false;
 	mm_segment_t old_fs;
 
+	dev_dbg(dev, "mxc_v4l2out_streamon: field format=%d\n",
+		vout->field_fmt);
+	if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+		ipu_request_irq(IPU_IRQ_PRP_VF_OUT_EOF,
+				mxc_v4l2out_pp_in_irq_handler,
+				0, &vout->video_dev->name, vout);
+		display_input_ch = MEM_VDI_PRP_VF_MEM;
+	} else {
+		ipu_request_irq(IPU_IRQ_PP_IN_EOF,
+				mxc_v4l2out_pp_in_irq_handler,
+				0, &vout->video_dev->name, vout);
+		display_input_ch = MEM_PP_MEM;
+	}
+
 	if (!vout)
 		return -EINVAL;
 
@@ -500,7 +767,10 @@ static int mxc_v4l2out_streamon(vout_data * vout)
 
 	/* Init Display Channel */
 #ifdef CONFIG_FB_MXC_ASYNC_PANEL
-	ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
+	if (vout->field_fmt == V4L2_FIELD_ALTERNATE)
+		ipu_enable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
+	else
+		ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
 
 	if (vout->cur_disp_output < DISP3) {
 		mxcfb_set_refresh_mode(fbi, MXCFB_REFRESH_OFF, 0);
@@ -531,7 +801,6 @@ static int mxc_v4l2out_streamon(vout_data * vout)
 				dev_err(dev, "Error initializing PP chan\n");
 				return -EINVAL;
 			}
-
 			if (ipu_init_channel_buffer(vout->post_proc_ch,
 						    IPU_INPUT_BUFFER,
 						    params.mem_pp_adc.
@@ -670,149 +939,37 @@ static int mxc_v4l2out_streamon(vout_data * vout)
 		    (fbi->fix.line_length * fbi->var.yres);
 		vout->display_buf_size = vout->crop_current.width *
 		    vout->crop_current.height * fbi->var.bits_per_pixel / 8;
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE)
+			vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
+		else
+			vout->post_proc_ch = MEM_PP_MEM;
 	}
 
 	/* Init PP */
 	if (use_direct_adc == false && !vout->ic_bypass) {
-		vout->post_proc_ch = MEM_PP_MEM;
-		ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
-
-		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
-			out_width = vout->crop_current.height;
-			out_height = vout->crop_current.width;
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+			vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
+			ipu_enable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
+		} else {
+			vout->post_proc_ch = MEM_PP_MEM;
+			ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
 		}
-		memset(&params, 0, sizeof(params));
-		params.mem_pp_mem.in_width = vout->v2f.fmt.pix.width;
-		params.mem_pp_mem.in_height = vout->v2f.fmt.pix.height;
 
 		if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
 			out_width = vout->crop_current.height;
 			out_height = vout->crop_current.width;
 		}
 		memset(&params, 0, sizeof(params));
-		params.mem_pp_mem.in_width = vout->v2f.fmt.pix.width;
-		params.mem_pp_mem.in_height = vout->v2f.fmt.pix.height;
-		params.mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
-		params.mem_pp_mem.out_width = out_width;
-		params.mem_pp_mem.out_height = out_height;
-		if (vout->display_ch == ADC_SYS2)
-			params.mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
-		else
-			params.mem_pp_mem.out_pixel_fmt = bpp_to_fmt(fbi);
-		if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
-			dev_err(dev, "Error initializing PP channel\n");
-			return -EINVAL;
-		}
-
-		if (ipu_init_channel_buffer(vout->post_proc_ch,
-						IPU_INPUT_BUFFER,
-						params.mem_pp_mem.in_pixel_fmt,
-						params.mem_pp_mem.in_width,
-						params.mem_pp_mem.in_height,
-						vout->v2f.fmt.pix.bytesperline /
-						bytes_per_pixel(params.mem_pp_mem.
-								in_pixel_fmt),
-						IPU_ROTATE_NONE,
-						vout->v4l2_bufs[vout->ipu_buf[0]].m.
-						offset,
-						vout->v4l2_bufs[vout->ipu_buf[1]].m.
-						offset, vout->offset.u_offset,
-						vout->offset.v_offset) != 0) {
-			dev_err(dev, "Error initializing PP input buffer\n");
-			return -EINVAL;
-		}
-
-		if (!ipu_can_rotate_in_place(vout->rotate)) {
-			if (vout->rot_pp_bufs[0]) {
-				mxc_free_buffers(vout->rot_pp_bufs,
-						 vout->rot_pp_bufs_vaddr, 2,
-						 vout->display_buf_size);
-			}
-			if (mxc_allocate_buffers
-			    (vout->rot_pp_bufs, vout->rot_pp_bufs_vaddr, 2,
-			     vout->display_buf_size) < 0) {
-				return -ENOBUFS;
-			}
-
-			if (ipu_init_channel_buffer(vout->post_proc_ch,
-						    IPU_OUTPUT_BUFFER,
-						    params.mem_pp_mem.
-						    out_pixel_fmt, out_width,
-						    out_height, out_width,
-						    IPU_ROTATE_NONE,
-						    vout->rot_pp_bufs[0],
-						    vout->rot_pp_bufs[1], 0,
-						    0) != 0) {
-				dev_err(dev,
-					"Error initializing PP output buffer\n");
-				return -EINVAL;
-			}
-
-			if (ipu_init_channel(MEM_ROT_PP_MEM, NULL) != 0) {
-				dev_err(dev,
-					"Error initializing PP ROT channel\n");
-				return -EINVAL;
-			}
-
-			if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
-						    IPU_INPUT_BUFFER,
-						    params.mem_pp_mem.
-						    out_pixel_fmt, out_width,
-						    out_height, out_width,
-						    vout->rotate,
-						    vout->rot_pp_bufs[0],
-						    vout->rot_pp_bufs[1], 0,
-						    0) != 0) {
-				dev_err(dev,
-					"Error initializing PP ROT input buffer\n");
-				return -EINVAL;
-			}
-
-			/* swap width and height */
-			if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
-				out_width = vout->crop_current.width;
-				out_height = vout->crop_current.height;
-			}
-
-			if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
-						    IPU_OUTPUT_BUFFER,
-						    params.mem_pp_mem.
-						    out_pixel_fmt, out_width,
-						    out_height, out_width,
-						    IPU_ROTATE_NONE,
-						    vout->display_bufs[0],
-						    vout->display_bufs[1], 0,
-						    0) != 0) {
-				dev_err(dev,
-					"Error initializing PP output buffer\n");
-				return -EINVAL;
-			}
-
-			if (ipu_link_channels(vout->post_proc_ch,
-					      MEM_ROT_PP_MEM) < 0) {
-				return -EINVAL;
-			}
-			ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0);
-			ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 1);
-
-			ipu_enable_channel(MEM_ROT_PP_MEM);
-
-			display_input_ch = MEM_ROT_PP_MEM;
+		int rc;
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+			rc = init_VDI(params, vout, dev, fbi, &display_input_ch,
+				      out_width, out_height);
 		} else {
-			if (ipu_init_channel_buffer(vout->post_proc_ch,
-						    IPU_OUTPUT_BUFFER,
-						    params.mem_pp_mem.
-						    out_pixel_fmt, out_width,
-						    out_height, out_width,
-						    vout->rotate,
-						    vout->display_bufs[0],
-						    vout->display_bufs[1], 0,
-						    0) != 0) {
-				dev_err(dev,
-					"Error initializing PP output buffer\n");
-				return -EINVAL;
-			}
+			rc = init_PP(params, vout, dev, fbi, &display_input_ch,
+				     out_width, out_height);
 		}
+		if (rc < 0)
+			return rc;
 		if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) {
 			dev_err(dev, "Error linking ipu channels\n");
 			return -EINVAL;
@@ -889,6 +1046,11 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
 		return 0;
 	}
 
+	if (vout->field_fmt == V4L2_FIELD_ALTERNATE)
+		ipu_free_irq(IPU_IRQ_PRP_VF_OUT_EOF, vout);
+	else
+		ipu_free_irq(IPU_IRQ_PP_IN_EOF, vout);
+
 	spin_lock_irqsave(&g_lock, lockflag);
 
 	del_timer(&vout->output_timer);
@@ -897,8 +1059,12 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
 		vout->state = STATE_STREAM_STOPPING;
 	}
 
-	if (!vout->ic_bypass)
-		ipu_disable_irq(IPU_IRQ_PP_IN_EOF);
+	if (!vout->ic_bypass) {
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE)
+			ipu_disable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
+		else
+			ipu_disable_irq(IPU_IRQ_PP_IN_EOF);
+	}
 
 	spin_unlock_irqrestore(&g_lock, lockflag);
 
@@ -921,11 +1087,23 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
 		}
 	}
 
-	if (vout->post_proc_ch == MEM_PP_MEM) {	/* SDC or ADC with Rotation */
+	if (vout->post_proc_ch == MEM_PP_MEM ||
+	    vout->post_proc_ch == MEM_PRP_VF_MEM ||
+	    vout->post_proc_ch == MEM_VDI_PRP_VF_MEM) {
+		/* SDC or ADC with Rotation */
 		if (!ipu_can_rotate_in_place(vout->rotate)) {
-			ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM);
-			ipu_unlink_channels(MEM_ROT_PP_MEM, vout->display_ch);
-			ipu_disable_channel(MEM_ROT_PP_MEM, true);
+			if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+				ipu_unlink_channels(MEM_VDI_PRP_VF_MEM,
+						    MEM_ROT_VF_MEM);
+				ipu_unlink_channels(MEM_ROT_VF_MEM,
+						    vout->display_ch);
+				ipu_disable_channel(MEM_ROT_VF_MEM, true);
+			} else {
+				ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM);
+				ipu_unlink_channels(MEM_ROT_PP_MEM,
+						    vout->display_ch);
+				ipu_disable_channel(MEM_ROT_PP_MEM, true);
+			}
 
 			if (vout->rot_pp_bufs[0]) {
 				mxc_free_buffers(vout->rot_pp_bufs,
@@ -933,9 +1111,18 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
 						 vout->display_buf_size);
 			}
 		} else {
-			ipu_unlink_channels(MEM_PP_MEM, vout->display_ch);
+			if (vout->field_fmt == V4L2_FIELD_ALTERNATE)
+				ipu_unlink_channels(MEM_VDI_PRP_VF_MEM,
+						    vout->display_ch);
+			else
+				ipu_unlink_channels(MEM_PP_MEM,
+						    vout->display_ch);
+		}
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+			ipu_disable_channel(MEM_VDI_PRP_VF_MEM, true);
+		} else {
+			ipu_disable_channel(MEM_PP_MEM, true);
 		}
-		ipu_disable_channel(MEM_PP_MEM, true);
 
 		if (vout->display_ch == ADC_SYS2 ||
 			vout->display_ch == MEM_FG_SYNC) {
@@ -955,9 +1142,15 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
 			vout->display_bufs[1] = 0;
 		}
 
-		ipu_uninit_channel(MEM_PP_MEM);
-		if (!ipu_can_rotate_in_place(vout->rotate))
-			ipu_uninit_channel(MEM_ROT_PP_MEM);
+		if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+			ipu_uninit_channel(MEM_VDI_PRP_VF_MEM);
+			if (!ipu_can_rotate_in_place(vout->rotate))
+				ipu_uninit_channel(MEM_ROT_VF_MEM);
+		} else {
+			ipu_uninit_channel(MEM_PP_MEM);
+			if (!ipu_can_rotate_in_place(vout->rotate))
+				ipu_uninit_channel(MEM_ROT_PP_MEM);
+		}
 	} else {		/* ADC Direct */
 		ipu_disable_channel(MEM_PP_ADC, true);
 		ipu_uninit_channel(MEM_PP_ADC);
@@ -1060,6 +1253,25 @@ static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f)
 		bytesperline = f->fmt.pix.bytesperline;
 	}
 
+	/* Based on http://v4l2spec.bytesex.org/spec/x6386.htm#V4L2-FIELD */
+	switch (f->fmt.pix.field) {
+		/* Images are in progressive format, not interlaced */
+	case V4L2_FIELD_NONE:
+		vout->field_fmt = V4L2_FIELD_NONE;
+		break;
+		/* The two fields of a frame are passed in separate buffers,
+		   in temporal order, i. e. the older one first. */
+	case V4L2_FIELD_ALTERNATE:
+	case V4L2_FIELD_INTERLACED_TB:
+	case V4L2_FIELD_INTERLACED_BT:
+		if (cpu_is_mx51())
+			vout->field_fmt = V4L2_FIELD_ALTERNATE;
+		break;
+	default:
+		vout->field_fmt = V4L2_FIELD_NONE;
+		break;
+	}
+
 	switch (f->fmt.pix.pixelformat) {
 	case V4L2_PIX_FMT_YUV422P:
 		/* byteperline for YUV planar formats is for
@@ -1178,11 +1390,8 @@ static int mxc_v4l2out_open(struct inode *inode, struct file *file)
 	if (signal_pending(current))
 		goto oops;
 
-	if (vout->open_count++ == 0) {
-		ipu_request_irq(IPU_IRQ_PP_IN_EOF,
-				mxc_v4l2out_pp_in_irq_handler,
-				0, dev->name, vout);
 
+	if (vout->open_count++ == 0) {
 		init_waitqueue_head(&vout->v4l_bufq);
 
 		init_timer(&vout->output_timer);
@@ -1224,8 +1433,6 @@ static int mxc_v4l2out_close(struct inode *inode, struct file *file)
 		if (vout->state != STATE_STREAM_OFF)
 			mxc_v4l2out_streamoff(vout);
 
-		ipu_free_irq(IPU_IRQ_PP_IN_EOF, vout);
-
 		file->private_data = NULL;
 
 		mxc_free_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr,
@@ -1724,7 +1931,7 @@ static int mxc_v4l2out_mmap(struct file *file, struct vm_area_struct *vma)
 	}
 
 	/* make buffers inner write-back, outer write-thru cacheable */
-//	vma->vm_page_prot = pgprot_outer_wrthru(vma->vm_page_prot);
+	/* vma->vm_page_prot = pgprot_outer_wrthru(vma->vm_page_prot);*/
 
 	if (remap_pfn_range(vma, vma->vm_start,
 			    vma->vm_pgoff, size, vma->vm_page_prot)) {
@@ -1822,7 +2029,7 @@ static int mxc_v4l2out_probe(struct platform_device *pdev)
 	}
 	dev_info(&pdev->dev, "Registered device video%d\n",
 		 vout->video_dev->minor & 0x1f);
-//	vout->video_dev->dev = &pdev->dev;
+	/*vout->video_dev->dev = &pdev->dev;*/
 
 	video_set_drvdata(vout->video_dev, vout);
 
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h
index 9f5001f..6d40840 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.h
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h
@@ -32,6 +32,7 @@
 
 #include <linux/ipu.h>
 #include <linux/mxc_v4l2.h>
+#include <linux/videodev2.h>
 
 #define MIN_FRAME_NUM 2
 #define MAX_FRAME_NUM 30
@@ -125,6 +126,7 @@ typedef struct _vout_data {
 	/* crop */
 	struct v4l2_rect crop_bounds[MXC_V4L2_OUT_NUM_OUTPUTS];
 	struct v4l2_rect crop_current;
+	enum v4l2_field field_fmt;
 } vout_data;
 
 #endif
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index eb11b4a..a121970 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -49,7 +49,7 @@ unsigned char g_dc_di_assignment[10];
 ipu_channel_t g_ipu_csi_channel[2];
 int g_ipu_irq[2];
 int g_ipu_hw_rev;
-bool g_sec_chan_en[21];
+bool g_sec_chan_en[22];
 bool g_thrd_chan_en[21];
 uint32_t g_channel_init_mask;
 uint32_t g_channel_enable_mask;
@@ -65,8 +65,11 @@ static int ipu_dmfc_use_count;
 static int ipu_smfc_use_count;
 static int ipu_ic_use_count;
 static int ipu_rot_use_count;
+static int ipu_vdi_use_count;
 static int ipu_di_use_count[2];
 static int ipu_csi_use_count[2];
+/* Set to the follow using IC direct channel, default non */
+static ipu_channel_t using_ic_dirct_ch;
 
 /* for power gating */
 static uint32_t ipu_conf_reg;
@@ -89,6 +92,7 @@ u32 *ipu_csi_reg[2];
 u32 *ipu_cpmem_base;
 u32 *ipu_tpmem_base;
 u32 *ipu_disp_base[2];
+u32 *ipu_vdi_reg;
 
 /* Static functions */
 static irqreturn_t ipu_irq_handler(int irq, void *desc);
@@ -188,7 +192,9 @@ static int ipu_probe(struct platform_device *pdev)
 	ipu_tpmem_base = ioremap(ipu_base + IPU_TPM_REG_BASE, SZ_64K);
 	ipu_dc_tmpl_reg = ioremap(ipu_base + IPU_DC_TMPL_REG_BASE, SZ_128K);
 	ipu_disp_base[1] = ioremap(ipu_base + IPU_DISP1_BASE, SZ_4K);
+	ipu_vdi_reg = ioremap(ipu_base + IPU_VDI_REG_BASE, PAGE_SIZE);
 
+	dev_dbg(g_ipu_dev, "IPU VDI Regs = %p\n", ipu_vdi_reg);
 	dev_dbg(g_ipu_dev, "IPU CM Regs = %p\n", ipu_cm_reg);
 	dev_dbg(g_ipu_dev, "IPU IC Regs = %p\n", ipu_ic_reg);
 	dev_dbg(g_ipu_dev, "IPU IDMAC Regs = %p\n", ipu_idmac_reg);
@@ -269,6 +275,7 @@ int ipu_remove(struct platform_device *pdev)
 	iounmap(ipu_tpmem_base);
 	iounmap(ipu_dc_tmpl_reg);
 	iounmap(ipu_disp_base[1]);
+	iounmap(ipu_vdi_reg);
 
 	return 0;
 }
@@ -384,6 +391,12 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
 			ret = -EINVAL;
 			goto err;
 		}
+		if ((using_ic_dirct_ch != 0) &&
+			(using_ic_dirct_ch != MEM_PRP_ENC_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		using_ic_dirct_ch = CSI_PRP_ENC_MEM;
 
 		ipu_ic_use_count++;
 		ipu_csi_use_count[params->csi_prp_enc_mem.csi]++;
@@ -413,6 +426,12 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
 			ret = -EINVAL;
 			goto err;
 		}
+		if ((using_ic_dirct_ch != 0) &&
+			(using_ic_dirct_ch != MEM_PRP_VF_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		using_ic_dirct_ch = CSI_PRP_VF_MEM;
 
 		ipu_ic_use_count++;
 		ipu_csi_use_count[params->csi_prp_vf_mem.csi]++;
@@ -449,6 +468,24 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
 
 		_ipu_ic_init_prpvf(params, false);
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		if ((using_ic_dirct_ch != 0) &&
+			(using_ic_dirct_ch != MEM_VDI_PRP_VF_MEM)) {
+			ret = -EINVAL;
+			goto err;
+		}
+		using_ic_dirct_ch = MEM_VDI_PRP_VF_MEM;
+		ipu_ic_use_count++;
+		ipu_vdi_use_count++;
+		reg = __raw_readl(IPU_FS_PROC_FLOW1);
+		reg &= ~FS_VDI_SRC_SEL_MASK;
+		__raw_writel(reg , IPU_FS_PROC_FLOW1);
+
+		if (params->mem_prp_vf_mem.graphics_combine_en)
+			g_sec_chan_en[IPU_CHAN_ID(channel)] = true;
+		_ipu_ic_init_prpvf(params, false);
+		_ipu_vdi_init(params);
+		break;
 	case MEM_ROT_VF_MEM:
 		ipu_ic_use_count++;
 		ipu_rot_use_count++;
@@ -546,6 +583,10 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
 	ipu_conf = __raw_readl(IPU_CONF);
 	if (ipu_ic_use_count == 1)
 		ipu_conf |= IPU_CONF_IC_EN;
+	if (ipu_vdi_use_count == 1) {
+		ipu_conf |= IPU_CONF_VDI_EN;
+		ipu_conf |= IPU_CONF_IC_INPUT;
+	}
 	if (ipu_rot_use_count == 1)
 		ipu_conf |= IPU_CONF_ROT_EN;
 	if (ipu_dc_use_count == 1)
@@ -635,6 +676,8 @@ void ipu_uninit_channel(ipu_channel_t channel)
 		break;
 	case CSI_PRP_ENC_MEM:
 		ipu_ic_use_count--;
+		if (using_ic_dirct_ch == CSI_PRP_ENC_MEM)
+			using_ic_dirct_ch = 0;
 		_ipu_ic_uninit_prpenc();
 		if (g_ipu_csi_channel[0] == channel) {
 			g_ipu_csi_channel[0] = CHAN_NONE;
@@ -646,6 +689,8 @@ void ipu_uninit_channel(ipu_channel_t channel)
 		break;
 	case CSI_PRP_VF_MEM:
 		ipu_ic_use_count--;
+		if (using_ic_dirct_ch == CSI_PRP_VF_MEM)
+			using_ic_dirct_ch = 0;
 		_ipu_ic_uninit_prpvf();
 		if (g_ipu_csi_channel[0] == channel) {
 			g_ipu_csi_channel[0] = CHAN_NONE;
@@ -661,6 +706,16 @@ void ipu_uninit_channel(ipu_channel_t channel)
 		reg = __raw_readl(IPU_FS_PROC_FLOW1);
 		__raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ipu_ic_use_count--;
+		ipu_vdi_use_count--;
+		if (using_ic_dirct_ch == MEM_VDI_PRP_VF_MEM)
+			using_ic_dirct_ch = 0;
+		_ipu_ic_uninit_prpvf();
+		_ipu_vdi_uninit();
+		reg = __raw_readl(IPU_FS_PROC_FLOW1);
+		__raw_writel(reg & ~FS_VF_IN_VALID, IPU_FS_PROC_FLOW1);
+		break;
 	case MEM_ROT_VF_MEM:
 		ipu_rot_use_count--;
 		ipu_ic_use_count--;
@@ -726,6 +781,10 @@ void ipu_uninit_channel(ipu_channel_t channel)
 
 	if (ipu_ic_use_count == 0)
 		ipu_conf &= ~IPU_CONF_IC_EN;
+	if (ipu_vdi_use_count == 0) {
+		ipu_conf &= ~IPU_CONF_VDI_EN;
+		ipu_conf &= ~IPU_CONF_IC_INPUT;
+	}
 	if (ipu_rot_use_count == 0)
 		ipu_conf &= ~IPU_CONF_ROT_EN;
 	if (ipu_dc_use_count == 0)
@@ -759,6 +818,7 @@ void ipu_uninit_channel(ipu_channel_t channel)
 	}
 
 	WARN_ON(ipu_ic_use_count < 0);
+	WARN_ON(ipu_vdi_use_count < 0);
 	WARN_ON(ipu_rot_use_count < 0);
 	WARN_ON(ipu_dc_use_count < 0);
 	WARN_ON(ipu_dp_use_count < 0);
@@ -927,7 +987,6 @@ int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
 	int ret = 0;
 	unsigned long lock_flags;
 	uint32_t dma_chan = channel_2_dma(channel, type);
-
 	if (dma_chan == IDMA_CHAN_INVALID)
 		return -EINVAL;
 
@@ -981,11 +1040,13 @@ EXPORT_SYMBOL(ipu_select_buffer);
 
 #define NA	-1
 static int proc_dest_sel[] =
-    { 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15 };
+  { 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
+    0, 1, 1, 5, 5, 5, 5, 5, 7, 8, 9, 10, 11, 12, 14, 31 };
 static int proc_src_sel[] = { 0, 6, 7, 6, 7, 8, 5, NA, NA, NA,
-NA, NA, NA, NA, NA, 1, 2, 3, 4, 7, 8 };
+  NA, NA, NA, NA, NA,  1,  2,  3,  4,  7,  8, NA, NA, NA };
 static int disp_src_sel[] = { 0, 6, 7, 8, 3, 4, 5, NA, NA, NA,
-NA, NA, NA, NA, NA, 1, NA, 2, NA, 3, 4 };
+  NA, NA, NA, NA, NA,  1, NA,  2, NA,  3,  4,  4,  4,  4 };
+
 
 /*!
  * This function links 2 channels together for automatic frame
@@ -1084,6 +1145,12 @@ int32_t ipu_link_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch)
 		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
 		    FS_PRPVF_DEST_SEL_OFFSET;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		fs_proc_flow2 |=
+		    proc_dest_sel[IPU_CHAN_ID(dest_ch)] <<
+		    FS_PRPVF_DEST_SEL_OFFSET;
+		break;
 	case MEM_ROT_VF_MEM:
 		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
 		fs_proc_flow2 |=
@@ -1123,6 +1190,11 @@ int32_t ipu_link_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch)
 		fs_proc_flow1 |=
 		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		fs_proc_flow1 |=
+		    proc_src_sel[IPU_CHAN_ID(src_ch)] << FS_PRP_SRC_SEL_OFFSET;
+		break;
 	case MEM_ROT_VF_MEM:
 		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
 		fs_proc_flow1 |=
@@ -1242,6 +1314,9 @@ int32_t ipu_unlink_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch)
 	case MEM_PRP_VF_MEM:
 		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow2 &= ~FS_PRPVF_DEST_SEL_MASK;
+		break;
 	case MEM_ROT_VF_MEM:
 		fs_proc_flow2 &= ~FS_PRPVF_ROT_DEST_SEL_MASK;
 		break;
@@ -1266,6 +1341,9 @@ int32_t ipu_unlink_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch)
 	case MEM_PRP_VF_MEM:
 		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		fs_proc_flow1 &= ~FS_PRP_SRC_SEL_MASK;
+		break;
 	case MEM_ROT_VF_MEM:
 		fs_proc_flow1 &= ~FS_PRPVF_ROT_SRC_SEL_MASK;
 		break;
@@ -1368,7 +1446,8 @@ int32_t ipu_enable_channel(ipu_channel_t channel)
 	}
 
 	if ((g_sec_chan_en[IPU_CHAN_ID(channel)]) &&
-		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM))) {
+		((channel == MEM_PP_MEM) || (channel == MEM_PRP_VF_MEM) ||
+		 (channel == MEM_VDI_PRP_VF_MEM))) {
 		sec_dma = channel_2_dma(channel, IPU_GRAPH_IN_BUFFER);
 		reg = __raw_readl(IDMAC_CHA_EN(sec_dma));
 		__raw_writel(reg | idma_mask(sec_dma), IDMAC_CHA_EN(sec_dma));
@@ -1784,6 +1863,9 @@ uint32_t _ipu_channel_status(ipu_channel_t channel)
 	case MEM_PRP_VF_MEM:
 		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		stat = (task_stat_reg & TSTAT_VF_MASK) >> TSTAT_VF_OFFSET;
+		break;
 	case MEM_ROT_VF_MEM:
 		stat =
 		    (task_stat_reg & TSTAT_VF_ROT_MASK) >> TSTAT_VF_ROT_OFFSET;
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
index 4a05ce5..60ba843 100644
--- a/drivers/mxc/ipu3/ipu_ic.c
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/spinlock.h>
+#include <linux/videodev2.h>
 #include <linux/io.h>
 #include <linux/ipu.h>
 
@@ -64,6 +65,9 @@ void _ipu_ic_enable_task(ipu_channel_t channel)
 	case MEM_PRP_VF_MEM:
 		ic_conf |= IC_CONF_PRPVF_EN;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf |= IC_CONF_PRPVF_EN;
+		break;
 	case MEM_ROT_VF_MEM:
 		ic_conf |= IC_CONF_PRPVF_ROT_EN;
 		break;
@@ -96,6 +100,9 @@ void _ipu_ic_disable_task(ipu_channel_t channel)
 	case MEM_PRP_VF_MEM:
 		ic_conf &= ~IC_CONF_PRPVF_EN;
 		break;
+	case MEM_VDI_PRP_VF_MEM:
+		ic_conf &= ~IC_CONF_PRPVF_EN;
+		break;
 	case MEM_ROT_VF_MEM:
 		ic_conf &= ~IC_CONF_PRPVF_ROT_EN;
 		break;
@@ -118,6 +125,36 @@ void _ipu_ic_disable_task(ipu_channel_t channel)
 	__raw_writel(ic_conf, IC_CONF);
 }
 
+void _ipu_vdi_init(ipu_channel_params_t *params)
+{
+	uint32_t reg;
+	uint32_t pixel_fmt;
+
+	reg = ((params->mem_prp_vf_mem.in_height-1) << 16) |
+	  (params->mem_prp_vf_mem.in_width-1);
+	__raw_writel(reg, VDI_FSIZE);
+
+	/* Full motion, only vertical filter is used
+	   Burst size is 4 accesses */
+	pixel_fmt =
+	    (params->mem_prp_vf_mem.in_pixel_fmt ==
+	     V4L2_PIX_FMT_YUV422P) ? VDI_C_CH_422 : VDI_C_CH_420;
+
+	reg = pixel_fmt | VDI_C_MOT_SEL_FULL | VDI_C_BURST_SIZE2_4;
+	__raw_writel(reg, VDI_C);
+
+	reg = __raw_readl(IC_CONF);
+	reg &= ~IC_CONF_RWS_EN;
+	__raw_writel(reg, IC_CONF);
+}
+
+_ipu_vdi_uninit(void)
+{
+	uint32_t reg;
+	__raw_writel(0, VDI_FSIZE);
+	__raw_writel(0, VDI_C);
+}
+
 void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi)
 {
 	uint32_t reg, ic_conf;
@@ -165,7 +202,7 @@ void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi)
 
 		if (!(ic_conf & IC_CONF_PRPVF_CSC1)) {
 			/* need transparent CSC1 conversion */
-			_init_csc(IC_TASK_VIEWFINDER, RGB, RGB, 1);
+			_init_csc(IC_TASK_POST_PROCESSOR, RGB, RGB, 1);
 			ic_conf |= IC_CONF_PRPVF_CSC1;  /* Enable RGB->RGB CSC */
 		}
 		in_fmt = format_to_colorspace(params->mem_prp_vf_mem.in_g_pixel_fmt);
diff --git a/drivers/mxc/ipu3/ipu_param_mem.h b/drivers/mxc/ipu3/ipu_param_mem.h
index 44f5a07..dbb763b 100644
--- a/drivers/mxc/ipu3/ipu_param_mem.h
+++ b/drivers/mxc/ipu3/ipu_param_mem.h
@@ -146,8 +146,14 @@ static inline void _ipu_ch_param_init(int ch,
 	memset(&params, 0, sizeof(params));
 
 	ipu_ch_param_set_field(&params, 0, 125, 13, width - 1);
-	ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
-	ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+
+	if ((ch == 8) || (ch == 9) || (ch == 10)) {
+		ipu_ch_param_set_field(&params, 0, 138, 12, (height / 2) - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, (stride * 2) - 1);
+	} else {
+		ipu_ch_param_set_field(&params, 0, 138, 12, height - 1);
+		ipu_ch_param_set_field(&params, 1, 102, 14, stride - 1);
+	}
 
 	ipu_ch_param_set_field(&params, 1, 0, 29, addr0 >> 3);
 	ipu_ch_param_set_field(&params, 1, 29, 29, addr1 >> 3);
@@ -158,6 +164,7 @@ static inline void _ipu_ch_param_init(int ch,
 		ipu_ch_param_set_field(&params, 0, 107, 3, 5);	/* bits/pixel */
 		ipu_ch_param_set_field(&params, 1, 85, 4, 6);	/* pix format */
 		ipu_ch_param_set_field(&params, 1, 78, 7, 63);	/* burst size */
+
 		break;
 	case IPU_PIX_FMT_GENERIC_32:
 		/*Represents 32-bit Generic data */
@@ -167,6 +174,7 @@ static inline void _ipu_ch_param_init(int ch,
 		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
 		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
 
+
 		_ipu_ch_params_set_packing(&params, 5, 0, 6, 5, 5, 11, 1, 16);
 		/* Set WID3 to be 8-bit for seperate alpha channel */
 		if (ch == 14 || ch == 15)
@@ -212,14 +220,13 @@ static inline void _ipu_ch_param_init(int ch,
 	case IPU_PIX_FMT_ABGR32:
 		ipu_ch_param_set_field(&params, 0, 107, 3, 0);	/* bits/pixel */
 		ipu_ch_param_set_field(&params, 1, 85, 4, 7);	/* pix format */
-		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
 
 		_ipu_ch_params_set_packing(&params, 8, 0, 8, 8, 8, 16, 8, 24);
 		break;
 	case IPU_PIX_FMT_UYVY:
 		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
 		ipu_ch_param_set_field(&params, 1, 85, 4, 0xA);	/* pix format */
-		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
+		ipu_ch_param_set_field(&params, 1, 78, 7, 15);	/* burst size */
 		break;
 	case IPU_PIX_FMT_YUYV:
 		ipu_ch_param_set_field(&params, 0, 107, 3, 3);	/* bits/pixel */
@@ -229,13 +236,18 @@ static inline void _ipu_ch_param_init(int ch,
 	case IPU_PIX_FMT_YUV420P2:
 	case IPU_PIX_FMT_YUV420P:
 		ipu_ch_param_set_field(&params, 1, 85, 4, 2);	/* pix format */
-		ipu_ch_param_set_field(&params, 1, 78, 7, 31);	/* burst size */
 
 		if (uv_stride < stride / 2)
 			uv_stride = stride / 2;
 
-		u_offset = (u == 0) ? stride * height : u;
-		v_offset = (v == 0) ? u_offset + (uv_stride * height / 2) : v;
+		u_offset = stride * height;
+		v_offset = u_offset + (uv_stride * height / 2);
+		if ((ch == 8) || (ch == 9) || (ch == 10)) {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 15);  /* burst size */
+			uv_stride = uv_stride*2;
+		} else {
+			ipu_ch_param_set_field(&params, 1, 78, 7, 31);  /* burst size */
+		}
 		break;
 	case IPU_PIX_FMT_YVU422P:
 		/* BPP & pixel format */
@@ -270,6 +282,8 @@ static inline void _ipu_ch_param_init(int ch,
 		dev_err(g_ipu_dev, "mxc ipu: unimplemented pixel format\n");
 		break;
 	}
+	/*set burst size to 16*/
+
 
 	if (uv_stride)
 		ipu_ch_param_set_field(&params, 1, 128, 14, uv_stride - 1);
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
index c54315f..3fdd12a 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -60,6 +60,8 @@ int _ipu_chan_is_interlaced(ipu_channel_t channel);
 void _ipu_ic_enable_task(ipu_channel_t channel);
 void _ipu_ic_disable_task(ipu_channel_t channel);
 void _ipu_ic_init_prpvf(ipu_channel_params_t *params, bool src_is_csi);
+void _ipu_vdi_init(ipu_channel_params_t *params);
+void _ipu_vdi_uninit(void);
 void _ipu_ic_uninit_prpvf(void);
 void _ipu_ic_init_rotate_vf(ipu_channel_params_t *params);
 void _ipu_ic_uninit_rotate_vf(void);
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
index 4723c22..7769c10 100644
--- a/drivers/mxc/ipu3/ipu_regs.h
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -43,6 +43,8 @@
 #define IPU_TPM_REG_BASE	0x1F060000
 #define IPU_DC_TMPL_REG_BASE	0x1F080000
 #define IPU_ISP_TBPR_REG_BASE	0x1F0C0000
+#define IPU_VDI_REG_BASE	0x1E068000
+
 
 extern u32 *ipu_cm_reg;
 extern u32 *ipu_idmac_reg;
@@ -56,6 +58,7 @@ extern u32 *ipu_smfc_reg;
 extern u32 *ipu_csi_reg[];
 extern u32 *ipu_tpmem_base;
 extern u32 *ipu_disp_base[];
+extern u32 *ipu_vdi_reg;
 
 /* Register addresses */
 /* IPU Common registers */
@@ -123,6 +126,9 @@ extern u32 *ipu_disp_base[];
 #define IPUIRQ_2_CTRLREG(irq)	(IPU_INT_CTRL(1) + ((irq) / 32))
 #define IPUIRQ_2_MASK(irq)	(1UL << ((irq) & 0x1F))
 
+#define VDI_FSIZE (ipu_vdi_reg)
+#define VDI_C (ipu_vdi_reg + 0x0004/4)
+
 /* CMOS Sensor Interface Registers */
 #define CSI_SENS_CONF(csi)	(ipu_csi_reg[csi])
 #define CSI_SENS_FRM_SIZE(csi)	(ipu_csi_reg[csi] + 0x0004/4)
@@ -299,6 +305,7 @@ enum {
 	IPU_CONF_DMFC_EN = 0x00000400,
 	IPU_CONF_SMFC_EN = 0x00000100,
 	IPU_CONF_DC_EN = 0x00000200,
+	IPU_CONF_VDI_EN = 0x00001000,
 	IPU_CONF_IDMAC_DIS = 0x00400000,
 	IPU_CONF_IC_DMFC_SEL = 0x02000000,
 	IPU_CONF_IC_DMFC_SYNC = 0x04000000,
@@ -324,6 +331,9 @@ enum {
 	FS_PRP_SRC_SEL_OFFSET = 24,
 	FS_VF_IN_VALID = 0x80000000,
 	FS_ENC_IN_VALID = 0x40000000,
+	FS_VDI_SRC_SEL_MASK = 0x30000000,
+	FS_VDI_SRC_SEL_OFFSET = 28,
+
 
 	FS_PRPENC_DEST_SEL_MASK = 0x0000000F,
 	FS_PRPENC_DEST_SEL_OFFSET = 0,
@@ -594,6 +604,19 @@ enum {
 	DI_SER_CONF_SERIAL_RS_POL = 0x00000004,
 	DI_SER_CONF_SERIAL_CS_POL = 0x00000002,
 	DI_SER_CONF_WAIT4SERIAL = 0x00000001,
+
+	VDI_C_CH_420 = 0x00000000,
+	VDI_C_CH_422 = 0x00000002,
+	VDI_C_MOT_SEL_FULL = 0x00000008,
+	VDI_C_MOT_SEL_HIGH = 0x00000004,
+	VDI_C_MOT_SEL_MED = 0x00000000,
+	VDI_C_BURST_SIZE1_4 = 0x00000030,
+	VDI_C_BURST_SIZE2_4 = 0x00000300,
+	VDI_C_BURST_SIZE3_4 = 0x00003000,
+	VDI_C_VWM1_SET_1 = 0x00000000,
+	VDI_C_VWM1_CLR_2 = 0x00010000,
+	VDI_C_VWM3_SET_1 = 0x00000000,
+	VDI_C_VWM3_CLR_2 = 0x02000000,
 };
 
 enum di_pins {
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
index f671e6d..7819537 100644
--- a/include/linux/ipu.h
+++ b/include/linux/ipu.h
@@ -225,6 +225,10 @@ typedef enum {
 	CSI_PRP_ENC_MEM = _MAKE_CHAN(19, NO_DMA, NO_DMA, NO_DMA, 20),
 	CSI_PRP_VF_MEM = _MAKE_CHAN(20, NO_DMA, NO_DMA, NO_DMA, 21),
 
+	MEM_VDI_PRP_VF_MEM_P = _MAKE_CHAN(21, 8, 14, 17, 21),
+	MEM_VDI_PRP_VF_MEM = _MAKE_CHAN(22, 9, 14, 17, 21),
+	MEM_VDI_PRP_VF_MEM_N = _MAKE_CHAN(23, 10, 14, 17, 21),
+
 	MEM_PP_ADC = CHAN_NONE,
 	ADC_SYS2 = CHAN_NONE,
 #endif
-- 
1.6.0.4





More information about the kernel-team mailing list