summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRan Ferderber <Ran.Ferderber@freescale.com>2009-08-11 10:45:22 +0300
committerJustin Waters <justin.waters@timesys.com>2009-10-13 11:05:09 -0400
commit1852787b446a0b8279dfd3efd9d47403c056ff31 (patch)
tree9a08a43108e63952cb3900cb665fda7e3c38f544
parenta9067a441adcab98b64e720c024698b2727c6476 (diff)
ENGR00114284: MX51: Add IPU interlace support in 2 more motion algorithms
Add algorithms for medium and low motion streams Signed-off-by: Ran Ferderber Ran.Ferderber@freescale.com
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.c365
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.h5
-rw-r--r--drivers/mxc/ipu3/ipu_common.c40
-rw-r--r--drivers/mxc/ipu3/ipu_ic.c82
-rw-r--r--drivers/mxc/ipu3/ipu_prv.h3
-rw-r--r--drivers/mxc/ipu3/ipu_regs.h6
-rw-r--r--include/linux/ipu.h17
-rw-r--r--include/linux/mxc_v4l2.h1
8 files changed, 404 insertions, 115 deletions
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index ac289e85ee5f..d38afbb17b46 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -36,6 +36,12 @@
#include "mxc_v4l2_output.h"
vout_data *g_vout;
+#define INTERLACED_CONTENT(vout) ((cpu_is_mx51_rev(CHIP_REV_2_0) >= 1) && \
+ (((vout)->field_fmt == V4L2_FIELD_INTERLACED_TB) || \
+ ((vout)->field_fmt == V4L2_FIELD_INTERLACED_BT)))
+#define LOAD_3FIELDS(vout) ((INTERLACED_CONTENT(vout)) && \
+ ((vout)->motion_sel != HIGH_MOTION))
+
#define SDC_FG_FB_FORMAT IPU_PIX_FMT_RGB565
struct v4l2_output mxc_outputs[2] = {
@@ -59,7 +65,10 @@ struct v4l2_output mxc_outputs[2] = {
static int video_nr = 16;
static int pending_buffer;
+static int pp_eof;
static spinlock_t g_lock = SPIN_LOCK_UNLOCKED;
+static int last_index_n;
+static int last_index_c;
/* debug counters */
uint32_t g_irq_cnt;
@@ -259,13 +268,18 @@ static irqreturn_t mxc_v4l2out_disp_refresh_irq_handler(int irq, void *dev_id)
}
}
- if (pending_buffer) {
+ if ((pending_buffer) && (pp_eof || vout->ic_bypass)) {
+ pp_eof = 0;
if (vout->ic_bypass) {
ret = ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER,
vout->next_rdy_ipu_buf);
} else {
- ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf);
+ if (LOAD_3FIELDS(vout)) {
+ ret = ipu_select_multi_vdi_buffer(vout->next_rdy_ipu_buf);
+ } else {
+ ret = ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf);
+ }
}
if (ret < 0) {
dev_err(&vout->video_dev->dev,
@@ -341,7 +355,6 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
unsigned long lock_flags = 0;
vout_data *vout = (vout_data *) arg;
-
spin_lock_irqsave(&g_lock, lock_flags);
if ((vout->state == STATE_STREAM_STOPPING)
@@ -359,25 +372,71 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
}
/* Dequeue buffer and pass to IPU */
- index = dequeue_buf(&vout->ready_q);
- if (index == -1) { /* no buffers ready, should never occur */
- dev_err(&vout->video_dev->dev,
- "mxc_v4l2out: timer - no queued buffers ready\n");
- goto exit0;
+ unsigned int aid_field_offset, current_field_offset;
+ if (INTERLACED_CONTENT(vout)) {
+ if (((LOAD_3FIELDS(vout)) && (vout->next_rdy_ipu_buf)) ||
+ ((!LOAD_3FIELDS(vout)) && !(vout->next_rdy_ipu_buf))) {
+ aid_field_offset = vout->bytesperline;
+ current_field_offset = 0;
+ index = last_index_n;
+ } else {
+ aid_field_offset = 0;
+ current_field_offset = vout->bytesperline;
+ index = dequeue_buf(&vout->ready_q);
+ if (index == -1) { /* no buffers ready, should never occur */
+ dev_err(&vout->video_dev->dev,
+ "mxc_v4l2out: timer - no queued buffers ready\n");
+ goto exit0;
+ }
+ g_buf_dq_cnt++;
+ vout->frame_count++;
+ last_index_n = index;
+ }
+ } else {
+ current_field_offset = 0;
+ index = dequeue_buf(&vout->ready_q);
+ if (index == -1) { /* no buffers ready, should never occur */
+ dev_err(&vout->video_dev->dev,
+ "mxc_v4l2out: timer - no queued buffers ready\n");
+ goto exit0;
+ }
+ g_buf_dq_cnt++;
+ vout->frame_count++;
}
- g_buf_dq_cnt++;
- vout->frame_count++;
if (vout->ic_bypass) {
vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
ret = ipu_update_channel_buffer(vout->display_ch, IPU_INPUT_BUFFER,
vout->next_rdy_ipu_buf,
vout->v4l2_bufs[index].m.offset);
} else {
- vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
- ret = ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
- vout->next_rdy_ipu_buf,
- vout->v4l2_bufs[index].m.offset);
+ if (LOAD_3FIELDS(vout)) {
+ int index_n = index;
+ index = last_index_n;
+ int index_p = last_index_c;
+ vout->ipu_buf_p[vout->next_rdy_ipu_buf] = index_p;
+ vout->ipu_buf[vout->next_rdy_ipu_buf] = last_index_c = index;
+ vout->ipu_buf_n[vout->next_rdy_ipu_buf] = last_index_n = index_n;
+ last_index_n = vout->ipu_buf_n[vout->next_rdy_ipu_buf];
+ last_index_c = vout->ipu_buf[vout->next_rdy_ipu_buf];
+ ret = ipu_update_channel_buffer(vout->post_proc_ch,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index].m.offset+current_field_offset);
+ ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_P,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index_p].m.offset+aid_field_offset);
+ ret += ipu_update_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
+ IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index_n].m.offset+aid_field_offset);
+ } else {
+ vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
+ ret = ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
+ vout->next_rdy_ipu_buf,
+ vout->v4l2_bufs[index].m.offset+current_field_offset);
+ }
}
if (ret < 0) {
dev_err(&vout->video_dev->dev,
@@ -409,15 +468,26 @@ static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id)
g_irq_cnt++;
/* Process previous buffer */
- last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
+ if (LOAD_3FIELDS(vout))
+ last_buf = vout->ipu_buf_p[vout->next_done_ipu_buf];
+ else
+ last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
+
if (last_buf != -1) {
- g_buf_output_cnt++;
- vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
- queue_buf(&vout->done_q, last_buf);
+ if ((!INTERLACED_CONTENT(vout)) || (vout->next_done_ipu_buf)) {
+ g_buf_output_cnt++;
+ vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
+ queue_buf(&vout->done_q, last_buf);
+ wake_up_interruptible(&vout->v4l_bufq);
+ }
vout->ipu_buf[vout->next_done_ipu_buf] = -1;
- wake_up_interruptible(&vout->v4l_bufq);
+ if (LOAD_3FIELDS(vout)) {
+ vout->ipu_buf_p[vout->next_done_ipu_buf] = -1;
+ vout->ipu_buf_n[vout->next_done_ipu_buf] = -1;
+ }
vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
}
+ pp_eof = 1;
if (vout->state == STATE_STREAM_STOPPING) {
if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) {
@@ -454,12 +524,88 @@ static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-#ifdef CONFIG_MXC_IPU_V3EX
/*!
- * Start the output stream
+ * Initialize VDI channels
+ *
+ * @param vout structure vout_data *
+ *
+ * @return status 0 Success
+ */
+static int init_VDI_channel(vout_data *vout, ipu_channel_params_t params)
+{
+ struct device *dev = &vout->video_dev->dev;
+
+ if (ipu_init_channel(MEM_VDI_PRP_VF_MEM, &params) != 0) {
+ dev_dbg(dev, "Error initializing VDI current channel\n");
+ return -EINVAL;
+ }
+ if (LOAD_3FIELDS(vout)) {
+ if (ipu_init_channel(MEM_VDI_PRP_VF_MEM_P, &params) != 0) {
+ dev_err(dev, "Error initializing VDI previous channel\n");
+ return -EINVAL;
+ }
+ if (ipu_init_channel(MEM_VDI_PRP_VF_MEM_N, &params) != 0) {
+ dev_err(dev, "Error initializing VDI next channel\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/*!
+ * Initialize VDI channel buffers
+ *
+ * @param vout structure vout_data *
+ *
+ * @return status 0 Success
+ */
+static int init_VDI_in_channel_buffer(vout_data *vout, uint32_t in_pixel_fmt,
+ uint16_t in_width, uint16_t in_height,
+ uint32_t stride,
+ dma_addr_t phyaddr_0, dma_addr_t phyaddr_1,
+ uint32_t u_offset, uint32_t v_offset)
+{
+ struct device *dev = &vout->video_dev->dev;
+
+ if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER,
+ in_pixel_fmt, in_width, in_height, stride,
+ IPU_ROTATE_NONE,
+ vout->v4l2_bufs[vout->ipu_buf[0]].m.offset+vout->bytesperline,
+ vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
+ u_offset, v_offset) != 0) {
+ dev_err(dev, "Error initializing VDI current input buffer\n");
+ return -EINVAL;
+ }
+ if (LOAD_3FIELDS(vout)) {
+ if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM_P,
+ IPU_INPUT_BUFFER,
+ in_pixel_fmt, in_width, in_height,
+ stride, IPU_ROTATE_NONE,
+ vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset,
+ vout->v4l2_bufs[vout->ipu_buf_p[0]].m.offset+vout->bytesperline,
+ u_offset, v_offset) != 0) {
+ dev_err(dev, "Error initializing VDI previous input buffer\n");
+ return -EINVAL;
+ }
+ if (ipu_init_channel_buffer(MEM_VDI_PRP_VF_MEM_N,
+ IPU_INPUT_BUFFER,
+ in_pixel_fmt, in_width, in_height,
+ stride, IPU_ROTATE_NONE,
+ vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset,
+ vout->v4l2_bufs[vout->ipu_buf_n[0]].m.offset+vout->bytesperline,
+ u_offset, v_offset) != 0) {
+ dev_err(dev, "Error initializing VDI next input buffer\n");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+/*!
+ * Initialize VDI path
*
* @param vout structure vout_data *
- * out_width
+ *
* @return status 0 Success
*/
static int init_VDI(ipu_channel_params_t params, vout_data *vout,
@@ -469,6 +615,8 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
{
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.motion_sel = vout->motion_sel;
+ params.mem_prp_vf_mem.field_fmt = vout->field_fmt;
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;
@@ -476,25 +624,23 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
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");
+
+ if (init_VDI_channel(vout, params) != 0) {
+ dev_err(dev, "Error init_VDI_channel 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");
+
+ if (init_VDI_in_channel_buffer(vout,
+ params.mem_prp_vf_mem.in_pixel_fmt,
+ params.mem_prp_vf_mem.in_width,
+ params.mem_prp_vf_mem.in_height,
+ bytes_per_pixel(params.mem_prp_vf_mem.
+ in_pixel_fmt),
+ 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) {
return -EINVAL;
}
@@ -583,10 +729,11 @@ static int init_VDI(ipu_channel_params_t params, vout_data *vout,
}
return 0;
}
-#endif
/*!
- * Start the output stream
+ * Initialize PP path
+ *
+ * @param params structure ipu_channel_params_t
*
* @param vout structure vout_data *
*
@@ -734,17 +881,14 @@ static int mxc_v4l2out_streamon(vout_data * vout)
bool use_direct_adc = false;
mm_segment_t old_fs;
-#ifdef CONFIG_MXC_IPU_V3EX
dev_dbg(dev, "mxc_v4l2out_streamon: field format=%d\n",
vout->field_fmt);
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout)) {
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
-#endif
- {
+ } else {
ipu_request_irq(IPU_IRQ_PP_IN_EOF,
mxc_v4l2out_pp_in_irq_handler,
0, &vout->video_dev->name, vout);
@@ -762,26 +906,46 @@ static int mxc_v4l2out_streamon(vout_data * vout)
return -EINVAL;
}
+ if ((vout->field_fmt == V4L2_FIELD_BOTTOM) || (vout->field_fmt == V4L2_FIELD_TOP)) {
+ dev_err(dev, "4 queued buffers need, not supported yet!\n");
+ return -EINVAL;
+ }
+
pending_buffer = 0;
out_width = vout->crop_current.width;
out_height = vout->crop_current.height;
-
- vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
- vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
- vout->ipu_buf[1] = dequeue_buf(&vout->ready_q);
- vout->frame_count = 2;
+ vout->next_done_ipu_buf = 0;
+ vout->next_rdy_ipu_buf = 1;
+
+ if (!INTERLACED_CONTENT(vout)) {
+ vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
+ vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf[1] = dequeue_buf(&vout->ready_q);
+ vout->frame_count = 2;
+ } else if (!LOAD_3FIELDS(vout)) {
+ vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf[1] = -1;
+ vout->frame_count = 1;
+ last_index_n = vout->ipu_buf[0];
+ } else {
+ vout->ipu_buf_p[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf[0] = vout->ipu_buf_p[0];
+ vout->ipu_buf_n[0] = dequeue_buf(&vout->ready_q);
+ vout->ipu_buf_p[1] = -1;
+ vout->ipu_buf[1] = -1;
+ vout->ipu_buf_n[1] = -1;
+ last_index_c = vout->ipu_buf[0];
+ last_index_n = vout->ipu_buf_n[0];
+ vout->frame_count = 2;
+ }
/* Init Display Channel */
#ifdef CONFIG_FB_MXC_ASYNC_PANEL
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout))
ipu_enable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
- } else
-#endif
- {
+ else
ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
- }
if (vout->cur_disp_output < DISP3) {
mxcfb_set_refresh_mode(fbi, MXCFB_REFRESH_OFF, 0);
@@ -963,25 +1127,18 @@ 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;
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout))
vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
- } else
-#endif
- {
+ else
vout->post_proc_ch = MEM_PP_MEM;
- }
}
/* Init PP */
if (use_direct_adc == false && !vout->ic_bypass) {
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout)) {
vout->post_proc_ch = MEM_VDI_PRP_VF_MEM;
ipu_enable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
- } else
-#endif
- {
+ } else {
vout->post_proc_ch = MEM_PP_MEM;
ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
}
@@ -992,13 +1149,10 @@ static int mxc_v4l2out_streamon(vout_data * vout)
}
memset(&params, 0, sizeof(params));
int rc;
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout)) {
rc = init_VDI(params, vout, dev, fbi, &display_input_ch,
out_width, out_height);
- } else
-#endif
- {
+ } else {
rc = init_PP(params, vout, dev, fbi, &display_input_ch,
out_width, out_height);
}
@@ -1015,12 +1169,19 @@ static int mxc_v4l2out_streamon(vout_data * vout)
if (use_direct_adc == false) {
ipu_enable_channel(vout->display_ch);
if (!vout->ic_bypass) {
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
+ ipu_enable_channel(vout->post_proc_ch);
ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);
-
- ipu_enable_channel(vout->post_proc_ch);
+ if (LOAD_3FIELDS(vout)) {
+ ipu_enable_channel(MEM_VDI_PRP_VF_MEM_P);
+ ipu_enable_channel(MEM_VDI_PRP_VF_MEM_N);
+ ipu_select_multi_vdi_buffer(0);
+ } else if (INTERLACED_CONTENT(vout)) {
+ ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
+ } else {
+ ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
+ ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
+ }
} else {
ipu_update_channel_buffer(vout->display_ch,
IPU_INPUT_BUFFER,
@@ -1028,7 +1189,6 @@ static int mxc_v4l2out_streamon(vout_data * vout)
ipu_update_channel_buffer(vout->display_ch,
IPU_INPUT_BUFFER,
1, vout->v4l2_bufs[vout->ipu_buf[1]].m.offset);
-
ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0);
ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 1);
}
@@ -1040,7 +1200,6 @@ static int mxc_v4l2out_streamon(vout_data * vout)
ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
ipu_enable_channel(vout->post_proc_ch);
}
-
vout->start_jiffies = jiffies;
msleep(1);
@@ -1072,14 +1231,10 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
return 0;
}
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout))
ipu_free_irq(IPU_IRQ_PRP_VF_OUT_EOF, vout);
- } else
-#endif
- {
+ else
ipu_free_irq(IPU_IRQ_PP_IN_EOF, vout);
- }
spin_lock_irqsave(&g_lock, lockflag);
@@ -1090,14 +1245,10 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
}
if (!vout->ic_bypass) {
-#ifdef CONFIG_MXC_IPU_V3EX
- if (vout->field_fmt == V4L2_FIELD_ALTERNATE) {
+ if (INTERLACED_CONTENT(vout))
ipu_disable_irq(IPU_IRQ_PRP_VF_OUT_EOF);
- } else
-#endif
- {
+ else
ipu_disable_irq(IPU_IRQ_PP_IN_EOF);
- }
}
spin_unlock_irqrestore(&g_lock, lockflag);
@@ -1136,10 +1287,8 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
vout->display_buf_size);
}
} else {
- ipu_unlink_channels(MEM_PP_MEM,
- vout->display_ch);
+ ipu_unlink_channels(MEM_PP_MEM, vout->display_ch);
}
-
ipu_disable_channel(MEM_PP_MEM, true);
if (vout->display_ch == ADC_SYS2 ||
@@ -1163,9 +1312,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
ipu_uninit_channel(MEM_PP_MEM);
if (!ipu_can_rotate_in_place(vout->rotate))
ipu_uninit_channel(MEM_ROT_PP_MEM);
- }
-#ifdef CONFIG_MXC_IPU_V3EX
- else if (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM) {
+ } else if (INTERLACED_CONTENT(vout) && (vout->post_proc_ch == MEM_VDI_PRP_VF_MEM)) {
if (!ipu_can_rotate_in_place(vout->rotate)) {
ipu_unlink_channels(MEM_VDI_PRP_VF_MEM,
MEM_ROT_VF_MEM);
@@ -1206,9 +1353,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
ipu_uninit_channel(MEM_VDI_PRP_VF_MEM);
if (!ipu_can_rotate_in_place(vout->rotate))
ipu_uninit_channel(MEM_ROT_VF_MEM);
- }
-#endif
- else { /* ADC Direct */
+ } else { /* ADC Direct */
ipu_disable_channel(MEM_PP_ADC, true);
ipu_uninit_channel(MEM_PP_ADC);
}
@@ -1309,21 +1454,26 @@ static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f)
} else {
bytesperline = f->fmt.pix.bytesperline;
}
+ vout->bytesperline = bytesperline;
/* Based on http://v4l2spec.bytesex.org/spec/x6386.htm#V4L2-FIELD */
- switch (f->fmt.pix.field) {
+ vout->field_fmt = f->fmt.pix.field;
+ switch (vout->field_fmt) {
/* 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:
+ dev_err(&vout->video_dev->dev,
+ "V4L2_FIELD_ALTERNATE field format not supported yet!\n");
+ break;
case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
if (cpu_is_mx51())
- vout->field_fmt = V4L2_FIELD_ALTERNATE;
- break;
+ break;
+ case V4L2_FIELD_INTERLACED_BT:
+ dev_err(&vout->video_dev->dev,
+ "V4L2_FIELD_INTERLACED_BT field format not supported yet!\n");
default:
vout->field_fmt = V4L2_FIELD_NONE;
break;
@@ -1415,6 +1565,9 @@ static int mxc_set_v42lout_control(vout_data * vout, struct v4l2_control *c)
case V4L2_CID_MXC_ROT:
vout->rotate = c->value;
break;
+ case V4L2_CID_MXC_MOTION:
+ vout->motion_sel = c->value;
+ break;
default:
return -EINVAL;
}
@@ -1669,7 +1822,7 @@ mxc_v4l2out_do_ioctl(struct inode *inode, struct file *file,
break;
}
- dev_dbg(&vdev->dev, "VIDIOC_QBUF: %d\n", buf->index);
+ dev_dbg(&vdev->dev, "VIDIOC_QBUF: %d field = %d\n", buf->index, buf->field);
/* mmapped buffers are L1 WB cached,
* so we need to clean them */
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h
index 6d4084053e29..069edde1e850 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.h
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h
@@ -41,6 +41,7 @@
#define MXC_V4L2_OUT_2_SDC 0
#define MXC_V4L2_OUT_2_ADC 1
+
typedef struct {
int list[MAX_FRAME_NUM + 1];
int head;
@@ -87,6 +88,8 @@ typedef struct _vout_data {
s8 next_rdy_ipu_buf;
s8 next_done_ipu_buf;
s8 ipu_buf[2];
+ s8 ipu_buf_p[2];
+ s8 ipu_buf_n[2];
volatile v4lout_state state;
int cur_disp_output;
@@ -126,7 +129,9 @@ typedef struct _vout_data {
/* crop */
struct v4l2_rect crop_bounds[MXC_V4L2_OUT_NUM_OUTPUTS];
struct v4l2_rect crop_current;
+ u32 bytesperline;
enum v4l2_field field_fmt;
+ ipu_motion_sel motion_sel;
} vout_data;
#endif
diff --git a/drivers/mxc/ipu3/ipu_common.c b/drivers/mxc/ipu3/ipu_common.c
index 7fb6b983a58f..c81e3a22ce32 100644
--- a/drivers/mxc/ipu3/ipu_common.c
+++ b/drivers/mxc/ipu3/ipu_common.c
@@ -484,7 +484,13 @@ int32_t ipu_init_channel(ipu_channel_t channel, ipu_channel_params_t *params)
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);
+ _ipu_vdi_init(channel, params);
+ break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ _ipu_vdi_init(channel, params);
+ break;
+ case MEM_VDI_PRP_VF_MEM_N:
+ _ipu_vdi_init(channel, params);
break;
case MEM_ROT_VF_MEM:
ipu_ic_use_count++;
@@ -1036,10 +1042,41 @@ int32_t ipu_select_buffer(ipu_channel_t channel, ipu_buffer_t type,
/*Mark buffer 1 as ready. */
__raw_writel(idma_mask(dma_chan), IPU_CHA_BUF1_RDY(dma_chan));
}
+ if (channel == MEM_VDI_PRP_VF_MEM)
+ _ipu_vdi_toggle_top_field_man();
return 0;
}
EXPORT_SYMBOL(ipu_select_buffer);
+/*!
+ * This function is called to set a channel's buffer as ready.
+ *
+ * @param bufNum Input parameter for which buffer number set to
+ * ready state.
+ *
+ * @return Returns 0 on success or negative error code on fail
+ */
+int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum)
+{
+
+ uint32_t dma_chan = channel_2_dma(MEM_VDI_PRP_VF_MEM, IPU_INPUT_BUFFER);
+ uint32_t mask_bit =
+ idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_P, IPU_INPUT_BUFFER))|
+ idma_mask(dma_chan)|
+ idma_mask(channel_2_dma(MEM_VDI_PRP_VF_MEM_N, IPU_INPUT_BUFFER));
+
+ if (bufNum == 0) {
+ /*Mark buffer 0 as ready. */
+ __raw_writel(mask_bit, IPU_CHA_BUF0_RDY(dma_chan));
+ } else {
+ /*Mark buffer 1 as ready. */
+ __raw_writel(mask_bit, IPU_CHA_BUF1_RDY(dma_chan));
+ }
+ _ipu_vdi_toggle_top_field_man();
+ return 0;
+}
+EXPORT_SYMBOL(ipu_select_multi_vdi_buffer);
+
#define NA -1
static int proc_dest_sel[] =
{ 0, 1, 1, 3, 5, 5, 4, 7, 8, 9, 10, 11, 12, 14, 15, 16,
@@ -1654,7 +1691,6 @@ static irqreturn_t ipu_irq_handler(int irq, void *desc)
dev_err(g_ipu_dev,
"IPU Error - IPU_INT_STAT_%d = 0x%08X\n",
err_reg[i], int_stat);
-
/* Disable interrupts so we only get error once */
int_stat =
__raw_readl(IPU_INT_CTRL(err_reg[i])) & ~int_stat;
diff --git a/drivers/mxc/ipu3/ipu_ic.c b/drivers/mxc/ipu3/ipu_ic.c
index 437df0fa409e..2df9894dbd4e 100644
--- a/drivers/mxc/ipu3/ipu_ic.c
+++ b/drivers/mxc/ipu3/ipu_ic.c
@@ -42,6 +42,34 @@ static bool _calc_resize_coeffs(uint32_t inSize, uint32_t outSize,
uint32_t *resizeCoeff,
uint32_t *downsizeCoeff);
+void _ipu_vdi_set_top_field_man(bool top_field_0)
+{
+ uint32_t reg;
+
+ reg = __raw_readl(VDI_C);
+ if (top_field_0)
+ reg &= ~VDI_C_TOP_FIELD_MAN_1;
+ else
+ reg |= VDI_C_TOP_FIELD_MAN_1;
+ __raw_writel(reg, VDI_C);
+}
+
+void _ipu_vdi_set_motion(ipu_motion_sel motion_sel)
+{
+ uint32_t reg;
+
+ reg = __raw_readl(VDI_C);
+ reg &= ~(VDI_C_MOT_SEL_FULL | VDI_C_MOT_SEL_MED | VDI_C_MOT_SEL_LOW);
+ if (motion_sel == HIGH_MOTION)
+ reg |= VDI_C_MOT_SEL_FULL;
+ else if (motion_sel == MED_MOTION)
+ reg |= VDI_C_MOT_SEL_MED;
+ else
+ reg |= VDI_C_MOT_SEL_LOW;
+
+ __raw_writel(reg, VDI_C);
+}
+
void ic_dump_register(void)
{
printk(KERN_DEBUG "IC_CONF = \t0x%08X\n", __raw_readl(IC_CONF));
@@ -125,7 +153,7 @@ void _ipu_ic_disable_task(ipu_channel_t channel)
__raw_writel(ic_conf, IC_CONF);
}
-void _ipu_vdi_init(ipu_channel_params_t *params)
+void _ipu_vdi_init(ipu_channel_t channel, ipu_channel_params_t *params)
{
uint32_t reg;
uint32_t pixel_fmt;
@@ -140,17 +168,47 @@ void _ipu_vdi_init(ipu_channel_params_t *params)
(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;
+ reg = __raw_readl(VDI_C);
+ reg |= pixel_fmt;
+ switch (channel) {
+ case MEM_VDI_PRP_VF_MEM:
+ reg |= VDI_C_BURST_SIZE2_4;
+ break;
+ case MEM_VDI_PRP_VF_MEM_P:
+ reg |= VDI_C_BURST_SIZE1_4 | VDI_C_VWM1_SET_1 | VDI_C_VWM1_CLR_2;
+ break;
+ case MEM_VDI_PRP_VF_MEM_N:
+ reg |= VDI_C_BURST_SIZE3_4 | VDI_C_VWM3_SET_1 | VDI_C_VWM3_CLR_2;
+ break;
+ default:
+ break;
+ }
__raw_writel(reg, VDI_C);
+ bool top_field_0;
+ /* MED_MOTION and LOW_MOTION algorithm that are using 3 fields
+ * should start presenting using the 2nd field.
+ */
+ if (((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_TB) &&
+ (params->mem_prp_vf_mem.motion_sel != HIGH_MOTION)) ||
+ ((params->mem_prp_vf_mem.field_fmt == V4L2_FIELD_INTERLACED_BT) &&
+ (params->mem_prp_vf_mem.motion_sel == HIGH_MOTION)))
+ top_field_0 = false;
+ else
+ top_field_0 = true;
+
+ /* Buffer selection toggle the value therefore init val is inverted. */
+ _ipu_vdi_set_top_field_man(!top_field_0);
+
+ _ipu_vdi_set_motion(params->mem_prp_vf_mem.motion_sel);
+
reg = __raw_readl(IC_CONF);
reg &= ~IC_CONF_RWS_EN;
__raw_writel(reg, IC_CONF);
}
-_ipu_vdi_uninit(void)
+void _ipu_vdi_uninit(void)
{
- uint32_t reg;
__raw_writel(0, VDI_FSIZE);
__raw_writel(0, VDI_C);
}
@@ -746,3 +804,19 @@ static bool _calc_resize_coeffs(uint32_t inSize, uint32_t outSize,
return true;
}
+
+void _ipu_vdi_toggle_top_field_man()
+{
+ uint32_t reg;
+ uint32_t mask_reg;
+
+ reg = __raw_readl(VDI_C);
+ mask_reg = reg & VDI_C_TOP_FIELD_MAN_1;
+ if (mask_reg == VDI_C_TOP_FIELD_MAN_1)
+ reg &= ~VDI_C_TOP_FIELD_MAN_1;
+ else
+ reg |= VDI_C_TOP_FIELD_MAN_1;
+
+ __raw_writel(reg, VDI_C);
+}
+
diff --git a/drivers/mxc/ipu3/ipu_prv.h b/drivers/mxc/ipu3/ipu_prv.h
index 7fdd27230c68..c1a7ccadfc2d 100644
--- a/drivers/mxc/ipu3/ipu_prv.h
+++ b/drivers/mxc/ipu3/ipu_prv.h
@@ -61,7 +61,7 @@ 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_init(ipu_channel_t channel, 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);
@@ -78,6 +78,7 @@ void _ipu_ic_init_rotate_pp(ipu_channel_params_t *params);
void _ipu_ic_uninit_rotate_pp(void);
int _ipu_ic_idma_init(int dma_chan, uint16_t width, uint16_t height,
int burst_size, ipu_rotate_mode_t rot);
+void _ipu_vdi_toggle_top_field_man();
int _ipu_csi_init(ipu_channel_t channel, uint32_t csi);
void ipu_csi_set_test_generator(bool active, uint32_t r_value,
uint32_t g_value, uint32_t b_value,
diff --git a/drivers/mxc/ipu3/ipu_regs.h b/drivers/mxc/ipu3/ipu_regs.h
index 7769c10e737b..9ddcd351d6b8 100644
--- a/drivers/mxc/ipu3/ipu_regs.h
+++ b/drivers/mxc/ipu3/ipu_regs.h
@@ -608,15 +608,17 @@ enum {
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_LOW = 0x00000004,
VDI_C_MOT_SEL_MED = 0x00000000,
VDI_C_BURST_SIZE1_4 = 0x00000030,
VDI_C_BURST_SIZE2_4 = 0x00000300,
VDI_C_BURST_SIZE3_4 = 0x00003000,
VDI_C_VWM1_SET_1 = 0x00000000,
- VDI_C_VWM1_CLR_2 = 0x00010000,
+ VDI_C_VWM1_CLR_2 = 0x00080000,
VDI_C_VWM3_SET_1 = 0x00000000,
VDI_C_VWM3_CLR_2 = 0x02000000,
+ VDI_C_TOP_FIELD_MAN_1 = 0x40000000,
+ VDI_C_TOP_FIELD_AUTO_1 = 0x80000000,
};
enum di_pins {
diff --git a/include/linux/ipu.h b/include/linux/ipu.h
index 78195375d994..b1d27fb64af2 100644
--- a/include/linux/ipu.h
+++ b/include/linux/ipu.h
@@ -26,6 +26,7 @@
#define __ASM_ARCH_IPU_H__
#include <linux/types.h>
+#include <linux/videodev2.h>
#ifdef __KERNEL__
#include <linux/interrupt.h>
#else
@@ -72,6 +73,15 @@ typedef enum {
IPU_PANEL_TFT,
} ipu_panel_t;
+/*!
+ * Enumeration of VDI MOTION select
+ */
+typedef enum {
+ MED_MOTION = 0,
+ LOW_MOTION = 1,
+ HIGH_MOTION = 2,
+} ipu_motion_sel;
+
/* IPU Pixel format definitions */
/* Four-character-code (FOURCC) */
#define fourcc(a, b, c, d)\
@@ -193,6 +203,9 @@ typedef enum {
MEM_DC_SYNC = CHAN_NONE,
DIRECT_ASYNC0 = CHAN_NONE,
DIRECT_ASYNC1 = CHAN_NONE,
+ MEM_VDI_PRP_VF_MEM_P = CHAN_NONE,
+ MEM_VDI_PRP_VF_MEM = CHAN_NONE,
+ MEM_VDI_PRP_VF_MEM_N = CHAN_NONE,
#else
MEM_ROT_ENC_MEM = _MAKE_CHAN(1, 45, NO_DMA, NO_DMA, 48),
MEM_ROT_VF_MEM = _MAKE_CHAN(2, 46, NO_DMA, NO_DMA, 49),
@@ -357,6 +370,8 @@ typedef union {
uint8_t alpha;
uint32_t key_color;
bool alpha_chan_en;
+ ipu_motion_sel motion_sel;
+ enum v4l2_field field_fmt;
} mem_prp_vf_mem;
struct {
uint32_t temp;
@@ -812,6 +827,7 @@ enum {
STOP,
};
+
/*Define template constants*/
#define ATM_ADDR_RANGE 0x20 /*offset address of DISP */
#define TEMPLATE_BUF_SIZE 0x20 /*size of template */
@@ -860,6 +876,7 @@ int32_t ipu_update_channel_buffer(ipu_channel_t channel, ipu_buffer_t type,
int32_t ipu_select_buffer(ipu_channel_t channel,
ipu_buffer_t type, uint32_t bufNum);
+int32_t ipu_select_multi_vdi_buffer(uint32_t bufNum);
int32_t ipu_link_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch);
int32_t ipu_unlink_channels(ipu_channel_t src_ch, ipu_channel_t dest_ch);
diff --git a/include/linux/mxc_v4l2.h b/include/linux/mxc_v4l2.h
index a94074eb9610..d474aa2f4c86 100644
--- a/include/linux/mxc_v4l2.h
+++ b/include/linux/mxc_v4l2.h
@@ -29,6 +29,7 @@
#define V4L2_CID_MXC_ROT (V4L2_CID_PRIVATE_BASE + 0)
#define V4L2_CID_MXC_FLASH (V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_MXC_VF_ROT (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_MXC_MOTION (V4L2_CID_PRIVATE_BASE + 3)
#define V4L2_MXC_ROTATE_NONE 0
#define V4L2_MXC_ROTATE_VERT_FLIP 1