summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.c157
-rw-r--r--drivers/media/video/mxc/output/mxc_v4l2_output.h5
-rw-r--r--drivers/video/mxc/mxc_ipuv3_fb.c9
3 files changed, 103 insertions, 68 deletions
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.c b/drivers/media/video/mxc/output/mxc_v4l2_output.c
index 28c7fac90140..a9707d54eac2 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.c
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.c
@@ -245,6 +245,7 @@ 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,
@@ -289,10 +290,9 @@ static int finish_previous_frame(vout_data *vout)
mm_segment_t old_fs;
int ret = 0;
- /* make sure buf[next_done_ipu_buf] showed */
+ /* make sure buf[vout->disp_buf_num] in showing */
while (ipu_check_buffer_busy(vout->display_ch,
- IPU_INPUT_BUFFER, vout->next_done_ipu_buf)) {
- /* wait for display frame finish */
+ IPU_INPUT_BUFFER, vout->disp_buf_num)) {
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->next_done_ipu_buf);
+ vout->disp_buf_num);
}
}
}
@@ -318,9 +318,9 @@ static int show_current_frame(vout_data *vout)
mm_segment_t old_fs;
int ret = 0;
- /* make sure buf[next_rdy_ipu_buf] begin to show */
+ /* make sure buf[vout->disp_buf_num] begin to show */
if (ipu_get_cur_buffer_idx(vout->display_ch, IPU_INPUT_BUFFER)
- != vout->next_rdy_ipu_buf) {
+ != vout->disp_buf_num) {
/* 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 timer_work_func(struct work_struct *work)
+static void icbypass_work_func(struct work_struct *work)
{
vout_data *vout =
- container_of(work, vout_data, timer_work);
+ container_of(work, vout_data, icbypass_work);
int index, ret;
int last_buf;
unsigned long lock_flags = 0;
@@ -346,34 +346,30 @@ static void timer_work_func(struct work_struct *work)
spin_lock_irqsave(&g_lock, lock_flags);
- 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++;
+ 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;
- }
- 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;
+ 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;
last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
if (last_buf != -1) {
@@ -403,6 +399,24 @@ 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;
@@ -436,12 +450,22 @@ 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->timer_work) == 0) {
- dev_err(&vout->video_dev->dev, "work was in queue already!\n ");
+ if (queue_work(vout->v4l_wq, &vout->icbypass_work) == 0) {
+ dev_err(&vout->video_dev->dev,
+ "ic bypass 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);
@@ -523,10 +547,13 @@ static void mxc_v4l2out_timer_handler(unsigned long arg)
goto exit0;
}
- /* Non IC split action */
+ /* Split mode use buf 0 only, no need swith buf */
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)
@@ -628,13 +655,6 @@ 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 */
@@ -676,11 +696,8 @@ 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 {
- /* show to display */
- select_display_buffer(vout, vout->next_done_ipu_buf);
+ disp_buf_num = vout->next_done_ipu_buf;
ret += ipu_select_buffer(vout->display_input_ch, IPU_OUTPUT_BUFFER,
vout->next_done_ipu_buf);
}
@@ -688,6 +705,7 @@ 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);
@@ -697,7 +715,9 @@ 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;
}
- vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
+ /* split mode use buf 0 only, no need switch buf */
+ if (!vout->pp_split)
+ vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
}
} /* end of last_buf != -1 */
@@ -932,6 +952,9 @@ 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;
@@ -1021,6 +1044,12 @@ 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,
@@ -1030,8 +1059,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,
- vout->v4l2_bufs[vout->ipu_buf[0]].m.offset,
- vout->v4l2_bufs[vout->ipu_buf[1]].m.offset,
+ phy_addr0,
+ phy_addr1,
vout->offset.u_offset,
vout->offset.v_offset) != 0) {
dev_err(dev, "Error initializing PP input buffer\n");
@@ -1196,8 +1225,10 @@ 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 = 1;
+ vout->next_rdy_ipu_buf = vout->next_disp_ipu_buf = 1;
+ vout->fb_blank = 0;
vout->pp_split = 0;
ipu_ic_out_max_height_size = 1024;
#ifdef CONFIG_MXC_IPU_V1
@@ -1212,12 +1243,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) &&
@@ -1228,8 +1259,8 @@ static int mxc_v4l2out_streamon(vout_data *vout)
else
vout->pp_split = 3; /*2 vertical stripes*/
} else {
- vout->ipu_buf[1] = dequeue_buf(&vout->ready_q);
- vout->frame_count = 2;
+ vout->ipu_buf[1] = -1;
+ vout->frame_count = 1;
}
} else if (!LOAD_3FIELDS(vout)) {
vout->ipu_buf[0] = dequeue_buf(&vout->ready_q);
@@ -1460,13 +1491,8 @@ 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 if (INTERLACED_CONTENT(vout)) {
- ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
- } else {
+ } 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
@@ -1476,9 +1502,6 @@ 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,
@@ -1492,7 +1515,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->timer_work);
+ queue_work(vout->v4l_wq, &vout->icbypass_work);
}
vout->start_jiffies = jiffies;
@@ -1530,7 +1553,7 @@ static int mxc_v4l2out_streamoff(vout_data *vout)
ipu_free_irq(vout->work_irq, vout);
if (vout->ic_bypass)
- cancel_work_sync(&vout->timer_work);
+ cancel_work_sync(&vout->icbypass_work);
spin_lock_irqsave(&g_lock, lockflag);
@@ -1891,7 +1914,7 @@ static int mxc_v4l2out_open(struct file *file)
goto oops;
}
- INIT_WORK(&vout->timer_work, timer_work_func);
+ INIT_WORK(&vout->icbypass_work, icbypass_work_func);
}
file->private_data = dev;
diff --git a/drivers/media/video/mxc/output/mxc_v4l2_output.h b/drivers/media/video/mxc/output/mxc_v4l2_output.h
index 096dc3b17a06..c26194f5ff90 100644
--- a/drivers/media/video/mxc/output/mxc_v4l2_output.h
+++ b/drivers/media/video/mxc/output/mxc_v4l2_output.h
@@ -79,7 +79,9 @@ typedef struct _vout_data {
struct timer_list output_timer;
struct workqueue_struct *v4l_wq;
- struct work_struct timer_work;
+ struct work_struct icbypass_work;
+ int disp_buf_num;
+ int fb_blank;
unsigned long start_jiffies;
u32 frame_count;
@@ -88,6 +90,7 @@ typedef struct _vout_data {
s8 next_rdy_ipu_buf;
s8 next_done_ipu_buf;
+ s8 next_disp_ipu_buf;
s8 ipu_buf[2];
s8 ipu_buf_p[2];
s8 ipu_buf_n[2];
diff --git a/drivers/video/mxc/mxc_ipuv3_fb.c b/drivers/video/mxc/mxc_ipuv3_fb.c
index 23e3047cc749..50c8b0110485 100644
--- a/drivers/video/mxc/mxc_ipuv3_fb.c
+++ b/drivers/video/mxc/mxc_ipuv3_fb.c
@@ -1100,6 +1100,15 @@ static int mxcfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
return -EFAULT;
break;
}
+ case MXCFB_GET_FB_BLANK:
+ {
+ struct mxcfb_info *mxc_fbi =
+ (struct mxcfb_info *)fbi->par;
+
+ if (put_user(mxc_fbi->cur_blank, argp))
+ return -EFAULT;
+ break;
+ }
default:
retval = -EINVAL;
}