summaryrefslogtreecommitdiff
path: root/drivers/media/video/mxc/output/mxc_v4l2_output.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/mxc/output/mxc_v4l2_output.c')
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.c157
1 files changed, 67 insertions, 90 deletions
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index b7bbfed73019..0567298dcb7e 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -245,7 +245,6 @@ static int select_display_buffer(vout_data *vout, int next_buf)
{
int ret = 0;
- vout->disp_buf_num = next_buf;
if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
!= next_buf)
ret = ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER,
@@ -290,9 +289,10 @@ static int finish_previous_frame(vout_data *vout)
mm_segment_t old_fs;
int ret = 0;
- /* make sure buf[vout->disp_buf_num] in showing */
+ /* make sure buf[next_done_ipu_buf] showed */
while (ipu_check_buffer_busy(vout->display_ch,
- IPU_INPUT_BUFFER, vout->disp_buf_num)) {
+ IPU_INPUT_BUFFER, vout->next_done_ipu_buf)) {
+ /* wait for display frame finish */
if (fbi->fbops->fb_ioctl) {
old_fs = get_fs();
set_fs(KERNEL_DS);
@@ -303,7 +303,7 @@ static int finish_previous_frame(vout_data *vout)
if (ret < 0) {
/* ic_bypass need clear display buffer ready for next update*/
ipu_clear_buffer_ready(vout->display_ch, IPU_INPUT_BUFFER,
- vout->disp_buf_num);
+ vout->next_done_ipu_buf);
}
}
}
@@ -318,9 +318,9 @@ static int show_current_frame(vout_data *vout)
mm_segment_t old_fs;
int ret = 0;
- /* make sure buf[vout->disp_buf_num] begin to show */
+ /* make sure buf[next_rdy_ipu_buf] begin to show */
if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
- != vout->disp_buf_num) {
+ != vout->next_rdy_ipu_buf) {
/* wait for display frame finish */
if (fbi->fbops->fb_ioctl) {
old_fs = get_fs();
@@ -334,10 +334,10 @@ static int show_current_frame(vout_data *vout)
return ret;
}
-static void icbypass_work_func(struct work_struct *work)
+static void timer_work_func(struct work_struct *work)
{
vout_data *vout =
- container_of(work, vout_data, icbypass_work);
+ container_of(work, vout_data, timer_work);
int index, ret;
int last_buf;
unsigned long lock_flags = 0;
@@ -346,30 +346,34 @@ static void icbypass_work_func(struct work_struct *work)
spin_lock_irqsave(&g_lock, lock_flags);
- 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 exit;
- }
- g_buf_dq_cnt++;
- vout->frame_count++;
+ if (g_buf_output_cnt == 0) {
+ ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 1);
+ } else {
+ 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 exit;
+ }
+ g_buf_dq_cnt++;
+ vout->frame_count++;
- 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);
- ret += select_display_buffer(vout, vout->next_rdy_ipu_buf);
- if (ret < 0) {
- dev_err(&vout->video_dev->dev,
- "unable to update buffer %d address rc=%d\n",
- vout->next_rdy_ipu_buf, ret);
- goto exit;
+ 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);
+ ret += select_display_buffer(vout, vout->next_rdy_ipu_buf);
+ if (ret < 0) {
+ dev_err(&vout->video_dev->dev,
+ "unable to update buffer %d address rc=%d\n",
+ vout->next_rdy_ipu_buf, ret);
+ goto exit;
+ }
+ spin_unlock_irqrestore(&g_lock, lock_flags);
+ show_current_frame(vout);
+ spin_lock_irqsave(&g_lock, lock_flags);
+ vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
}
- spin_unlock_irqrestore(&g_lock, lock_flags);
- show_current_frame(vout);
- spin_lock_irqsave(&g_lock, lock_flags);
- vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
if (last_buf != -1) {
@@ -399,24 +403,6 @@ exit:
spin_unlock_irqrestore(&g_lock, lock_flags);
}
-static int get_cur_fb_blank(vout_data *vout)
-{
- struct fb_info *fbi =
- registered_fb[vout->output_fb_num[vout->cur_disp_output]];
- mm_segment_t old_fs;
- int ret = 0;
-
- if (fbi->fbops->fb_ioctl) {
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = fbi->fbops->fb_ioctl(fbi, MXCFB_GET_FB_BLANK,
- (unsigned int)(&vout->fb_blank));
- set_fs(old_fs);
- }
-
- return ret;
-}
-
static void mxc_v4l2out_timer_handler(unsigned long arg)
{
int index, ret;
@@ -450,22 +436,12 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
/* Handle ic bypass mode in work queue */
if (vout->ic_bypass) {
- if (queue_work(vout->v4l_wq, &vout->icbypass_work) == 0) {
- dev_err(&vout->video_dev->dev,
- "ic bypass work was in queue already!\n ");
+ if (queue_work(vout->v4l_wq, &vout->timer_work) == 0) {
+ dev_err(&vout->video_dev->dev, "work was in queue already!\n ");
vout->state = STATE_STREAM_PAUSED;
}
goto exit0;
- } else if (!vout->fb_blank &&
- (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
- == vout->next_disp_ipu_buf)) {
- dev_dbg(&vout->video_dev->dev, "IPU disp busy\n");
- get_cur_fb_blank(vout);
- index = peek_next_buf(&vout->ready_q);
- setup_next_buf_timer(vout, index);
- goto exit0;
}
- vout->fb_blank = 0;
/* Dequeue buffer and pass to IPU */
index = dequeue_buf(&vout->ready_q);
@@ -547,13 +523,10 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
goto exit0;
}
- /* Split mode use buf 0 only, no need swith buf */
+ /* Non IC split action */
if (!vout->pp_split)
vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
- /* Always assume display in double buffers */
- vout->next_disp_ipu_buf = !vout->next_disp_ipu_buf;
-
/* Setup timer for next buffer */
index = peek_next_buf(&vout->ready_q);
if (index != -1)
@@ -655,6 +628,13 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
if (ret < 0)
dev_err(&vout->video_dev->dev,
"unable to set IPU buffer ready\n");
+ vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
+
+ } else {/* last stripe is done, run display refresh */
+ select_display_buffer(vout, disp_buf_num);
+ vout->ipu_buf[vout->next_done_ipu_buf] = -1;
+ vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
}
/* offset for next buffer's EBA */
@@ -696,8 +676,11 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
/* next stripe_buffer index 0..7 */
vout->pp_split_buf_num = (vout->pp_split_buf_num + vout->pp_split) & 0x7;
+
+
} else {
- disp_buf_num = vout->next_done_ipu_buf;
+ /* show to display */
+ select_display_buffer(vout, vout->next_done_ipu_buf);
ret += ipu_select_buffer(vout->display_input_ch, IPU_OUTPUT_BUFFER,
vout->next_done_ipu_buf);
}
@@ -705,7 +688,6 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
/* release buffer. For split mode: if second stripe is done */
release_buffer = vout->pp_split ? (!(vout->pp_split_buf_num & 0x3)) : 1;
if (release_buffer) {
- select_display_buffer(vout, disp_buf_num);
g_buf_output_cnt++;
vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
queue_buf(&vout->done_q, last_buf);
@@ -715,9 +697,7 @@ static irqreturn_t mxc_v4l2out_work_irq_handler(int irq, void *dev_id)
vout->ipu_buf_p[vout->next_done_ipu_buf] = -1;
vout->ipu_buf_n[vout->next_done_ipu_buf] = -1;
}
- /* split mode use buf 0 only, no need switch buf */
- if (!vout->pp_split)
- vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
}
} /* end of last_buf != -1 */
@@ -950,9 +930,6 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
u32 eba_offset;
u16 x_pos;
u16 y_pos;
- dma_addr_t phy_addr0;
- dma_addr_t phy_addr1;
-
eba_offset = 0;
x_pos = 0;
y_pos = 0;
@@ -1042,12 +1019,6 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
return -EINVAL;
}
- /* always enable double buffer */
- phy_addr0 = vout->v4l2_bufs[vout->ipu_buf[0]].m.offset;
- if (vout->ipu_buf[1] == -1)
- phy_addr1 = phy_addr0;
- else
- phy_addr1 = vout->v4l2_bufs[vout->ipu_buf[1]].m.offset;
if (ipu_init_channel_buffer(vout->post_proc_ch,
IPU_INPUT_BUFFER,
params->mem_pp_mem.in_pixel_fmt,
@@ -1057,8 +1028,8 @@ static int init_PP(ipu_channel_params_t *params, vout_data *vout,
bytes_per_pixel(params->mem_pp_mem.
in_pixel_fmt),
IPU_ROTATE_NONE,
- phy_addr0,
- phy_addr1,
+ 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");
@@ -1223,10 +1194,8 @@ static int mxc_v4l2out_streamon(vout_data * vout)
g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0;
out_width = vout->crop_current.width;
out_height = vout->crop_current.height;
- vout->disp_buf_num = 0;
vout->next_done_ipu_buf = 0;
- vout->next_rdy_ipu_buf = vout->next_disp_ipu_buf = 1;
- vout->fb_blank = 0;
+ vout->next_rdy_ipu_buf = 1;
vout->pp_split = 0;
ipu_ic_out_max_height_size = 1024;
#ifdef CONFIG_MXC_IPU_V1
@@ -1241,12 +1210,12 @@ static int mxc_v4l2out_streamon(vout_data * vout)
(out_height > ipu_ic_out_max_height_size))
vout->pp_split = 4;
if (!INTERLACED_CONTENT(vout)) {
+ vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
/* split IC by two stripes, the by pass is impossible*/
if ((out_width != vout->v2f.fmt.pix.width ||
out_height != vout->v2f.fmt.pix.height) &&
vout->pp_split) {
- vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
vout->ipu_buf[1] = vout->ipu_buf[0];
vout->frame_count = 1;
if ((out_width > ipu_ic_out_max_width_size) &&
@@ -1257,8 +1226,8 @@ static int mxc_v4l2out_streamon(vout_data * vout)
else
vout->pp_split = 3; /*2 vertical stripes*/
} else {
- vout->ipu_buf[1] = -1;
- vout->frame_count = 1;
+ 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);
@@ -1492,8 +1461,13 @@ static int mxc_v4l2out_streamon(vout_data * 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
+ } 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);
+ if (!vout->pp_split)
+ ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
+ }
ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);
#ifdef CONFIG_MXC_IPU_V1
@@ -1503,6 +1477,9 @@ static int mxc_v4l2out_streamon(vout_data * vout)
ipu_update_channel_buffer(vout->display_ch,
IPU_INPUT_BUFFER,
0, vout->v4l2_bufs[vout->ipu_buf[0]].m.offset);
+ ipu_update_channel_buffer(vout->display_ch,
+ IPU_INPUT_BUFFER,
+ 1, vout->v4l2_bufs[vout->ipu_buf[1]].m.offset);
if (vout->offset.u_offset || vout->offset.v_offset)
/* only update u/v offset */
ipu_update_channel_offset(vout->display_ch,
@@ -1516,7 +1493,7 @@ static int mxc_v4l2out_streamon(vout_data * vout)
0,
0);
ipu_select_buffer(vout->display_ch, IPU_INPUT_BUFFER, 0);
- queue_work(vout->v4l_wq, &vout->icbypass_work);
+ queue_work(vout->v4l_wq, &vout->timer_work);
}
vout->start_jiffies = jiffies;
@@ -1554,7 +1531,7 @@ static int mxc_v4l2out_streamoff(vout_data * vout)
ipu_free_irq(vout->work_irq, vout);
if (vout->ic_bypass)
- cancel_work_sync(&vout->icbypass_work);
+ cancel_work_sync(&vout->timer_work);
spin_lock_irqsave(&g_lock, lockflag);
@@ -1915,7 +1892,7 @@ static int mxc_v4l2out_open(struct file *file)
goto oops;
}
- INIT_WORK(&vout->icbypass_work, icbypass_work_func);
+ INIT_WORK(&vout->timer_work, timer_work_func);
}
file->private_data = dev;