Commit 5cf93f1d authored by Kuninori Morimoto's avatar Kuninori Morimoto Committed by Mauro Carvalho Chehab

V4L/DVB (13128): sh_mobile_ceu_camera: add VBP error support

If CEU driver can not receive data from camera,
CETCR has VBP error state.
Then, CEU is stopped and cure operation is needed.
This patch add VBP error cure operation.
Signed-off-by: default avatarKuninori Morimoto <morimoto.kuninori@renesas.com>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b1de7aeb
...@@ -236,26 +236,45 @@ static void free_buffer(struct videobuf_queue *vq, ...@@ -236,26 +236,45 @@ static void free_buffer(struct videobuf_queue *vq,
#define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */ #define CEU_CETCR_MAGIC 0x0317f313 /* acknowledge magical interrupt sources */
#define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */ #define CEU_CETCR_IGRW (1 << 4) /* prohibited register access interrupt bit */
#define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */ #define CEU_CEIER_CPEIE (1 << 0) /* one-frame capture end interrupt */
#define CEU_CEIER_VBP (1 << 20) /* vbp error */
#define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */ #define CEU_CAPCR_CTNCP (1 << 16) /* continuous capture mode (if set) */
#define CEU_CEIER_MASK (CEU_CEIER_CPEIE | CEU_CEIER_VBP)
static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) /*
* return value doesn't reflex the success/failure to queue the new buffer,
* but rather the status of the previous buffer.
*/
static int sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
{ {
struct soc_camera_device *icd = pcdev->icd; struct soc_camera_device *icd = pcdev->icd;
dma_addr_t phys_addr_top, phys_addr_bottom; dma_addr_t phys_addr_top, phys_addr_bottom;
u32 status;
int ret = 0;
/* The hardware is _very_ picky about this sequence. Especially /* The hardware is _very_ picky about this sequence. Especially
* the CEU_CETCR_MAGIC value. It seems like we need to acknowledge * the CEU_CETCR_MAGIC value. It seems like we need to acknowledge
* several not-so-well documented interrupt sources in CETCR. * several not-so-well documented interrupt sources in CETCR.
*/ */
ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_CPEIE); ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) & ~CEU_CEIER_MASK);
ceu_write(pcdev, CETCR, ~ceu_read(pcdev, CETCR) & CEU_CETCR_MAGIC); status = ceu_read(pcdev, CETCR);
ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_CPEIE); ceu_write(pcdev, CETCR, ~status & CEU_CETCR_MAGIC);
ceu_write(pcdev, CEIER, ceu_read(pcdev, CEIER) | CEU_CEIER_MASK);
ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP); ceu_write(pcdev, CAPCR, ceu_read(pcdev, CAPCR) & ~CEU_CAPCR_CTNCP);
ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW); ceu_write(pcdev, CETCR, CEU_CETCR_MAGIC ^ CEU_CETCR_IGRW);
/*
* When a VBP interrupt occurs, a capture end interrupt does not occur
* and the image of that frame is not captured correctly. So, soft reset
* is needed here.
*/
if (status & CEU_CEIER_VBP) {
sh_mobile_ceu_soft_reset(pcdev);
ret = -EIO;
}
if (!pcdev->active) if (!pcdev->active)
return; return ret;
phys_addr_top = videobuf_to_dma_contig(pcdev->active); phys_addr_top = videobuf_to_dma_contig(pcdev->active);
ceu_write(pcdev, CDAYR, phys_addr_top); ceu_write(pcdev, CDAYR, phys_addr_top);
...@@ -281,6 +300,8 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev) ...@@ -281,6 +300,8 @@ static void sh_mobile_ceu_capture(struct sh_mobile_ceu_dev *pcdev)
pcdev->active->state = VIDEOBUF_ACTIVE; pcdev->active->state = VIDEOBUF_ACTIVE;
ceu_write(pcdev, CAPSR, 0x1); /* start capture */ ceu_write(pcdev, CAPSR, 0x1); /* start capture */
return ret;
} }
static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq, static int sh_mobile_ceu_videobuf_prepare(struct videobuf_queue *vq,
...@@ -353,6 +374,11 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq, ...@@ -353,6 +374,11 @@ static void sh_mobile_ceu_videobuf_queue(struct videobuf_queue *vq,
list_add_tail(&vb->queue, &pcdev->capture); list_add_tail(&vb->queue, &pcdev->capture);
if (!pcdev->active) { if (!pcdev->active) {
/*
* Because there were no active buffer at this moment,
* we are not interested in the return value of
* sh_mobile_ceu_capture here.
*/
pcdev->active = vb; pcdev->active = vb;
sh_mobile_ceu_capture(pcdev); sh_mobile_ceu_capture(pcdev);
} }
...@@ -413,9 +439,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data) ...@@ -413,9 +439,8 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
else else
pcdev->active = NULL; pcdev->active = NULL;
sh_mobile_ceu_capture(pcdev); vb->state = (sh_mobile_ceu_capture(pcdev) < 0) ?
VIDEOBUF_ERROR : VIDEOBUF_DONE;
vb->state = VIDEOBUF_DONE;
do_gettimeofday(&vb->ts); do_gettimeofday(&vb->ts);
vb->field_count++; vb->field_count++;
wake_up(&vb->done); wake_up(&vb->done);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment