static int singles;
static int delivered;
+#ifdef MCAM_MODE_VMALLOC
/*
* Internal DMA buffer management. Since the controller cannot do S/G I/O,
* we must have physically contiguous buffers to bring frames into.
"The size of the allocated DMA buffers. If actual operating "
"parameters require larger buffers, an attempt to reallocate "
"will be made.");
+#else /* MCAM_MODE_VMALLOC */
+static const int alloc_bufs_at_read = 0;
+static const int n_dma_bufs = 3; /* Used by S/G_PARM */
+#endif /* MCAM_MODE_VMALLOC */
static int flip;
module_param(flip, bool, 0444);
}
/* ------------------------------------------------------------------- */
+
+#ifdef MCAM_MODE_VMALLOC
/*
* Code specific to the vmalloc buffer mode.
*/
}
+/*
+ * Make sure our allocated buffers are up to the task.
+ */
+static int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+ if (cam->nbufs > 0 && cam->dma_buf_size < cam->pix_format.sizeimage)
+ mcam_free_dma_bufs(cam);
+ if (cam->nbufs == 0)
+ return mcam_alloc_dma_bufs(cam, 0);
+ return 0;
+}
+
+static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
+{
+ tasklet_schedule(&cam->s_tasklet);
+}
+
+#else /* MCAM_MODE_VMALLOC */
+
+static inline int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
+{
+ return 0;
+}
+
+static inline void mcam_free_dma_bufs(struct mcam_camera *cam)
+{
+ return;
+}
+
+static inline int mcam_check_dma_buffers(struct mcam_camera *cam)
+{
+ return 0;
+}
+
+
+
+#endif /* MCAM_MODE_VMALLOC */
+
+
+#ifdef MCAM_MODE_DMA_CONTIG
/* ---------------------------------------------------------------------- */
/*
* DMA-contiguous code.
mcam_set_contig_buffer(cam, frame);
}
+#endif /* MCAM_MODE_DMA_CONTIG */
-
+#ifdef MCAM_MODE_DMA_SG
/* ---------------------------------------------------------------------- */
/*
* Scatter/gather-specific code.
clear_bit(CF_SG_RESTART, &cam->flags);
}
+#else /* MCAM_MODE_DMA_SG */
+
+static inline void mcam_sg_restart(struct mcam_camera *cam)
+{
+ return;
+}
+
+#endif /* MCAM_MODE_DMA_SG */
/* ---------------------------------------------------------------------- */
/*
unsigned long flags;
spin_lock_irqsave(&cam->dev_lock, flags);
- 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;
- }
+ cam->dma_setup(cam);
mcam_ctlr_image(cam);
mcam_set_config_needed(cam, 0);
clear_bit(CF_SG_RESTART, &cam->flags);
.wait_finish = mcam_vb_wait_finish,
};
+
+#ifdef MCAM_MODE_DMA_SG
/*
* Scatter/gather mode uses all of the above functions plus a
* few extras to deal with DMA mapping.
.wait_finish = mcam_vb_wait_finish,
};
+#endif /* MCAM_MODE_DMA_SG */
+
static int mcam_setup_vb2(struct mcam_camera *cam)
{
struct vb2_queue *vq = &cam->vb_queue;
INIT_LIST_HEAD(&cam->buffers);
switch (cam->buffer_mode) {
case B_DMA_contig:
+#ifdef MCAM_MODE_DMA_CONTIG
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_dma_contig_memops;
cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ cam->dma_setup = mcam_ctlr_dma_contig;
+ cam->frame_complete = mcam_dma_contig_done;
+#endif
break;
case B_DMA_sg:
+#ifdef MCAM_MODE_DMA_SG
vq->ops = &mcam_vb2_sg_ops;
vq->mem_ops = &vb2_dma_sg_memops;
vq->io_modes = VB2_MMAP | VB2_USERPTR;
+ cam->dma_setup = mcam_ctlr_dma_sg;
+ cam->frame_complete = mcam_dma_sg_done;
+#endif
break;
case B_vmalloc:
+#ifdef MCAM_MODE_VMALLOC
+ tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
+ (unsigned long) cam);
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops;
vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
vq->io_modes = VB2_MMAP;
+ cam->dma_setup = mcam_ctlr_dma_vmalloc;
+ cam->frame_complete = mcam_vmalloc_done;
+#endif
break;
}
return vb2_queue_init(vq);
static void mcam_cleanup_vb2(struct mcam_camera *cam)
{
vb2_queue_release(&cam->vb_queue);
+#ifdef MCAM_MODE_DMA_CONTIG
if (cam->buffer_mode == B_DMA_contig)
vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
+#endif
}
/*
* Make sure we have appropriate DMA buffers.
*/
- ret = -ENOMEM;
if (cam->buffer_mode == B_vmalloc) {
- if (cam->nbufs > 0 &&
- cam->dma_buf_size < cam->pix_format.sizeimage)
- mcam_free_dma_bufs(cam);
- if (cam->nbufs == 0) {
- if (mcam_alloc_dma_bufs(cam, 0))
- goto out;
- }
+ ret = mcam_check_dma_buffers(cam);
+ if (ret)
+ goto out;
}
mcam_set_config_needed(cam, 1);
ret = 0;
/*
* Process the frame and set up the next one.
*/
- switch (cam->buffer_mode) {
- case B_vmalloc:
- tasklet_schedule(&cam->s_tasklet);
- break;
- case B_DMA_contig:
- mcam_dma_contig_done(cam, frame);
- break;
- case B_DMA_sg:
- mcam_dma_sg_done(cam, frame);
- break;
- }
+ cam->frame_complete(cam, frame);
}
};
int ret;
+ /*
+ * Validate the requested buffer mode.
+ */
+ if (buffer_mode >= 0)
+ cam->buffer_mode = buffer_mode;
+ if (cam->buffer_mode == B_DMA_sg &&
+ cam->chip_id == V4L2_IDENT_CAFE) {
+ printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, "
+ "attempting vmalloc mode instead\n");
+ cam->buffer_mode = B_vmalloc;
+ }
+ if (!mcam_buffer_mode_supported(cam->buffer_mode)) {
+ printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n",
+ cam->buffer_mode);
+ return -EINVAL;
+ }
/*
* Register with V4L
*/
cam->mbus_code = mcam_def_mbus_code;
INIT_LIST_HEAD(&cam->dev_list);
INIT_LIST_HEAD(&cam->buffers);
- tasklet_init(&cam->s_tasklet, mcam_frame_tasklet, (unsigned long) cam);
- /*
- * User space may want to override the asked-for buffer mode;
- * here's hoping they know what they're doing.
- */
- if (buffer_mode == 0)
- cam->buffer_mode = B_vmalloc;
- else if (buffer_mode == 1)
- cam->buffer_mode = B_DMA_contig;
- else if (buffer_mode == 2) {
- 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",
- buffer_mode);
mcam_ctlr_init(cam);
/*
#include <media/v4l2-dev.h>
#include <media/videobuf2-core.h>
+/*
+ * Create our own symbols for the supported buffer modes, but, for now,
+ * base them entirely on which videobuf2 options have been selected.
+ */
+#if defined(CONFIG_VIDEOBUF2_VMALLOC) || defined(CONFIG_VIDEOBUF2_VMALLOC_MODULE)
+#define MCAM_MODE_VMALLOC 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_CONTIG) || defined(CONFIG_VIDEOBUF2_DMA_CONTIG_MODULE)
+#define MCAM_MODE_DMA_CONTIG 1
+#endif
+
+#if defined(CONFIG_VIDEOBUF2_DMA_SG) || defined(CONFIG_VIDEOBUF2_DMA_SG_MODULE)
+#define MCAM_MODE_DMA_SG 1
+#endif
+
+#if !defined(MCAM_MODE_VMALLOC) && !defined(MCAM_MODE_DMA_CONTIG) && \
+ !defined(MCAM_MODE_DMA_SG)
+#error One of the videobuf buffer modes must be selected in the config
+#endif
+
enum mcam_state {
S_NOTREADY, /* Not yet initialized */
*/
enum mcam_buffer_mode {
B_vmalloc = 0,
- B_DMA_contig,
- B_DMA_sg
+ B_DMA_contig = 1,
+ B_DMA_sg = 2
};
+/*
+ * Is a given buffer mode supported by the current kernel configuration?
+ */
+static inline int mcam_buffer_mode_supported(enum mcam_buffer_mode mode)
+{
+ switch (mode) {
+#ifdef MCAM_MODE_VMALLOC
+ case B_vmalloc:
+#endif
+#ifdef MCAM_MODE_DMA_CONTIG
+ case B_DMA_contig:
+#endif
+#ifdef MCAM_MODE_DMA_SG
+ case B_DMA_sg:
+#endif
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+
/*
* A description of one of our devices.
* Locking: controlled by s_mutex. Certain fields, however, require
struct vb2_queue vb_queue;
struct list_head buffers; /* Available frames */
- /* DMA buffers - vmalloc mode */
unsigned int nbufs; /* How many are alloc'd */
int next_buf; /* Next to consume (dev_lock) */
+
+ /* DMA buffers - vmalloc mode */
+#ifdef MCAM_MODE_VMALLOC
unsigned int dma_buf_size; /* allocated size */
void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */
dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
+ struct tasklet_struct s_tasklet;
+#endif
unsigned int sequence; /* Frame sequence number */
unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */
- /* DMA buffers - contiguous DMA mode */
+ /* DMA buffers - DMA modes */
struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS];
struct vb2_alloc_ctx *vb_alloc_ctx;
unsigned short last_delivered;
- struct tasklet_struct s_tasklet;
+ /* Mode-specific ops, set at open time */
+ void (*dma_setup)(struct mcam_camera *cam);
+ void (*frame_complete)(struct mcam_camera *cam, int frame);
/* Current operating parameters */
u32 sensor_type; /* Currently ov7670 only */