aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pxa_camera.c
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2008-04-22 09:37:49 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-24 13:09:45 -0400
commite7c506881973d0c762d660005be54c4095219c59 (patch)
treeb0dea2bf2e0145bc6a39944c44ce185d34df31e5 /drivers/media/video/pxa_camera.c
parenta5462e5be3c1cec7e00e6af9985ff31bf4ef8aa0 (diff)
V4L/DVB (7670): pxa-camera: handle FIFO overruns
FIFO overruns are not seldom on PXA camera interface FIFOs. Handle them by dropping the corrupted frame, waiting for the next start-of-frame, and restarting capture. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pxa_camera.c')
-rw-r--r--drivers/media/video/pxa_camera.c59
1 files changed, 39 insertions, 20 deletions
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index b999bda23c48..1dcfd9109c57 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -118,6 +118,7 @@ struct pxa_camera_dev {
118 unsigned int irq; 118 unsigned int irq;
119 void __iomem *base; 119 void __iomem *base;
120 120
121 int channels;
121 unsigned int dma_chans[3]; 122 unsigned int dma_chans[3];
122 123
123 struct pxacamera_platform_data *pdata; 124 struct pxacamera_platform_data *pdata;
@@ -398,14 +399,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
398 } else { 399 } else {
399 struct pxa_cam_dma *buf_dma; 400 struct pxa_cam_dma *buf_dma;
400 struct pxa_cam_dma *act_dma; 401 struct pxa_cam_dma *act_dma;
401 int channels = 1;
402 int nents; 402 int nents;
403 int i; 403 int i;
404 404
405 if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P) 405 for (i = 0; i < pcdev->channels; i++) {
406 channels = 3;
407
408 for (i = 0; i < channels; i++) {
409 buf_dma = &buf->dmas[i]; 406 buf_dma = &buf->dmas[i];
410 act_dma = &active->dmas[i]; 407 act_dma = &active->dmas[i];
411 nents = buf_dma->sglen; 408 nents = buf_dma->sglen;
@@ -445,20 +442,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
445 442
446 DCSR(pcdev->dma_chans[i]) = DCSR_RUN; 443 DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
447 } 444 }
448#ifdef DEBUG
449 if (CISR & (CISR_IFO_0 | CISR_IFO_1 | CISR_IFO_2)) {
450 dev_warn(pcdev->dev, "FIFO overrun\n");
451 for (i = 0; i < channels; i++)
452 DDADR(pcdev->dma_chans[i]) =
453 pcdev->active->dmas[i].sg_dma;
454
455 CICR0 &= ~CICR0_ENB;
456 CIFR |= CIFR_RESET_F;
457 for (i = 0; i < channels; i++)
458 DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
459 CICR0 |= CICR0_ENB;
460 }
461#endif
462 } 445 }
463 446
464 spin_unlock_irqrestore(&pcdev->lock, flags); 447 spin_unlock_irqrestore(&pcdev->lock, flags);
@@ -522,7 +505,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
522{ 505{
523 struct pxa_buffer *buf; 506 struct pxa_buffer *buf;
524 unsigned long flags; 507 unsigned long flags;
525 unsigned int status; 508 u32 status, camera_status, overrun;
526 struct videobuf_buffer *vb; 509 struct videobuf_buffer *vb;
527 510
528 spin_lock_irqsave(&pcdev->lock, flags); 511 spin_lock_irqsave(&pcdev->lock, flags);
@@ -546,6 +529,25 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
546 goto out; 529 goto out;
547 } 530 }
548 531
532 camera_status = CISR;
533 overrun = CISR_IFO_0;
534 if (pcdev->channels == 3)
535 overrun |= CISR_IFO_1 | CISR_IFO_2;
536 if (camera_status & overrun) {
537 dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
538 /* Stop the Capture Interface */
539 CICR0 &= ~CICR0_ENB;
540 /* Stop DMA */
541 DCSR(channel) = 0;
542 /* Reset the FIFOs */
543 CIFR |= CIFR_RESET_F;
544 /* Enable End-Of-Frame Interrupt */
545 CICR0 &= ~CICR0_EOFM;
546 /* Restart the Capture Interface */
547 CICR0 |= CICR0_ENB;
548 goto out;
549 }
550
549 vb = &pcdev->active->vb; 551 vb = &pcdev->active->vb;
550 buf = container_of(vb, struct pxa_buffer, vb); 552 buf = container_of(vb, struct pxa_buffer, vb);
551 WARN_ON(buf->inwork || list_empty(&vb->queue)); 553 WARN_ON(buf->inwork || list_empty(&vb->queue));
@@ -670,7 +672,21 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
670 672
671 dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status); 673 dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
672 674
675 if (!status)
676 return IRQ_NONE;
677
673 CISR = status; 678 CISR = status;
679
680 if (status & CISR_EOF) {
681 int i;
682 for (i = 0; i < pcdev->channels; i++) {
683 DDADR(pcdev->dma_chans[i]) =
684 pcdev->active->dmas[i].sg_dma;
685 DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
686 }
687 CICR0 |= CICR0_EOFM;
688 }
689
674 return IRQ_HANDLED; 690 return IRQ_HANDLED;
675} 691}
676 692
@@ -785,6 +801,8 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
785 if (!common_flags) 801 if (!common_flags)
786 return -EINVAL; 802 return -EINVAL;
787 803
804 pcdev->channels = 1;
805
788 /* Make choises, based on platform preferences */ 806 /* Make choises, based on platform preferences */
789 if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) && 807 if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
790 (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) { 808 (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
@@ -855,6 +873,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
855 873
856 switch (pixfmt) { 874 switch (pixfmt) {
857 case V4L2_PIX_FMT_YUV422P: 875 case V4L2_PIX_FMT_YUV422P:
876 pcdev->channels = 3;
858 cicr1 |= CICR1_YCBCR_F; 877 cicr1 |= CICR1_YCBCR_F;
859 case V4L2_PIX_FMT_YUYV: 878 case V4L2_PIX_FMT_YUYV:
860 cicr1 |= CICR1_COLOR_SP_VAL(2); 879 cicr1 |= CICR1_COLOR_SP_VAL(2);