diff options
author | Quinn Jensen <quinn.jensen@freescale.com> | 2007-10-24 21:27:32 -0600 |
---|---|---|
committer | Quinn Jensen <quinn.jensen@freescale.com> | 2007-10-24 21:27:32 -0600 |
commit | 04d61c58040f259b08e5170d62e2fb49ae8fd19b (patch) | |
tree | e1ab1a95a9f8c27741533ec0fcee94743329763c | |
parent | 9e4175807497c24b82d5866076d8c7c80cdd5a94 (diff) |
Bugzilla 605. Fix tearing when VPU rotates images.2.6.22-mx27ads-2007102503272.6.22-mx27-200710250327
Patch for Bugzilla 605. Fix tearing when VPU rotates images.
A diagonal line appears when the VPU rotates the picture,
at the encode stage. The PRP driver updates the buffer
addresses while the PRP is processing data.
Applies to linux 2.6.22 kernel for MX27 platform.
http://www.bitshrine.org/gpp/linux-2.6.22-mx-Bugzilla-605.-Fix-tearing-when-VPU-rotates.patch
-rw-r--r-- | drivers/media/video/mxc/capture/mx27_prphw.c | 47 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mx27_prpsw.c | 10 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mx27_v4l2_capture.c | 151 | ||||
-rw-r--r-- | drivers/media/video/mxc/capture/mxc_v4l2_capture.h | 3 |
4 files changed, 89 insertions, 122 deletions
diff --git a/drivers/media/video/mxc/capture/mx27_prphw.c b/drivers/media/video/mxc/capture/mx27_prphw.c index 0e8632573cff..ee90012ea5fc 100644 --- a/drivers/media/video/mxc/capture/mx27_prphw.c +++ b/drivers/media/video/mxc/capture/mx27_prphw.c @@ -361,7 +361,6 @@ static const unsigned char coeftab[] = { 1, 20 }; - /*! * @brief Build PrP coefficient table based on average algorithm * @@ -614,7 +613,7 @@ int prp_scale(scale_t * pscale, int din, int dout, int inv, return -1; } } - + if ((num > MAX_TBL * MAX_TBL) || scale(pscale, num, den) < 0) { pr_debug("Scale err, unsupported ratio %d : %d\n", num, den); return -1; @@ -1067,50 +1066,6 @@ static int prphw_ch2_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl) __raw_writel((cfg->ch2_width << 16) | cfg->ch2_height, PRP_CH2_OUT_IMAGE_SIZE); - if (cfg->ch2_pix == PRP_PIX2_YUV420) { - u32 size; - - /* Luminanance band start address */ - __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR); - - if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { - if (!cfg->ch2_ptr2) - __raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR); - else - __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR); - } - - /* Cb and Cr band start address */ - size = cfg->ch2_width * cfg->ch2_height; - __raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR); - __raw_writel(cfg->ch2_ptr + size + (size >> 2), - PRP_DEST_CR_PTR); - - if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { - if (!cfg->ch2_ptr2) { - __raw_writel(cfg->ch2_ptr + size, - PRP_SOURCE_CB_PTR); - __raw_writel(cfg->ch2_ptr + size + (size >> 2), - PRP_SOURCE_CR_PTR); - } else { - __raw_writel(cfg->ch2_ptr2 + size, - PRP_SOURCE_CB_PTR); - __raw_writel(cfg->ch2_ptr2 + size + (size >> 2), - PRP_SOURCE_CR_PTR); - } - } - } else { /* Pixel interleaved YUV422 or YUV444 */ - __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR); - - if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) { - if (!cfg->ch2_ptr2) - __raw_writel(cfg->ch2_ptr, PRP_SOURCE_Y_PTR); - else - __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR); - } - } - *prp_cntl |= PRP_CNTL_CH2B1 | PRP_CNTL_CH2B2; - return 0; } diff --git a/drivers/media/video/mxc/capture/mx27_prpsw.c b/drivers/media/video/mxc/capture/mx27_prpsw.c index b39623f25c1f..b4bfccc745b1 100644 --- a/drivers/media/video/mxc/capture/mx27_prpsw.c +++ b/drivers/media/video/mxc/capture/mx27_prpsw.c @@ -293,12 +293,11 @@ static irqreturn_t prp_isr(int irq, void *dev_id) } else if (cam->capture_on) { if (status & PRP_INTRSTAT_CH2OVF) { prphw_disable(PRP_CHANNEL_2); - prphw_enable(PRP_CHANNEL_2); cam->enc_callback(1, cam); - } - else if (status & - (PRP_INTRSTAT_CH2BUF1 | PRP_INTRSTAT_CH2BUF2)) { - cam->enc_callback(0, cam); + } else if (status & + (PRP_INTRSTAT_CH2BUF1 | PRP_INTRSTAT_CH2BUF2)) { + if (cam->overflow != 1) + cam->enc_callback(0, cam); } } if (cam->overlay_on @@ -1003,7 +1002,6 @@ static int prp_resize_check_ch1(emma_prp_cfg * cfg) } } - pr_debug("Ch1 resize error.\n"); return -1; diff --git a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c index d6d91bda3e98..7d92fbfaa333 100644 --- a/drivers/media/video/mxc/capture/mx27_v4l2_capture.c +++ b/drivers/media/video/mxc/capture/mx27_v4l2_capture.c @@ -44,10 +44,52 @@ static int video_nr = -1; cam_data *g_cam; EXPORT_SYMBOL(g_cam); -static int dq_intr_cnt=0; -static int dq_timeout_cnt=0; -static int empty_wq_cnt=0; +static int dq_intr_cnt = 0; +static int dq_timeout_cnt = 0; +static int empty_wq_cnt = 0; +struct workqueue_struct *v4l2_work; +static void prp_reset(struct work_struct *unused) +{ + struct mxc_v4l_frame *done_frame, *ready_frame, *temp_frame; + + g_cam->ping_pong_csi = 0; + g_cam->enc_enable(g_cam); + if (!list_empty(&g_cam->working_q)) { + done_frame = + list_entry(g_cam->working_q.next, struct mxc_v4l_frame, + queue); + list_del(g_cam->working_q.next); + if (!list_empty(&g_cam->working_q)) { + temp_frame = + list_entry(g_cam->working_q.next, + struct mxc_v4l_frame, queue); + list_del(g_cam->working_q.next); + list_add_tail(&temp_frame->queue, &g_cam->working_q); + g_cam->enc_update_eba(temp_frame->paddress, + &g_cam->ping_pong_csi); + } + list_add_tail(&done_frame->queue, &g_cam->working_q); + g_cam->enc_update_eba(done_frame->paddress, + &g_cam->ping_pong_csi); + pr_debug("prp_reset - working_q\n"); + } else if (list_empty(&g_cam->ready_q)) { + prphw_disable(PRP_CHANNEL_2); + g_cam->skip_frame++; + } else { + ready_frame = + list_entry(g_cam->ready_q.next, struct mxc_v4l_frame, + queue); + list_del(g_cam->ready_q.next); + list_add_tail(&ready_frame->queue, &g_cam->working_q); + g_cam->enc_update_eba(ready_frame->paddress, + &g_cam->ping_pong_csi); + } + g_cam->overflow = 0; + wake_up_interruptible(&g_cam->overflow_queue); +} + +DECLARE_WORK(prp_reset_work, prp_reset); /*! * Free frame buffers * @@ -184,6 +226,7 @@ static int mxc_streamon(cam_data * cam) } cam->ping_pong_csi = 0; + cam->overflow = 0; if (cam->enc_update_eba) { frame = list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue); @@ -684,66 +727,23 @@ static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf) int retval = 0; struct mxc_v4l_frame *frame; - cont: if (!wait_event_interruptible_timeout(cam->enc_queue, cam->enc_counter != 0, 10 * HZ)) { - if( (dq_timeout_cnt & 0x1f) == 0) - printk(KERN_ERR "mxc_v4l_dqueue timeout enc_counter %x\n", + if ((dq_timeout_cnt & 0x1f) == 0) + printk(KERN_ERR + "mxc_v4l_dqueue timeout enc_counter %x\n", cam->enc_counter); dq_timeout_cnt++; - if (cam->overflow == 1) { - cam->enc_enable(cam); - cam->overflow = 0; - if (!list_empty(&cam->ready_q)) { - frame = - list_entry(cam->ready_q.next, - struct mxc_v4l_frame, queue); - list_del(cam->ready_q.next); - list_add_tail(&frame->queue, &cam->working_q); - cam->enc_update_eba(frame->paddress, - &cam->ping_pong_csi); - } - goto cont; - } return -ETIME; } else if (signal_pending(current)) { - if(dq_intr_cnt == 0) - printk(KERN_ERR "mxc_v4l_dqueue() interrupt received %d\n",dq_intr_cnt); - dq_intr_cnt++; - if (cam->overflow == 1) { - cam->enc_enable(cam); - cam->overflow = 0; - if (!list_empty(&cam->ready_q)) { - frame = - list_entry(cam->ready_q.next, - struct mxc_v4l_frame, queue); - list_del(cam->ready_q.next); - list_add_tail(&frame->queue, &cam->working_q); - cam->enc_update_eba(frame->paddress, - &cam->ping_pong_csi); - } - goto cont; - } + if (dq_intr_cnt == 0) + printk(KERN_ERR + "mxc_v4l_dqueue() interrupt received %d\n", + dq_intr_cnt); + dq_intr_cnt++; return -ERESTARTSYS; } - if (cam->overflow == 1) { - cam->enc_enable(cam); - cam->overflow = 0; - if (!list_empty(&cam->ready_q)) { - frame = - list_entry(cam->ready_q.next, struct mxc_v4l_frame, - queue); - list_del(cam->ready_q.next); - list_add_tail(&frame->queue, &cam->working_q); - cam->enc_update_eba(frame->paddress, - &cam->ping_pong_csi); - } - printk(KERN_INFO "mxc_v4l_dqueue - overflow\n"); - - } - - cam->enc_counter--; frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue); @@ -801,9 +801,9 @@ static int mxc_v4l_open(struct inode *inode, struct file *file) cam_data *cam = dev->priv; int err = 0; - dq_intr_cnt = 0; + dq_intr_cnt = 0; dq_timeout_cnt = 0; - empty_wq_cnt = 0; + empty_wq_cnt = 0; if (!cam) { pr_info("Internal error, cam_data not found!\n"); return -ENODEV; @@ -890,6 +890,7 @@ static int mxc_v4l_close(struct inode *inode, struct file *file) err |= mxc_streamoff(cam); cam->capture_on = false; wake_up_interruptible(&cam->enc_queue); + wake_up_interruptible(&cam->overflow_queue); } if (--cam->open_count == 0) { @@ -904,6 +905,7 @@ static int mxc_v4l_close(struct inode *inode, struct file *file) /* capture off */ wake_up_interruptible(&cam->enc_queue); + wake_up_interruptible(&cam->overflow_queue); mxc_free_frames(cam); cam->enc_counter++; prp_exit(cam); @@ -1440,22 +1442,17 @@ mxc_v4l_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_QBUF:{ struct v4l2_buffer *buf = arg; int index = buf->index; - int overflow = 0; pr_debug("VIDIOC_QBUF: %d\n", buf->index); - if (cam->overflow == 1) { - cam->enc_enable(cam); - cam->overflow = 0; - overflow = 1; - printk(KERN_INFO "VIDIOC_QBUF - overflow\n"); - } - + wait_event_interruptible(cam->overflow_queue, + cam->overflow == 0); spin_lock_irqsave(&cam->int_lock, lock_flags); if ((cam->frame[index].buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) { cam->frame[index].buffer.flags |= V4L2_BUF_FLAG_QUEUED; - if ((cam->skip_frame > 0) || (overflow == 1)) { + if (cam->skip_frame > 0) { + prphw_enable(PRP_CHANNEL_2); list_add_tail(&cam->frame[index].queue, &cam->working_q); retval = @@ -1913,15 +1910,22 @@ static void camera_callback(u32 mask, void *dev) return; if (mask == 1) { - cam->overflow = 1; + if (cam->overflow == 0) { + cam->overflow = 1; + queue_work(v4l2_work, &prp_reset_work); + } + return; } if (list_empty(&cam->working_q)) { if (empty_wq_cnt == 0) { - printk(KERN_ERR "camera_callback: working queue empty %d\n",empty_wq_cnt); + printk(KERN_ERR + "camera_callback: working queue empty %d\n", + empty_wq_cnt); } empty_wq_cnt++; - if (list_empty(&cam->ready_q)) { + if (list_empty(&cam->ready_q)) { + prphw_disable(PRP_CHANNEL_2); cam->skip_frame++; } else { ready_frame = @@ -1941,7 +1945,10 @@ static void camera_callback(u32 mask, void *dev) done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE; done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED; + list_del(cam->working_q.next); if (list_empty(&cam->ready_q)) { + if (list_empty(&cam->working_q)) + prphw_disable(PRP_CHANNEL_2); cam->skip_frame++; } else { ready_frame = @@ -1954,7 +1961,6 @@ static void camera_callback(u32 mask, void *dev) } /* Added to the done queue */ - list_del(cam->working_q.next); list_add_tail(&done_frame->queue, &cam->done_q); /* Wake up the queue */ @@ -2000,6 +2006,8 @@ static void init_camera_struct(cam_data * cam) init_waitqueue_head(&cam->enc_queue); init_waitqueue_head(&cam->still_queue); + init_waitqueue_head(&cam->overflow_queue); + cam->overflow = 0; /* setup cropping */ cam->crop_bounds.left = 0; @@ -2158,6 +2166,8 @@ static __init int camera_init(void) init_camera_struct(cam); + v4l2_work = create_singlethread_workqueue("v4l2_emma"); + /* Register the I2C device */ err = platform_device_register(&mxc_v4l2_devices); if (err != 0) { @@ -2201,6 +2211,9 @@ static void __exit camera_exit(void) { pr_debug("unregistering video\n"); + flush_workqueue(v4l2_work); + destroy_workqueue(v4l2_work); + video_unregister_device(g_cam->video_dev); platform_driver_unregister(&mxc_v4l2_driver); diff --git a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h index 69cc5189fd16..733bcc66599a 100644 --- a/drivers/media/video/mxc/capture/mxc_v4l2_capture.h +++ b/drivers/media/video/mxc/capture/mxc_v4l2_capture.h @@ -105,7 +105,8 @@ typedef struct _cam_data { spinlock_t int_lock; struct mxc_v4l_frame frame[FRAME_NUM]; int skip_frame; - int overflow; + wait_queue_head_t overflow_queue; + int overflow; wait_queue_head_t enc_queue; int enc_counter; dma_addr_t rot_enc_bufs[2]; |