Commit cbc4f3a2 authored by Jonathan Corbet's avatar Jonathan Corbet Committed by Mauro Carvalho Chehab

[media] marvell-cam: Working s/g DMA

The core Marvell camera driver can now do scatter/gather DMA on controllers
which support that functionality.
Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 60c07322
...@@ -3,6 +3,8 @@ config VIDEO_CAFE_CCIC ...@@ -3,6 +3,8 @@ config VIDEO_CAFE_CCIC
depends on PCI && I2C && VIDEO_V4L2 depends on PCI && I2C && VIDEO_V4L2
select VIDEO_OV7670 select VIDEO_OV7670
select VIDEOBUF2_VMALLOC select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_DMA_SG
---help--- ---help---
This is a video4linux2 driver for the Marvell 88ALP01 integrated This is a video4linux2 driver for the Marvell 88ALP01 integrated
CMOS camera controller. This is the controller found on first- CMOS camera controller. This is the controller found on first-
...@@ -15,6 +17,7 @@ config VIDEO_MMP_CAMERA ...@@ -15,6 +17,7 @@ config VIDEO_MMP_CAMERA
select I2C_GPIO select I2C_GPIO
select VIDEOBUF2_VMALLOC select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_CONTIG
select VIDEOBUF2_DMA_SG
---help--- ---help---
This is a Video4Linux2 driver for the integrated camera This is a Video4Linux2 driver for the integrated camera
controller found on Marvell Armada 610 application controller found on Marvell Armada 610 application
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <media/ov7670.h> #include <media/ov7670.h>
#include <media/videobuf2-vmalloc.h> #include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h> #include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
#include "mcam-core.h" #include "mcam-core.h"
...@@ -106,6 +107,7 @@ MODULE_PARM_DESC(buffer_mode, ...@@ -106,6 +107,7 @@ MODULE_PARM_DESC(buffer_mode,
#define CF_DMA_ACTIVE 3 /* A frame is incoming */ #define CF_DMA_ACTIVE 3 /* A frame is incoming */
#define CF_CONFIG_NEEDED 4 /* Must configure hardware */ #define CF_CONFIG_NEEDED 4 /* Must configure hardware */
#define CF_SINGLE_BUFFER 5 /* Running with a single buffer */ #define CF_SINGLE_BUFFER 5 /* Running with a single buffer */
#define CF_SG_RESTART 6 /* SG restart needed */
#define sensor_call(cam, o, f, args...) \ #define sensor_call(cam, o, f, args...) \
v4l2_subdev_call(cam->sensor, o, f, ##args) v4l2_subdev_call(cam->sensor, o, f, ##args)
...@@ -179,6 +181,17 @@ static void mcam_set_config_needed(struct mcam_camera *cam, int needed) ...@@ -179,6 +181,17 @@ static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
clear_bit(CF_CONFIG_NEEDED, &cam->flags); clear_bit(CF_CONFIG_NEEDED, &cam->flags);
} }
/*
* The two-word DMA descriptor format used by the Armada 610 and like. There
* Is a three-word format as well (set C1_DESC_3WORD) where the third
* word is a pointer to the next descriptor, but we don't use it. Two-word
* descriptors have to be contiguous in memory.
*/
struct mcam_dma_desc {
u32 dma_addr;
u32 segment_len;
};
/* /*
* Our buffer type for working with videobuf2. Note that the vb2 * Our buffer type for working with videobuf2. Note that the vb2
* developers have decreed that struct vb2_buffer must be at the * developers have decreed that struct vb2_buffer must be at the
...@@ -187,6 +200,9 @@ static void mcam_set_config_needed(struct mcam_camera *cam, int needed) ...@@ -187,6 +200,9 @@ static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
struct mcam_vb_buffer { struct mcam_vb_buffer {
struct vb2_buffer vb_buf; struct vb2_buffer vb_buf;
struct list_head queue; struct list_head queue;
struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */
dma_addr_t dma_desc_pa; /* Descriptor physical address */
int dma_desc_nent; /* Number of mapped descriptors */
}; };
static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb) static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
...@@ -268,6 +284,9 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame) ...@@ -268,6 +284,9 @@ static void mcam_set_contig_buffer(struct mcam_camera *cam, int frame)
clear_bit(CF_SINGLE_BUFFER, &cam->flags); clear_bit(CF_SINGLE_BUFFER, &cam->flags);
} }
/*
* Initial B_DMA_contig setup.
*/
static void mcam_ctlr_dma_contig(struct mcam_camera *cam) static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
{ {
mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS); mcam_reg_set_bit(cam, REG_CTRL1, C1_TWOBUFS);
...@@ -277,14 +296,38 @@ static void mcam_ctlr_dma_contig(struct mcam_camera *cam) ...@@ -277,14 +296,38 @@ static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
} }
static void mcam_ctlr_dma(struct mcam_camera *cam) /*
* Set up the next buffer for S/G I/O; caller should be sure that
* the controller is stopped and a buffer is available.
*/
static void mcam_sg_next_buffer(struct mcam_camera *cam)
{ {
if (cam->buffer_mode == B_DMA_contig) struct mcam_vb_buffer *buf;
mcam_ctlr_dma_contig(cam);
else buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue);
mcam_ctlr_dma_vmalloc(cam); list_del_init(&buf->queue);
mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa);
mcam_reg_write(cam, REG_DESC_LEN_Y,
buf->dma_desc_nent*sizeof(struct mcam_dma_desc));
mcam_reg_write(cam, REG_DESC_LEN_U, 0);
mcam_reg_write(cam, REG_DESC_LEN_V, 0);
cam->vb_bufs[0] = buf;
} }
/*
* Initial B_DMA_sg setup
*/
static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
{
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_3WORD);
mcam_sg_next_buffer(cam);
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
cam->nbufs = 3;
}
/*
* Image format setup, independent of DMA scheme.
*/
static void mcam_ctlr_image(struct mcam_camera *cam) static void mcam_ctlr_image(struct mcam_camera *cam)
{ {
int imgsz; int imgsz;
...@@ -341,9 +384,20 @@ static int mcam_ctlr_configure(struct mcam_camera *cam) ...@@ -341,9 +384,20 @@ static int mcam_ctlr_configure(struct mcam_camera *cam)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
mcam_ctlr_dma(cam); switch (cam->buffer_mode) {
case B_vmalloc:
mcam_ctlr_dma_vmalloc(cam);
break;
case B_DMA_contig:
mcam_ctlr_dma_contig(cam);
break;
case B_DMA_sg:
mcam_ctlr_dma_sg(cam);
break;
}
mcam_ctlr_image(cam); mcam_ctlr_image(cam);
mcam_set_config_needed(cam, 0); mcam_set_config_needed(cam, 0);
clear_bit(CF_SG_RESTART, &cam->flags);
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
return 0; return 0;
} }
...@@ -379,6 +433,19 @@ static void mcam_ctlr_stop(struct mcam_camera *cam) ...@@ -379,6 +433,19 @@ static void mcam_ctlr_stop(struct mcam_camera *cam)
mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
} }
/*
* Scatter/gather mode requires stopping the controller between
* frames so we can put in a new DMA descriptor array. If no new
* buffer exists at frame completion, the controller is left stopped;
* this function is charged with gettig things going again.
*/
static void mcam_sg_restart(struct mcam_camera *cam)
{
mcam_ctlr_dma_sg(cam);
mcam_ctlr_start(cam);
clear_bit(CF_SG_RESTART, &cam->flags);
}
static void mcam_ctlr_init(struct mcam_camera *cam) static void mcam_ctlr_init(struct mcam_camera *cam)
{ {
unsigned long flags; unsigned long flags;
...@@ -416,14 +483,15 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam) ...@@ -416,14 +483,15 @@ static void mcam_ctlr_stop_dma(struct mcam_camera *cam)
* interrupt, then wait until no DMA is active. * interrupt, then wait until no DMA is active.
*/ */
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
clear_bit(CF_SG_RESTART, &cam->flags);
mcam_ctlr_stop(cam); mcam_ctlr_stop(cam);
cam->state = S_IDLE;
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
msleep(10); msleep(40);
if (test_bit(CF_DMA_ACTIVE, &cam->flags)) if (test_bit(CF_DMA_ACTIVE, &cam->flags))
cam_err(cam, "Timeout waiting for DMA to end\n"); cam_err(cam, "Timeout waiting for DMA to end\n");
/* This would be bad news - what now? */ /* This would be bad news - what now? */
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
cam->state = S_IDLE;
mcam_ctlr_irq_disable(cam); mcam_ctlr_irq_disable(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
} }
...@@ -540,9 +608,8 @@ static int mcam_cam_configure(struct mcam_camera *cam) ...@@ -540,9 +608,8 @@ static int mcam_cam_configure(struct mcam_camera *cam)
* DMA buffer management. These functions need s_mutex held. * DMA buffer management. These functions need s_mutex held.
*/ */
/* FIXME: this is inefficient as hell, since dma_alloc_coherent just /*
* does a get_free_pages() call, and we waste a good chunk of an orderN * Allocate in-kernel DMA buffers for vmalloc mode.
* allocation. Should try to allocate the whole set in one chunk.
*/ */
static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime) static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
{ {
...@@ -650,24 +717,56 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs, ...@@ -650,24 +717,56 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
void *alloc_ctxs[]) void *alloc_ctxs[])
{ {
struct mcam_camera *cam = vb2_get_drv_priv(vq); struct mcam_camera *cam = vb2_get_drv_priv(vq);
int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
sizes[0] = cam->pix_format.sizeimage; sizes[0] = cam->pix_format.sizeimage;
*num_planes = 1; /* Someday we have to support planar formats... */ *num_planes = 1; /* Someday we have to support planar formats... */
if (*nbufs < 3 || *nbufs > 32) if (*nbufs < minbufs)
*nbufs = 3; /* semi-arbitrary numbers */ *nbufs = minbufs;
if (cam->buffer_mode == B_DMA_contig) if (cam->buffer_mode == B_DMA_contig)
alloc_ctxs[0] = cam->vb_alloc_ctx; alloc_ctxs[0] = cam->vb_alloc_ctx;
return 0; return 0;
} }
static int mcam_vb_buf_init(struct vb2_buffer *vb) /* DMA_sg only */
static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
{ {
struct mcam_vb_buffer *mvb = vb_to_mvb(vb); struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
INIT_LIST_HEAD(&mvb->queue); mvb->dma_desc = dma_alloc_coherent(cam->dev,
ndesc * sizeof(struct mcam_dma_desc),
&mvb->dma_desc_pa, GFP_KERNEL);
if (mvb->dma_desc == NULL) {
cam_err(cam, "Unable to get DMA descriptor array\n");
return -ENOMEM;
}
return 0; return 0;
} }
static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
{
struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
struct mcam_dma_desc *desc = mvb->dma_desc;
struct scatterlist *sg;
int i;
mvb->dma_desc_nent = dma_map_sg(cam->dev, sgd->sglist, sgd->num_pages,
DMA_FROM_DEVICE);
if (mvb->dma_desc_nent <= 0)
return -EIO; /* Not sure what's right here */
for_each_sg(sgd->sglist, sg, mvb->dma_desc_nent, i) {
desc->dma_addr = sg_dma_address(sg);
desc->segment_len = sg_dma_len(sg);
desc++;
}
return 0;
}
static void mcam_vb_buf_queue(struct vb2_buffer *vb) static void mcam_vb_buf_queue(struct vb2_buffer *vb)
{ {
struct mcam_vb_buffer *mvb = vb_to_mvb(vb); struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
...@@ -678,11 +777,34 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb) ...@@ -678,11 +777,34 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb)
spin_lock_irqsave(&cam->dev_lock, flags); spin_lock_irqsave(&cam->dev_lock, flags);
start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers); start = (cam->state == S_BUFWAIT) && !list_empty(&cam->buffers);
list_add(&mvb->queue, &cam->buffers); list_add(&mvb->queue, &cam->buffers);
if (test_bit(CF_SG_RESTART, &cam->flags))
mcam_sg_restart(cam);
spin_unlock_irqrestore(&cam->dev_lock, flags); spin_unlock_irqrestore(&cam->dev_lock, flags);
if (start) if (start)
mcam_read_setup(cam); mcam_read_setup(cam);
} }
static int mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
{
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_dma_sg_desc *sgd = vb2_dma_sg_plane_desc(vb, 0);
dma_unmap_sg(cam->dev, sgd->sglist, sgd->num_pages, DMA_FROM_DEVICE);
return 0;
}
static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
{
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
dma_free_coherent(cam->dev, ndesc * sizeof(struct mcam_dma_desc),
mvb->dma_desc, mvb->dma_desc_pa);
}
/* /*
* vb2 uses these to release the mutex when waiting in dqbuf. I'm * vb2 uses these to release the mutex when waiting in dqbuf. I'm
* not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
...@@ -752,7 +874,6 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq) ...@@ -752,7 +874,6 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq)
static const struct vb2_ops mcam_vb2_ops = { static const struct vb2_ops mcam_vb2_ops = {
.queue_setup = mcam_vb_queue_setup, .queue_setup = mcam_vb_queue_setup,
.buf_init = mcam_vb_buf_init,
.buf_queue = mcam_vb_buf_queue, .buf_queue = mcam_vb_buf_queue,
.start_streaming = mcam_vb_start_streaming, .start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming, .stop_streaming = mcam_vb_stop_streaming,
...@@ -760,22 +881,49 @@ static const struct vb2_ops mcam_vb2_ops = { ...@@ -760,22 +881,49 @@ static const struct vb2_ops mcam_vb2_ops = {
.wait_finish = mcam_vb_wait_finish, .wait_finish = mcam_vb_wait_finish,
}; };
/*
* Scatter/gather mode complicates things somewhat.
*/
static const struct vb2_ops mcam_vb2_sg_ops = {
.queue_setup = mcam_vb_queue_setup,
.buf_init = mcam_vb_sg_buf_init,
.buf_prepare = mcam_vb_sg_buf_prepare,
.buf_queue = mcam_vb_buf_queue,
.buf_finish = mcam_vb_sg_buf_finish,
.buf_cleanup = mcam_vb_sg_buf_cleanup,
.start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming,
.wait_prepare = mcam_vb_wait_prepare,
.wait_finish = mcam_vb_wait_finish,
};
static int mcam_setup_vb2(struct mcam_camera *cam) static int mcam_setup_vb2(struct mcam_camera *cam)
{ {
struct vb2_queue *vq = &cam->vb_queue; struct vb2_queue *vq = &cam->vb_queue;
memset(vq, 0, sizeof(*vq)); memset(vq, 0, sizeof(*vq));
vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vq->io_modes = VB2_MMAP; /* Add userptr */
vq->drv_priv = cam; vq->drv_priv = cam;
INIT_LIST_HEAD(&cam->buffers);
switch (cam->buffer_mode) {
case B_DMA_contig:
vq->ops = &mcam_vb2_ops; vq->ops = &mcam_vb2_ops;
if (cam->buffer_mode == B_DMA_contig) {
vq->mem_ops = &vb2_dma_contig_memops; vq->mem_ops = &vb2_dma_contig_memops;
cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev); cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
} else vq->io_modes = VB2_MMAP | VB2_USERPTR;
break;
case B_DMA_sg:
vq->ops = &mcam_vb2_sg_ops;
vq->mem_ops = &vb2_dma_sg_memops;
vq->io_modes = VB2_MMAP | VB2_USERPTR;
break;
case B_vmalloc:
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops; vq->mem_ops = &vb2_vmalloc_memops;
vq->buf_struct_size = sizeof(struct mcam_vb_buffer); vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
vq->io_modes = VB2_MMAP;
break;
}
return vb2_queue_init(vq); return vb2_queue_init(vq);
} }
...@@ -1313,8 +1461,6 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame, ...@@ -1313,8 +1461,6 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame,
{ {
vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage; vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
vbuf->v4l2_buf.sequence = cam->buf_seq[frame]; vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
vbuf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
vbuf->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage); vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE); vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
} }
...@@ -1363,7 +1509,7 @@ static void mcam_frame_tasklet(unsigned long data) ...@@ -1363,7 +1509,7 @@ static void mcam_frame_tasklet(unsigned long data)
/* /*
* For direct DMA, mark the buffer ready and set up another one. * For direct DMA, mark the buffer ready and set up another one.
*/ */
static void mcam_dma_complete(struct mcam_camera *cam, int frame) static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
{ {
struct mcam_vb_buffer *buf = cam->vb_bufs[frame]; struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
...@@ -1374,6 +1520,52 @@ static void mcam_dma_complete(struct mcam_camera *cam, int frame) ...@@ -1374,6 +1520,52 @@ static void mcam_dma_complete(struct mcam_camera *cam, int frame)
mcam_set_contig_buffer(cam, frame); mcam_set_contig_buffer(cam, frame);
} }
/*
* Frame completion with S/G is trickier. We can't muck with
* a descriptor chain on the fly, since the controller buffers it
* internally. So we have to actually stop and restart; Marvell
* says this is the way to do it.
*
* Of course, stopping is easier said than done; experience shows
* that the controller can start a frame *after* C0_ENABLE has been
* cleared. So when running in S/G mode, the controller is "stopped"
* on receipt of the start-of-frame interrupt. That means we can
* safely change the DMA descriptor array here and restart things
* (assuming there's another buffer waiting to go).
*/
static void mcam_dma_sg_done(struct mcam_camera *cam, int frame)
{
struct mcam_vb_buffer *buf = cam->vb_bufs[0];
/*
* Very Bad Not Good Things happen if you don't clear
* C1_DESC_ENA before making any descriptor changes.
*/
mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA);
/*
* If we have another buffer available, put it in and
* restart the engine.
*/
if (!list_empty(&cam->buffers)) {
mcam_sg_next_buffer(cam);
mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA);
mcam_ctlr_start(cam);
/*
* Otherwise set CF_SG_RESTART and the controller will
* be restarted once another buffer shows up.
*/
} else {
set_bit(CF_SG_RESTART, &cam->flags);
singles++;
}
/*
* Now we can give the completed frame back to user space.
*/
delivered++;
mcam_buffer_done(cam, frame, &buf->vb_buf);
}
static void mcam_frame_complete(struct mcam_camera *cam, int frame) static void mcam_frame_complete(struct mcam_camera *cam, int frame)
{ {
...@@ -1385,21 +1577,24 @@ static void mcam_frame_complete(struct mcam_camera *cam, int frame) ...@@ -1385,21 +1577,24 @@ static void mcam_frame_complete(struct mcam_camera *cam, int frame)
cam->next_buf = frame; cam->next_buf = frame;
cam->buf_seq[frame] = ++(cam->sequence); cam->buf_seq[frame] = ++(cam->sequence);
cam->last_delivered = frame; cam->last_delivered = frame;
frames++; frames++;
switch (cam->state) {
/* /*
* We're streaming and have a ready frame, hand it back * "This should never happen"
*/ */
case S_STREAMING: if (cam->state != S_STREAMING)
if (cam->buffer_mode == B_vmalloc) return;
/*
* Process the frame and set up the next one.
*/
switch (cam->buffer_mode) {
case B_vmalloc:
tasklet_schedule(&cam->s_tasklet); tasklet_schedule(&cam->s_tasklet);
else
mcam_dma_complete(cam, frame);
break; break;
case B_DMA_contig:
default: mcam_dma_contig_done(cam, frame);
cam_err(cam, "Frame interrupt in non-operational state\n"); break;
case B_DMA_sg:
mcam_dma_sg_done(cam, frame);
break; break;
} }
} }
...@@ -1416,6 +1611,11 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs) ...@@ -1416,6 +1611,11 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
* Handle any frame completions. There really should * Handle any frame completions. There really should
* not be more than one of these, or we have fallen * not be more than one of these, or we have fallen
* far behind. * far behind.
*
* When running in S/G mode, the frame number lacks any
* real meaning - there's only one descriptor array - but
* the controller still picks a different one to signal
* each time.
*/ */
for (frame = 0; frame < cam->nbufs; frame++) for (frame = 0; frame < cam->nbufs; frame++)
if (irqs & (IRQ_EOF0 << frame)) { if (irqs & (IRQ_EOF0 << frame)) {
...@@ -1430,6 +1630,8 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs) ...@@ -1430,6 +1630,8 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) { if (irqs & (IRQ_SOF0 | IRQ_SOF1 | IRQ_SOF2)) {
set_bit(CF_DMA_ACTIVE, &cam->flags); set_bit(CF_DMA_ACTIVE, &cam->flags);
handled = 1; handled = 1;
if (cam->buffer_mode == B_DMA_sg)
mcam_ctlr_stop(cam);
} }
return handled; return handled;
} }
...@@ -1480,8 +1682,15 @@ int mccic_register(struct mcam_camera *cam) ...@@ -1480,8 +1682,15 @@ int mccic_register(struct mcam_camera *cam)
cam->buffer_mode = B_vmalloc; cam->buffer_mode = B_vmalloc;
else if (buffer_mode == 1) else if (buffer_mode == 1)
cam->buffer_mode = B_DMA_contig; cam->buffer_mode = B_DMA_contig;
else if (buffer_mode != -1) else if (buffer_mode == 2) {
printk(KERN_ERR "marvel-cam: " if (cam->chip_id == V4L2_IDENT_ARMADA610)
cam->buffer_mode = B_DMA_sg;
else {
printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O\n");
cam->buffer_mode = B_vmalloc;
}
} else if (buffer_mode != -1)
printk(KERN_ERR "marvell-cam: "
"Strange module buffer mode %d - ignoring\n", "Strange module buffer mode %d - ignoring\n",
buffer_mode); buffer_mode);
mcam_ctlr_init(cam); mcam_ctlr_init(cam);
......
...@@ -38,7 +38,8 @@ enum mcam_state { ...@@ -38,7 +38,8 @@ enum mcam_state {
*/ */
enum mcam_buffer_mode { enum mcam_buffer_mode {
B_vmalloc = 0, B_vmalloc = 0,
B_DMA_contig B_DMA_contig,
B_DMA_sg
}; };
/* /*
...@@ -250,8 +251,11 @@ int mccic_resume(struct mcam_camera *cam); ...@@ -250,8 +251,11 @@ int mccic_resume(struct mcam_camera *cam);
#define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */ #define C0_SIF_HVSYNC 0x00000000 /* Use H/VSYNC */
#define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */ #define CO_SOF_NOSYNC 0x40000000 /* Use inband active signaling */
/* Bits below C1_444ALPHA are not present in Cafe */
#define REG_CTRL1 0x40 /* Control 1 */ #define REG_CTRL1 0x40 /* Control 1 */
#define C1_CLKGATE 0x00000001 /* Sensor clock gate */
#define C1_DESC_ENA 0x00000100 /* DMA descriptor enable */
#define C1_DESC_3WORD 0x00000200 /* Three-word descriptors used */
#define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */ #define C1_444ALPHA 0x00f00000 /* Alpha field in RGB444 */
#define C1_ALPHA_SHFT 20 #define C1_ALPHA_SHFT 20
#define C1_DMAB32 0x00000000 /* 32-byte DMA burst */ #define C1_DMAB32 0x00000000 /* 32-byte DMA burst */
...@@ -267,6 +271,14 @@ int mccic_resume(struct mcam_camera *cam); ...@@ -267,6 +271,14 @@ int mccic_resume(struct mcam_camera *cam);
/* This appears to be a Cafe-only register */ /* This appears to be a Cafe-only register */
#define REG_UBAR 0xc4 /* Upper base address register */ #define REG_UBAR 0xc4 /* Upper base address register */
/* Armada 610 DMA descriptor registers */
#define REG_DMA_DESC_Y 0x200
#define REG_DMA_DESC_U 0x204
#define REG_DMA_DESC_V 0x208
#define REG_DESC_LEN_Y 0x20c /* Lengths are in bytes */
#define REG_DESC_LEN_U 0x210
#define REG_DESC_LEN_V 0x214
/* /*
* Useful stuff that probably belongs somewhere global. * Useful stuff that probably belongs somewhere global.
*/ */
......
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