[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, ¶ms) != 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, ¶ms) != 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(¶ms, 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(¶ms, 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, ¶ms) != 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(¶ms, 0, sizeof(params));
ipu_ch_param_set_field(¶ms, 0, 125, 13, width - 1);
- ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1);
- ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1);
+
+ if ((ch == 8) || (ch == 9) || (ch == 10)) {
+ ipu_ch_param_set_field(¶ms, 0, 138, 12, (height / 2) - 1);
+ ipu_ch_param_set_field(¶ms, 1, 102, 14, (stride * 2) - 1);
+ } else {
+ ipu_ch_param_set_field(¶ms, 0, 138, 12, height - 1);
+ ipu_ch_param_set_field(¶ms, 1, 102, 14, stride - 1);
+ }
ipu_ch_param_set_field(¶ms, 1, 0, 29, addr0 >> 3);
ipu_ch_param_set_field(¶ms, 1, 29, 29, addr1 >> 3);
@@ -158,6 +164,7 @@ static inline void _ipu_ch_param_init(int ch,
ipu_ch_param_set_field(¶ms, 0, 107, 3, 5); /* bits/pixel */
ipu_ch_param_set_field(¶ms, 1, 85, 4, 6); /* pix format */
ipu_ch_param_set_field(¶ms, 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(¶ms, 1, 85, 4, 7); /* pix format */
ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
+
_ipu_ch_params_set_packing(¶ms, 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(¶ms, 0, 107, 3, 0); /* bits/pixel */
ipu_ch_param_set_field(¶ms, 1, 85, 4, 7); /* pix format */
- ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
_ipu_ch_params_set_packing(¶ms, 8, 0, 8, 8, 8, 16, 8, 24);
break;
case IPU_PIX_FMT_UYVY:
ipu_ch_param_set_field(¶ms, 0, 107, 3, 3); /* bits/pixel */
ipu_ch_param_set_field(¶ms, 1, 85, 4, 0xA); /* pix format */
- ipu_ch_param_set_field(¶ms, 1, 78, 7, 31); /* burst size */
+ ipu_ch_param_set_field(¶ms, 1, 78, 7, 15); /* burst size */
break;
case IPU_PIX_FMT_YUYV:
ipu_ch_param_set_field(¶ms, 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(¶ms, 1, 85, 4, 2); /* pix format */
- ipu_ch_param_set_field(¶ms, 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(¶ms, 1, 78, 7, 15); /* burst size */
+ uv_stride = uv_stride*2;
+ } else {
+ ipu_ch_param_set_field(¶ms, 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(¶ms, 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