diff options
author | Guennadi Liakhovetski <g.liakhovetski@gmx.de> | 2008-04-22 09:37:49 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:45 -0400 |
commit | e7c506881973d0c762d660005be54c4095219c59 (patch) | |
tree | b0dea2bf2e0145bc6a39944c44ce185d34df31e5 /drivers/media/video/pxa_camera.c | |
parent | a5462e5be3c1cec7e00e6af9985ff31bf4ef8aa0 (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.c | 59 |
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); |