Skip to content

Commit

Permalink
V4L/DVB (7670): pxa-camera: handle FIFO overruns
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Guennadi Liakhovetski authored and Mauro Carvalho Chehab committed Apr 24, 2008
1 parent a5462e5 commit e7c5068
Showing 1 changed file with 39 additions and 20 deletions.
59 changes: 39 additions & 20 deletions drivers/media/video/pxa_camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct pxa_camera_dev {
unsigned int irq;
void __iomem *base;

int channels;
unsigned int dma_chans[3];

struct pxacamera_platform_data *pdata;
Expand Down Expand Up @@ -398,14 +399,10 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,
} else {
struct pxa_cam_dma *buf_dma;
struct pxa_cam_dma *act_dma;
int channels = 1;
int nents;
int i;

if (buf->fmt->fourcc == V4L2_PIX_FMT_YUV422P)
channels = 3;

for (i = 0; i < channels; i++) {
for (i = 0; i < pcdev->channels; i++) {
buf_dma = &buf->dmas[i];
act_dma = &active->dmas[i];
nents = buf_dma->sglen;
Expand Down Expand Up @@ -445,20 +442,6 @@ static void pxa_videobuf_queue(struct videobuf_queue *vq,

DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
}
#ifdef DEBUG
if (CISR & (CISR_IFO_0 | CISR_IFO_1 | CISR_IFO_2)) {
dev_warn(pcdev->dev, "FIFO overrun\n");
for (i = 0; i < channels; i++)
DDADR(pcdev->dma_chans[i]) =
pcdev->active->dmas[i].sg_dma;

CICR0 &= ~CICR0_ENB;
CIFR |= CIFR_RESET_F;
for (i = 0; i < channels; i++)
DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
CICR0 |= CICR0_ENB;
}
#endif
}

spin_unlock_irqrestore(&pcdev->lock, flags);
Expand Down Expand Up @@ -522,7 +505,7 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
{
struct pxa_buffer *buf;
unsigned long flags;
unsigned int status;
u32 status, camera_status, overrun;
struct videobuf_buffer *vb;

spin_lock_irqsave(&pcdev->lock, flags);
Expand All @@ -546,6 +529,25 @@ static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
goto out;
}

camera_status = CISR;
overrun = CISR_IFO_0;
if (pcdev->channels == 3)
overrun |= CISR_IFO_1 | CISR_IFO_2;
if (camera_status & overrun) {
dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
/* Stop the Capture Interface */
CICR0 &= ~CICR0_ENB;
/* Stop DMA */
DCSR(channel) = 0;
/* Reset the FIFOs */
CIFR |= CIFR_RESET_F;
/* Enable End-Of-Frame Interrupt */
CICR0 &= ~CICR0_EOFM;
/* Restart the Capture Interface */
CICR0 |= CICR0_ENB;
goto out;
}

vb = &pcdev->active->vb;
buf = container_of(vb, struct pxa_buffer, vb);
WARN_ON(buf->inwork || list_empty(&vb->queue));
Expand Down Expand Up @@ -670,7 +672,21 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)

dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);

if (!status)
return IRQ_NONE;

CISR = status;

if (status & CISR_EOF) {
int i;
for (i = 0; i < pcdev->channels; i++) {
DDADR(pcdev->dma_chans[i]) =
pcdev->active->dmas[i].sg_dma;
DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
}
CICR0 |= CICR0_EOFM;
}

return IRQ_HANDLED;
}

Expand Down Expand Up @@ -785,6 +801,8 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
if (!common_flags)
return -EINVAL;

pcdev->channels = 1;

/* Make choises, based on platform preferences */
if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
(common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
Expand Down Expand Up @@ -855,6 +873,7 @@ static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)

switch (pixfmt) {
case V4L2_PIX_FMT_YUV422P:
pcdev->channels = 3;
cicr1 |= CICR1_YCBCR_F;
case V4L2_PIX_FMT_YUYV:
cicr1 |= CICR1_COLOR_SP_VAL(2);
Expand Down

0 comments on commit e7c5068

Please sign in to comment.