mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-13 08:39:52 +00:00
[media] marvell-cam: core code reorganization
This code shows signs of having been mucked with over the last five years or so; things were kind of mixed up. This patch reorders functions into a more rational organization which, with luck, will facilitate making the buffer modes selectable at configuration time. Code movement only: no functional changes here. Signed-off-by: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
983587c821
commit
d43dae75cc
@ -157,29 +157,20 @@ static struct mcam_format_struct *mcam_find_format(u32 pixelformat)
|
||||
}
|
||||
|
||||
/*
|
||||
* Start over with DMA buffers - dev_lock needed.
|
||||
* The default format we use until somebody says otherwise.
|
||||
*/
|
||||
static void mcam_reset_buffers(struct mcam_camera *cam)
|
||||
{
|
||||
int i;
|
||||
static const struct v4l2_pix_format mcam_def_pix_format = {
|
||||
.width = VGA_WIDTH,
|
||||
.height = VGA_HEIGHT,
|
||||
.pixelformat = V4L2_PIX_FMT_YUYV,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.bytesperline = VGA_WIDTH*2,
|
||||
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
|
||||
};
|
||||
|
||||
cam->next_buf = -1;
|
||||
for (i = 0; i < cam->nbufs; i++)
|
||||
clear_bit(i, &cam->flags);
|
||||
}
|
||||
static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
|
||||
V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
|
||||
static inline int mcam_needs_config(struct mcam_camera *cam)
|
||||
{
|
||||
return test_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
}
|
||||
|
||||
static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
|
||||
{
|
||||
if (needed)
|
||||
set_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
else
|
||||
clear_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* The two-word DMA descriptor format used by the Armada 610 and like. There
|
||||
@ -210,6 +201,19 @@ static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
|
||||
return container_of(vb, struct mcam_vb_buffer, vb_buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hand a completed buffer back to user space.
|
||||
*/
|
||||
static void mcam_buffer_done(struct mcam_camera *cam, int frame,
|
||||
struct vb2_buffer *vbuf)
|
||||
{
|
||||
vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
|
||||
vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
|
||||
vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
|
||||
vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Debugging and related.
|
||||
@ -222,11 +226,109 @@ static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_buffer *vb)
|
||||
dev_dbg((cam)->dev, fmt, ##arg);
|
||||
|
||||
|
||||
/*
|
||||
* Flag manipulation helpers
|
||||
*/
|
||||
static void mcam_reset_buffers(struct mcam_camera *cam)
|
||||
{
|
||||
int i;
|
||||
|
||||
cam->next_buf = -1;
|
||||
for (i = 0; i < cam->nbufs; i++)
|
||||
clear_bit(i, &cam->flags);
|
||||
}
|
||||
|
||||
static inline int mcam_needs_config(struct mcam_camera *cam)
|
||||
{
|
||||
return test_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
}
|
||||
|
||||
static void mcam_set_config_needed(struct mcam_camera *cam, int needed)
|
||||
{
|
||||
if (needed)
|
||||
set_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
else
|
||||
clear_bit(CF_CONFIG_NEEDED, &cam->flags);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/*
|
||||
* Deal with the controller.
|
||||
* Make the controller start grabbing images. Everything must
|
||||
* be set up before doing this.
|
||||
*/
|
||||
static void mcam_ctlr_start(struct mcam_camera *cam)
|
||||
{
|
||||
/* set_bit performs a read, so no other barrier should be
|
||||
needed here */
|
||||
mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
|
||||
}
|
||||
|
||||
static void mcam_ctlr_stop(struct mcam_camera *cam)
|
||||
{
|
||||
mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/*
|
||||
* Code specific to the vmalloc buffer mode.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allocate in-kernel DMA buffers for vmalloc mode.
|
||||
*/
|
||||
static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
|
||||
{
|
||||
int i;
|
||||
|
||||
mcam_set_config_needed(cam, 1);
|
||||
if (loadtime)
|
||||
cam->dma_buf_size = dma_buf_size;
|
||||
else
|
||||
cam->dma_buf_size = cam->pix_format.sizeimage;
|
||||
if (n_dma_bufs > 3)
|
||||
n_dma_bufs = 3;
|
||||
|
||||
cam->nbufs = 0;
|
||||
for (i = 0; i < n_dma_bufs; i++) {
|
||||
cam->dma_bufs[i] = dma_alloc_coherent(cam->dev,
|
||||
cam->dma_buf_size, cam->dma_handles + i,
|
||||
GFP_KERNEL);
|
||||
if (cam->dma_bufs[i] == NULL) {
|
||||
cam_warn(cam, "Failed to allocate DMA buffer\n");
|
||||
break;
|
||||
}
|
||||
(cam->nbufs)++;
|
||||
}
|
||||
|
||||
switch (cam->nbufs) {
|
||||
case 1:
|
||||
dma_free_coherent(cam->dev, cam->dma_buf_size,
|
||||
cam->dma_bufs[0], cam->dma_handles[0]);
|
||||
cam->nbufs = 0;
|
||||
case 0:
|
||||
cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
|
||||
return -ENOMEM;
|
||||
|
||||
case 2:
|
||||
if (n_dma_bufs > 2)
|
||||
cam_warn(cam, "Will limp along with only 2 buffers\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mcam_free_dma_bufs(struct mcam_camera *cam)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cam->nbufs; i++) {
|
||||
dma_free_coherent(cam->dev, cam->dma_buf_size,
|
||||
cam->dma_bufs[i], cam->dma_handles[i]);
|
||||
cam->dma_bufs[i] = NULL;
|
||||
}
|
||||
cam->nbufs = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set up DMA buffers when operating in vmalloc mode
|
||||
@ -250,6 +352,52 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
|
||||
mcam_reg_write(cam, REG_UBAR, 0); /* 32 bits only */
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data out to user space in the vmalloc case
|
||||
*/
|
||||
static void mcam_frame_tasklet(unsigned long data)
|
||||
{
|
||||
struct mcam_camera *cam = (struct mcam_camera *) data;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
struct mcam_vb_buffer *buf;
|
||||
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
for (i = 0; i < cam->nbufs; i++) {
|
||||
int bufno = cam->next_buf;
|
||||
|
||||
if (cam->state != S_STREAMING || bufno < 0)
|
||||
break; /* I/O got stopped */
|
||||
if (++(cam->next_buf) >= cam->nbufs)
|
||||
cam->next_buf = 0;
|
||||
if (!test_bit(bufno, &cam->flags))
|
||||
continue;
|
||||
if (list_empty(&cam->buffers)) {
|
||||
singles++;
|
||||
break; /* Leave it valid, hope for better later */
|
||||
}
|
||||
delivered++;
|
||||
clear_bit(bufno, &cam->flags);
|
||||
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
|
||||
queue);
|
||||
list_del_init(&buf->queue);
|
||||
/*
|
||||
* Drop the lock during the big copy. This *should* be safe...
|
||||
*/
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno],
|
||||
cam->pix_format.sizeimage);
|
||||
mcam_buffer_done(cam, bufno, &buf->vb_buf);
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* DMA-contiguous code.
|
||||
*/
|
||||
/*
|
||||
* Set up a contiguous buffer for the given frame. Here also is where
|
||||
* the underrun strategy is set: if there is no buffer available, reuse
|
||||
@ -295,6 +443,26 @@ static void mcam_ctlr_dma_contig(struct mcam_camera *cam)
|
||||
mcam_set_contig_buffer(cam, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Frame completion handling.
|
||||
*/
|
||||
static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
|
||||
{
|
||||
struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
|
||||
|
||||
if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
|
||||
delivered++;
|
||||
mcam_buffer_done(cam, frame, &buf->vb_buf);
|
||||
}
|
||||
mcam_set_contig_buffer(cam, frame);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* Scatter/gather-specific code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Set up the next buffer for S/G I/O; caller should be sure that
|
||||
@ -325,8 +493,74 @@ static void mcam_ctlr_dma_sg(struct mcam_camera *cam)
|
||||
cam->nbufs = 3;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Image format setup, independent of DMA scheme.
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* Buffer-mode-independent controller code.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Image format setup
|
||||
*/
|
||||
static void mcam_ctlr_image(struct mcam_camera *cam)
|
||||
{
|
||||
@ -417,34 +651,7 @@ static void mcam_ctlr_irq_disable(struct mcam_camera *cam)
|
||||
mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the controller start grabbing images. Everything must
|
||||
* be set up before doing this.
|
||||
*/
|
||||
static void mcam_ctlr_start(struct mcam_camera *cam)
|
||||
{
|
||||
/* set_bit performs a read, so no other barrier should be
|
||||
needed here */
|
||||
mcam_reg_set_bit(cam, REG_CTRL0, C0_ENABLE);
|
||||
}
|
||||
|
||||
static void mcam_ctlr_stop(struct mcam_camera *cam)
|
||||
{
|
||||
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)
|
||||
{
|
||||
@ -603,75 +810,6 @@ static int mcam_cam_configure(struct mcam_camera *cam)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/*
|
||||
* DMA buffer management. These functions need s_mutex held.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allocate in-kernel DMA buffers for vmalloc mode.
|
||||
*/
|
||||
static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
|
||||
{
|
||||
int i;
|
||||
|
||||
mcam_set_config_needed(cam, 1);
|
||||
if (loadtime)
|
||||
cam->dma_buf_size = dma_buf_size;
|
||||
else
|
||||
cam->dma_buf_size = cam->pix_format.sizeimage;
|
||||
if (n_dma_bufs > 3)
|
||||
n_dma_bufs = 3;
|
||||
|
||||
cam->nbufs = 0;
|
||||
for (i = 0; i < n_dma_bufs; i++) {
|
||||
cam->dma_bufs[i] = dma_alloc_coherent(cam->dev,
|
||||
cam->dma_buf_size, cam->dma_handles + i,
|
||||
GFP_KERNEL);
|
||||
if (cam->dma_bufs[i] == NULL) {
|
||||
cam_warn(cam, "Failed to allocate DMA buffer\n");
|
||||
break;
|
||||
}
|
||||
(cam->nbufs)++;
|
||||
}
|
||||
|
||||
switch (cam->nbufs) {
|
||||
case 1:
|
||||
dma_free_coherent(cam->dev, cam->dma_buf_size,
|
||||
cam->dma_bufs[0], cam->dma_handles[0]);
|
||||
cam->nbufs = 0;
|
||||
case 0:
|
||||
cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
|
||||
return -ENOMEM;
|
||||
|
||||
case 2:
|
||||
if (n_dma_bufs > 2)
|
||||
cam_warn(cam, "Will limp along with only 2 buffers\n");
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mcam_free_dma_bufs(struct mcam_camera *cam)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cam->nbufs; i++) {
|
||||
dma_free_coherent(cam->dev, cam->dma_buf_size,
|
||||
cam->dma_bufs[i], cam->dma_handles[i]);
|
||||
cam->dma_bufs[i] = NULL;
|
||||
}
|
||||
cam->nbufs = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/*
|
||||
* Here starts the V4L2 interface code.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Get everything ready, and start grabbing frames.
|
||||
*/
|
||||
@ -728,44 +866,6 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq, unsigned int *nbufs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
|
||||
int ndesc = cam->pix_format.sizeimage/PAGE_SIZE + 1;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -785,26 +885,6 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb)
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
* not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
|
||||
@ -882,8 +962,66 @@ static const struct vb2_ops mcam_vb2_ops = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Scatter/gather mode complicates things somewhat.
|
||||
* Scatter/gather mode uses all of the above functions plus a
|
||||
* few extras to deal with DMA mapping.
|
||||
*/
|
||||
static int mcam_vb_sg_buf_init(struct vb2_buffer *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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
|
||||
static const struct vb2_ops mcam_vb2_sg_ops = {
|
||||
.queue_setup = mcam_vb_queue_setup,
|
||||
.buf_init = mcam_vb_sg_buf_init,
|
||||
@ -934,23 +1072,10 @@ static void mcam_cleanup_vb2(struct mcam_camera *cam)
|
||||
vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
|
||||
}
|
||||
|
||||
static ssize_t mcam_v4l_read(struct file *filp,
|
||||
char __user *buffer, size_t len, loff_t *pos)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_read(&cam->vb_queue, buffer, len, pos,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* Streaming I/O support.
|
||||
* The long list of V4L2 ioctl() operations.
|
||||
*/
|
||||
|
||||
static int mcam_vidioc_streamon(struct file *filp, void *priv,
|
||||
@ -1029,80 +1154,6 @@ static int mcam_vidioc_dqbuf(struct file *filp, void *priv,
|
||||
}
|
||||
|
||||
|
||||
static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_mmap(&cam->vb_queue, vma);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int mcam_v4l_open(struct file *filp)
|
||||
{
|
||||
struct mcam_camera *cam = video_drvdata(filp);
|
||||
int ret = 0;
|
||||
|
||||
filp->private_data = cam;
|
||||
|
||||
frames = singles = delivered = 0;
|
||||
mutex_lock(&cam->s_mutex);
|
||||
if (cam->users == 0) {
|
||||
ret = mcam_setup_vb2(cam);
|
||||
if (ret)
|
||||
goto out;
|
||||
mcam_ctlr_power_up(cam);
|
||||
__mcam_cam_reset(cam);
|
||||
mcam_set_config_needed(cam, 1);
|
||||
}
|
||||
(cam->users)++;
|
||||
out:
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int mcam_v4l_release(struct file *filp)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
|
||||
cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
|
||||
singles, delivered);
|
||||
mutex_lock(&cam->s_mutex);
|
||||
(cam->users)--;
|
||||
if (filp == cam->owner) {
|
||||
mcam_ctlr_stop_dma(cam);
|
||||
cam->owner = NULL;
|
||||
}
|
||||
if (cam->users == 0) {
|
||||
mcam_cleanup_vb2(cam);
|
||||
mcam_ctlr_power_down(cam);
|
||||
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
|
||||
mcam_free_dma_bufs(cam);
|
||||
}
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned int mcam_v4l_poll(struct file *filp,
|
||||
struct poll_table_struct *pt)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_poll(&cam->vb_queue, filp, pt);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int mcam_vidioc_queryctrl(struct file *filp, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
@ -1155,21 +1206,6 @@ static int mcam_vidioc_querycap(struct file *file, void *priv,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The default format we use until somebody says otherwise.
|
||||
*/
|
||||
static const struct v4l2_pix_format mcam_def_pix_format = {
|
||||
.width = VGA_WIDTH,
|
||||
.height = VGA_HEIGHT,
|
||||
.pixelformat = V4L2_PIX_FMT_YUYV,
|
||||
.field = V4L2_FIELD_NONE,
|
||||
.bytesperline = VGA_WIDTH*2,
|
||||
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
|
||||
};
|
||||
|
||||
static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
|
||||
V4L2_MBUS_FMT_YUYV8_2X8;
|
||||
|
||||
static int mcam_vidioc_enum_fmt_vid_cap(struct file *filp,
|
||||
void *priv, struct v4l2_fmtdesc *fmt)
|
||||
{
|
||||
@ -1395,21 +1431,6 @@ static int mcam_vidioc_s_register(struct file *file, void *priv,
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This template device holds all of those v4l2 methods; we
|
||||
* clone it for specific real devices.
|
||||
*/
|
||||
|
||||
static const struct v4l2_file_operations mcam_v4l_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = mcam_v4l_open,
|
||||
.release = mcam_v4l_release,
|
||||
.read = mcam_v4l_read,
|
||||
.poll = mcam_v4l_poll,
|
||||
.mmap = mcam_v4l_mmap,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
|
||||
.vidioc_querycap = mcam_vidioc_querycap,
|
||||
.vidioc_enum_fmt_vid_cap = mcam_vidioc_enum_fmt_vid_cap,
|
||||
@ -1440,6 +1461,112 @@ static const struct v4l2_ioctl_ops mcam_v4l_ioctl_ops = {
|
||||
#endif
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* Our various file operations.
|
||||
*/
|
||||
static int mcam_v4l_open(struct file *filp)
|
||||
{
|
||||
struct mcam_camera *cam = video_drvdata(filp);
|
||||
int ret = 0;
|
||||
|
||||
filp->private_data = cam;
|
||||
|
||||
frames = singles = delivered = 0;
|
||||
mutex_lock(&cam->s_mutex);
|
||||
if (cam->users == 0) {
|
||||
ret = mcam_setup_vb2(cam);
|
||||
if (ret)
|
||||
goto out;
|
||||
mcam_ctlr_power_up(cam);
|
||||
__mcam_cam_reset(cam);
|
||||
mcam_set_config_needed(cam, 1);
|
||||
}
|
||||
(cam->users)++;
|
||||
out:
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int mcam_v4l_release(struct file *filp)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
|
||||
cam_err(cam, "Release, %d frames, %d singles, %d delivered\n", frames,
|
||||
singles, delivered);
|
||||
mutex_lock(&cam->s_mutex);
|
||||
(cam->users)--;
|
||||
if (filp == cam->owner) {
|
||||
mcam_ctlr_stop_dma(cam);
|
||||
cam->owner = NULL;
|
||||
}
|
||||
if (cam->users == 0) {
|
||||
mcam_cleanup_vb2(cam);
|
||||
mcam_ctlr_power_down(cam);
|
||||
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
|
||||
mcam_free_dma_bufs(cam);
|
||||
}
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t mcam_v4l_read(struct file *filp,
|
||||
char __user *buffer, size_t len, loff_t *pos)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_read(&cam->vb_queue, buffer, len, pos,
|
||||
filp->f_flags & O_NONBLOCK);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned int mcam_v4l_poll(struct file *filp,
|
||||
struct poll_table_struct *pt)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_poll(&cam->vb_queue, filp, pt);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int mcam_v4l_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct mcam_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&cam->s_mutex);
|
||||
ret = vb2_mmap(&cam->vb_queue, vma);
|
||||
mutex_unlock(&cam->s_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const struct v4l2_file_operations mcam_v4l_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = mcam_v4l_open,
|
||||
.release = mcam_v4l_release,
|
||||
.read = mcam_v4l_read,
|
||||
.poll = mcam_v4l_poll,
|
||||
.mmap = mcam_v4l_mmap,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* This template device holds all of those v4l2 methods; we
|
||||
* clone it for specific real devices.
|
||||
*/
|
||||
static struct video_device mcam_v4l_template = {
|
||||
.name = "mcam",
|
||||
.tvnorms = V4L2_STD_NTSC_M,
|
||||
@ -1454,119 +1581,6 @@ static struct video_device mcam_v4l_template = {
|
||||
/*
|
||||
* Interrupt handler stuff
|
||||
*/
|
||||
|
||||
|
||||
static void mcam_buffer_done(struct mcam_camera *cam, int frame,
|
||||
struct vb2_buffer *vbuf)
|
||||
{
|
||||
vbuf->v4l2_buf.bytesused = cam->pix_format.sizeimage;
|
||||
vbuf->v4l2_buf.sequence = cam->buf_seq[frame];
|
||||
vb2_set_plane_payload(vbuf, 0, cam->pix_format.sizeimage);
|
||||
vb2_buffer_done(vbuf, VB2_BUF_STATE_DONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy data out to user space in the vmalloc case
|
||||
*/
|
||||
static void mcam_frame_tasklet(unsigned long data)
|
||||
{
|
||||
struct mcam_camera *cam = (struct mcam_camera *) data;
|
||||
int i;
|
||||
unsigned long flags;
|
||||
struct mcam_vb_buffer *buf;
|
||||
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
for (i = 0; i < cam->nbufs; i++) {
|
||||
int bufno = cam->next_buf;
|
||||
|
||||
if (cam->state != S_STREAMING || bufno < 0)
|
||||
break; /* I/O got stopped */
|
||||
if (++(cam->next_buf) >= cam->nbufs)
|
||||
cam->next_buf = 0;
|
||||
if (!test_bit(bufno, &cam->flags))
|
||||
continue;
|
||||
if (list_empty(&cam->buffers)) {
|
||||
singles++;
|
||||
break; /* Leave it valid, hope for better later */
|
||||
}
|
||||
delivered++;
|
||||
clear_bit(bufno, &cam->flags);
|
||||
buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer,
|
||||
queue);
|
||||
list_del_init(&buf->queue);
|
||||
/*
|
||||
* Drop the lock during the big copy. This *should* be safe...
|
||||
*/
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
memcpy(vb2_plane_vaddr(&buf->vb_buf, 0), cam->dma_bufs[bufno],
|
||||
cam->pix_format.sizeimage);
|
||||
mcam_buffer_done(cam, bufno, &buf->vb_buf);
|
||||
spin_lock_irqsave(&cam->dev_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&cam->dev_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* For direct DMA, mark the buffer ready and set up another one.
|
||||
*/
|
||||
static void mcam_dma_contig_done(struct mcam_camera *cam, int frame)
|
||||
{
|
||||
struct mcam_vb_buffer *buf = cam->vb_bufs[frame];
|
||||
|
||||
if (!test_bit(CF_SINGLE_BUFFER, &cam->flags)) {
|
||||
delivered++;
|
||||
mcam_buffer_done(cam, frame, &buf->vb_buf);
|
||||
}
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@ -1600,8 +1614,10 @@ static void mcam_frame_complete(struct mcam_camera *cam, int frame)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The interrupt handler; this needs to be called from the
|
||||
* platform irq handler with the lock held.
|
||||
*/
|
||||
int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
|
||||
{
|
||||
unsigned int frame, handled = 0;
|
||||
@ -1636,10 +1652,10 @@ int mccic_irq(struct mcam_camera *cam, unsigned int irqs)
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/*
|
||||
* Registration and such.
|
||||
*/
|
||||
|
||||
static struct ov7670_config sensor_cfg = {
|
||||
/*
|
||||
* Exclude QCIF mode, because it only captures a tiny portion
|
||||
|
Loading…
x
Reference in New Issue
Block a user