summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/media/video/mxc/capture/mx27_prphw.c47
-rw-r--r--drivers/media/video/mxc/capture/mx27_prpsw.c10
-rw-r--r--drivers/media/video/mxc/capture/mx27_v4l2_capture.c151
-rw-r--r--drivers/media/video/mxc/capture/mxc_v4l2_capture.h3
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];