[media] media i.MX27 camera: migrate driver to videobuf2
Signed-off-by: Javier Martin <javier.martin@vista-silicon.com> Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
2c9ba37d7a
commit
c6a41e3271
|
@ -3,6 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008, Sascha Hauer, Pengutronix
|
* Copyright (C) 2008, Sascha Hauer, Pengutronix
|
||||||
* Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
|
* Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
|
||||||
|
* Copyright (C) 2012, Javier Martin, Vista Silicon S.L.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -30,8 +31,8 @@
|
||||||
|
|
||||||
#include <media/v4l2-common.h>
|
#include <media/v4l2-common.h>
|
||||||
#include <media/v4l2-dev.h>
|
#include <media/v4l2-dev.h>
|
||||||
#include <media/videobuf-core.h>
|
#include <media/videobuf2-core.h>
|
||||||
#include <media/videobuf-dma-contig.h>
|
#include <media/videobuf2-dma-contig.h>
|
||||||
#include <media/soc_camera.h>
|
#include <media/soc_camera.h>
|
||||||
#include <media/soc_mediabus.h>
|
#include <media/soc_mediabus.h>
|
||||||
|
|
||||||
|
@ -221,6 +222,22 @@ struct mx2_fmt_cfg {
|
||||||
struct mx2_prp_cfg cfg;
|
struct mx2_prp_cfg cfg;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum mx2_buffer_state {
|
||||||
|
MX2_STATE_QUEUED,
|
||||||
|
MX2_STATE_ACTIVE,
|
||||||
|
MX2_STATE_DONE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* buffer for one video frame */
|
||||||
|
struct mx2_buffer {
|
||||||
|
/* common v4l buffer stuff -- must be first */
|
||||||
|
struct vb2_buffer vb;
|
||||||
|
struct list_head queue;
|
||||||
|
enum mx2_buffer_state state;
|
||||||
|
|
||||||
|
int bufnum;
|
||||||
|
};
|
||||||
|
|
||||||
struct mx2_camera_dev {
|
struct mx2_camera_dev {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct soc_camera_host soc_host;
|
struct soc_camera_host soc_host;
|
||||||
|
@ -252,16 +269,7 @@ struct mx2_camera_dev {
|
||||||
size_t discard_size;
|
size_t discard_size;
|
||||||
struct mx2_fmt_cfg *emma_prp;
|
struct mx2_fmt_cfg *emma_prp;
|
||||||
u32 frame_count;
|
u32 frame_count;
|
||||||
};
|
struct vb2_alloc_ctx *alloc_ctx;
|
||||||
|
|
||||||
/* buffer for one video frame */
|
|
||||||
struct mx2_buffer {
|
|
||||||
/* common v4l buffer stuff -- must be first */
|
|
||||||
struct videobuf_buffer vb;
|
|
||||||
|
|
||||||
enum v4l2_mbus_pixelcode code;
|
|
||||||
|
|
||||||
int bufnum;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
|
static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
|
||||||
|
@ -398,7 +406,7 @@ static void mx2_camera_remove_device(struct soc_camera_device *icd)
|
||||||
static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
|
static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
|
||||||
int state)
|
int state)
|
||||||
{
|
{
|
||||||
struct videobuf_buffer *vb;
|
struct vb2_buffer *vb;
|
||||||
struct mx2_buffer *buf;
|
struct mx2_buffer *buf;
|
||||||
struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
|
struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
|
||||||
&pcdev->fb2_active;
|
&pcdev->fb2_active;
|
||||||
|
@ -411,25 +419,24 @@ static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
vb = &(*fb_active)->vb;
|
vb = &(*fb_active)->vb;
|
||||||
dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
|
dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
||||||
vb, vb->baddr, vb->bsize);
|
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
vb->state = state;
|
do_gettimeofday(&vb->v4l2_buf.timestamp);
|
||||||
do_gettimeofday(&vb->ts);
|
vb->v4l2_buf.sequence++;
|
||||||
vb->field_count++;
|
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
|
||||||
|
|
||||||
wake_up(&vb->done);
|
|
||||||
|
|
||||||
if (list_empty(&pcdev->capture)) {
|
if (list_empty(&pcdev->capture)) {
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
writel(0, pcdev->base_csi + fb_reg);
|
writel(0, pcdev->base_csi + fb_reg);
|
||||||
} else {
|
} else {
|
||||||
buf = list_entry(pcdev->capture.next, struct mx2_buffer,
|
buf = list_entry(pcdev->capture.next, struct mx2_buffer,
|
||||||
vb.queue);
|
queue);
|
||||||
vb = &buf->vb;
|
vb = &buf->vb;
|
||||||
list_del(&vb->queue);
|
list_del(&buf->queue);
|
||||||
vb->state = VIDEOBUF_ACTIVE;
|
buf->state = MX2_STATE_ACTIVE;
|
||||||
writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
|
writel(vb2_dma_contig_plane_dma_addr(vb, 0),
|
||||||
|
pcdev->base_csi + fb_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
*fb_active = buf;
|
*fb_active = buf;
|
||||||
|
@ -444,9 +451,9 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
|
||||||
u32 status = readl(pcdev->base_csi + CSISR);
|
u32 status = readl(pcdev->base_csi + CSISR);
|
||||||
|
|
||||||
if (status & CSISR_DMA_TSF_FB1_INT)
|
if (status & CSISR_DMA_TSF_FB1_INT)
|
||||||
mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
|
mx25_camera_frame_done(pcdev, 1, MX2_STATE_DONE);
|
||||||
else if (status & CSISR_DMA_TSF_FB2_INT)
|
else if (status & CSISR_DMA_TSF_FB2_INT)
|
||||||
mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
|
mx25_camera_frame_done(pcdev, 2, MX2_STATE_DONE);
|
||||||
|
|
||||||
/* FIXME: handle CSISR_RFF_OR_INT */
|
/* FIXME: handle CSISR_RFF_OR_INT */
|
||||||
|
|
||||||
|
@ -458,59 +465,50 @@ static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
|
||||||
/*
|
/*
|
||||||
* Videobuf operations
|
* Videobuf operations
|
||||||
*/
|
*/
|
||||||
static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
|
static int mx2_videobuf_setup(struct vb2_queue *vq,
|
||||||
unsigned int *size)
|
const struct v4l2_format *fmt,
|
||||||
|
unsigned int *count, unsigned int *num_planes,
|
||||||
|
unsigned int sizes[], void *alloc_ctxs[])
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = vq->priv_data;
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
|
||||||
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
|
struct mx2_camera_dev *pcdev = ici->priv;
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
||||||
icd->current_fmt->host_fmt);
|
icd->current_fmt->host_fmt);
|
||||||
|
|
||||||
dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
|
dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
|
||||||
|
|
||||||
|
/* TODO: support for VIDIOC_CREATE_BUFS not ready */
|
||||||
|
if (fmt != NULL)
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
if (bytes_per_line < 0)
|
if (bytes_per_line < 0)
|
||||||
return bytes_per_line;
|
return bytes_per_line;
|
||||||
|
|
||||||
*size = bytes_per_line * icd->user_height;
|
alloc_ctxs[0] = pcdev->alloc_ctx;
|
||||||
|
|
||||||
|
sizes[0] = bytes_per_line * icd->user_height;
|
||||||
|
|
||||||
if (0 == *count)
|
if (0 == *count)
|
||||||
*count = 32;
|
*count = 32;
|
||||||
if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
|
if (!*num_planes &&
|
||||||
*count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
|
sizes[0] * *count > MAX_VIDEO_MEM * 1024 * 1024)
|
||||||
|
*count = (MAX_VIDEO_MEM * 1024 * 1024) / sizes[0];
|
||||||
|
|
||||||
|
*num_planes = 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
|
static int mx2_videobuf_prepare(struct vb2_buffer *vb)
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = vq->priv_data;
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
|
||||||
struct videobuf_buffer *vb = &buf->vb;
|
|
||||||
|
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
|
|
||||||
vb, vb->baddr, vb->bsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This waits until this buffer is out of danger, i.e., until it is no
|
|
||||||
* longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
|
|
||||||
*/
|
|
||||||
videobuf_waiton(vq, vb, 0, 0);
|
|
||||||
|
|
||||||
videobuf_dma_contig_free(vq, vb);
|
|
||||||
dev_dbg(icd->parent, "%s freed\n", __func__);
|
|
||||||
|
|
||||||
vb->state = VIDEOBUF_NEEDS_INIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mx2_videobuf_prepare(struct videobuf_queue *vq,
|
|
||||||
struct videobuf_buffer *vb, enum v4l2_field field)
|
|
||||||
{
|
|
||||||
struct soc_camera_device *icd = vq->priv_data;
|
|
||||||
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
|
|
||||||
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
|
||||||
icd->current_fmt->host_fmt);
|
icd->current_fmt->host_fmt);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
|
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
||||||
vb, vb->baddr, vb->bsize);
|
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
if (bytes_per_line < 0)
|
if (bytes_per_line < 0)
|
||||||
return bytes_per_line;
|
return bytes_per_line;
|
||||||
|
@ -520,78 +518,58 @@ static int mx2_videobuf_prepare(struct videobuf_queue *vq,
|
||||||
* This can be useful if you want to see if we actually fill
|
* This can be useful if you want to see if we actually fill
|
||||||
* the buffer with something
|
* the buffer with something
|
||||||
*/
|
*/
|
||||||
memset((void *)vb->baddr, 0xaa, vb->bsize);
|
memset((void *)vb2_plane_vaddr(vb, 0),
|
||||||
|
0xaa, vb2_get_plane_payload(vb, 0));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (buf->code != icd->current_fmt->code ||
|
vb2_set_plane_payload(vb, 0, bytes_per_line * icd->user_height);
|
||||||
vb->width != icd->user_width ||
|
if (vb2_plane_vaddr(vb, 0) &&
|
||||||
vb->height != icd->user_height ||
|
vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
|
||||||
vb->field != field) {
|
|
||||||
buf->code = icd->current_fmt->code;
|
|
||||||
vb->width = icd->user_width;
|
|
||||||
vb->height = icd->user_height;
|
|
||||||
vb->field = field;
|
|
||||||
vb->state = VIDEOBUF_NEEDS_INIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
vb->size = bytes_per_line * vb->height;
|
|
||||||
if (vb->baddr && vb->bsize < vb->size) {
|
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vb->state == VIDEOBUF_NEEDS_INIT) {
|
|
||||||
ret = videobuf_iolock(vq, vb, NULL);
|
|
||||||
if (ret)
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
vb->state = VIDEOBUF_PREPARED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fail:
|
|
||||||
free_buffer(vq, buf);
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mx2_videobuf_queue(struct videobuf_queue *vq,
|
static void mx2_videobuf_queue(struct vb2_buffer *vb)
|
||||||
struct videobuf_buffer *vb)
|
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = vq->priv_data;
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
|
||||||
struct soc_camera_host *ici =
|
struct soc_camera_host *ici =
|
||||||
to_soc_camera_host(icd->parent);
|
to_soc_camera_host(icd->parent);
|
||||||
struct mx2_camera_dev *pcdev = ici->priv;
|
struct mx2_camera_dev *pcdev = ici->priv;
|
||||||
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
|
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
|
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
||||||
vb, vb->baddr, vb->bsize);
|
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
spin_lock_irqsave(&pcdev->lock, flags);
|
spin_lock_irqsave(&pcdev->lock, flags);
|
||||||
|
|
||||||
vb->state = VIDEOBUF_QUEUED;
|
buf->state = MX2_STATE_QUEUED;
|
||||||
list_add_tail(&vb->queue, &pcdev->capture);
|
list_add_tail(&buf->queue, &pcdev->capture);
|
||||||
|
|
||||||
if (cpu_is_mx25()) {
|
if (cpu_is_mx25()) {
|
||||||
u32 csicr3, dma_inten = 0;
|
u32 csicr3, dma_inten = 0;
|
||||||
|
|
||||||
if (pcdev->fb1_active == NULL) {
|
if (pcdev->fb1_active == NULL) {
|
||||||
writel(videobuf_to_dma_contig(vb),
|
writel(vb2_dma_contig_plane_dma_addr(vb, 0),
|
||||||
pcdev->base_csi + CSIDMASA_FB1);
|
pcdev->base_csi + CSIDMASA_FB1);
|
||||||
pcdev->fb1_active = buf;
|
pcdev->fb1_active = buf;
|
||||||
dma_inten = CSICR1_FB1_DMA_INTEN;
|
dma_inten = CSICR1_FB1_DMA_INTEN;
|
||||||
} else if (pcdev->fb2_active == NULL) {
|
} else if (pcdev->fb2_active == NULL) {
|
||||||
writel(videobuf_to_dma_contig(vb),
|
writel(vb2_dma_contig_plane_dma_addr(vb, 0),
|
||||||
pcdev->base_csi + CSIDMASA_FB2);
|
pcdev->base_csi + CSIDMASA_FB2);
|
||||||
pcdev->fb2_active = buf;
|
pcdev->fb2_active = buf;
|
||||||
dma_inten = CSICR1_FB2_DMA_INTEN;
|
dma_inten = CSICR1_FB2_DMA_INTEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dma_inten) {
|
if (dma_inten) {
|
||||||
list_del(&vb->queue);
|
list_del(&buf->queue);
|
||||||
vb->state = VIDEOBUF_ACTIVE;
|
buf->state = MX2_STATE_ACTIVE;
|
||||||
|
|
||||||
csicr3 = readl(pcdev->base_csi + CSICR3);
|
csicr3 = readl(pcdev->base_csi + CSICR3);
|
||||||
|
|
||||||
|
@ -613,32 +591,28 @@ static void mx2_videobuf_queue(struct videobuf_queue *vq,
|
||||||
spin_unlock_irqrestore(&pcdev->lock, flags);
|
spin_unlock_irqrestore(&pcdev->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mx2_videobuf_release(struct videobuf_queue *vq,
|
static void mx2_videobuf_release(struct vb2_buffer *vb)
|
||||||
struct videobuf_buffer *vb)
|
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = vq->priv_data;
|
struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
||||||
struct mx2_camera_dev *pcdev = ici->priv;
|
struct mx2_camera_dev *pcdev = ici->priv;
|
||||||
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
|
struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
|
dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
|
||||||
vb, vb->baddr, vb->bsize);
|
vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
switch (vb->state) {
|
switch (buf->state) {
|
||||||
case VIDEOBUF_ACTIVE:
|
case MX2_STATE_ACTIVE:
|
||||||
dev_info(icd->parent, "%s (active)\n", __func__);
|
dev_info(icd->parent, "%s (active)\n", __func__);
|
||||||
break;
|
break;
|
||||||
case VIDEOBUF_QUEUED:
|
case MX2_STATE_QUEUED:
|
||||||
dev_info(icd->parent, "%s (queued)\n", __func__);
|
dev_info(icd->parent, "%s (queued)\n", __func__);
|
||||||
break;
|
break;
|
||||||
case VIDEOBUF_PREPARED:
|
|
||||||
dev_info(icd->parent, "%s (prepared)\n", __func__);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
dev_info(icd->parent, "%s (unknown) %d\n", __func__,
|
dev_info(icd->parent, "%s (unknown) %d\n", __func__,
|
||||||
vb->state);
|
buf->state);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -652,11 +626,10 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
|
||||||
* state. This requires a specific handling for each of the these DMA
|
* state. This requires a specific handling for each of the these DMA
|
||||||
* types.
|
* types.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
spin_lock_irqsave(&pcdev->lock, flags);
|
spin_lock_irqsave(&pcdev->lock, flags);
|
||||||
if (vb->state == VIDEOBUF_QUEUED) {
|
list_del_init(&buf->queue);
|
||||||
list_del(&vb->queue);
|
if (cpu_is_mx25() && buf->state == MX2_STATE_ACTIVE) {
|
||||||
vb->state = VIDEOBUF_ERROR;
|
|
||||||
} else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
|
|
||||||
if (pcdev->fb1_active == buf) {
|
if (pcdev->fb1_active == buf) {
|
||||||
pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
|
pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
|
||||||
writel(0, pcdev->base_csi + CSIDMASA_FB1);
|
writel(0, pcdev->base_csi + CSIDMASA_FB1);
|
||||||
|
@ -667,30 +640,28 @@ static void mx2_videobuf_release(struct videobuf_queue *vq,
|
||||||
pcdev->fb2_active = NULL;
|
pcdev->fb2_active = NULL;
|
||||||
}
|
}
|
||||||
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
|
writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
|
||||||
vb->state = VIDEOBUF_ERROR;
|
|
||||||
}
|
}
|
||||||
spin_unlock_irqrestore(&pcdev->lock, flags);
|
spin_unlock_irqrestore(&pcdev->lock, flags);
|
||||||
|
|
||||||
free_buffer(vq, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct videobuf_queue_ops mx2_videobuf_ops = {
|
static struct vb2_ops mx2_videobuf_ops = {
|
||||||
.buf_setup = mx2_videobuf_setup,
|
.queue_setup = mx2_videobuf_setup,
|
||||||
.buf_prepare = mx2_videobuf_prepare,
|
.buf_prepare = mx2_videobuf_prepare,
|
||||||
.buf_queue = mx2_videobuf_queue,
|
.buf_queue = mx2_videobuf_queue,
|
||||||
.buf_release = mx2_videobuf_release,
|
.buf_cleanup = mx2_videobuf_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mx2_camera_init_videobuf(struct videobuf_queue *q,
|
static int mx2_camera_init_videobuf(struct vb2_queue *q,
|
||||||
struct soc_camera_device *icd)
|
struct soc_camera_device *icd)
|
||||||
{
|
{
|
||||||
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
|
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
struct mx2_camera_dev *pcdev = ici->priv;
|
q->io_modes = VB2_MMAP | VB2_USERPTR;
|
||||||
|
q->drv_priv = icd;
|
||||||
|
q->ops = &mx2_videobuf_ops;
|
||||||
|
q->mem_ops = &vb2_dma_contig_memops;
|
||||||
|
q->buf_struct_size = sizeof(struct mx2_buffer);
|
||||||
|
|
||||||
videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
|
return vb2_queue_init(q);
|
||||||
&pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
|
||||||
V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
|
|
||||||
icd, &icd->video_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \
|
#define MX2_BUS_FLAGS (V4L2_MBUS_MASTER | \
|
||||||
|
@ -1122,25 +1093,11 @@ static int mx2_camera_querycap(struct soc_camera_host *ici,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mx2_camera_reqbufs(struct soc_camera_device *icd,
|
|
||||||
struct v4l2_requestbuffers *p)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < p->count; i++) {
|
|
||||||
struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
|
|
||||||
struct mx2_buffer, vb);
|
|
||||||
INIT_LIST_HEAD(&buf->vb.queue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
|
static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
|
||||||
{
|
{
|
||||||
struct soc_camera_device *icd = file->private_data;
|
struct soc_camera_device *icd = file->private_data;
|
||||||
|
|
||||||
return videobuf_poll_stream(file, &icd->vb_vidq, pt);
|
return vb2_poll(&icd->vb2_vidq, file, pt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
|
static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
|
||||||
|
@ -1151,31 +1108,30 @@ static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
|
||||||
.set_crop = mx2_camera_set_crop,
|
.set_crop = mx2_camera_set_crop,
|
||||||
.get_formats = mx2_camera_get_formats,
|
.get_formats = mx2_camera_get_formats,
|
||||||
.try_fmt = mx2_camera_try_fmt,
|
.try_fmt = mx2_camera_try_fmt,
|
||||||
.init_videobuf = mx2_camera_init_videobuf,
|
.init_videobuf2 = mx2_camera_init_videobuf,
|
||||||
.reqbufs = mx2_camera_reqbufs,
|
|
||||||
.poll = mx2_camera_poll,
|
.poll = mx2_camera_poll,
|
||||||
.querycap = mx2_camera_querycap,
|
.querycap = mx2_camera_querycap,
|
||||||
.set_bus_param = mx2_camera_set_bus_param,
|
.set_bus_param = mx2_camera_set_bus_param,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
|
static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
|
||||||
int bufnum, int state)
|
int bufnum)
|
||||||
{
|
{
|
||||||
u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
|
u32 imgsize = pcdev->icd->user_height * pcdev->icd->user_width;
|
||||||
struct mx2_fmt_cfg *prp = pcdev->emma_prp;
|
struct mx2_fmt_cfg *prp = pcdev->emma_prp;
|
||||||
struct mx2_buffer *buf;
|
struct mx2_buffer *buf;
|
||||||
struct videobuf_buffer *vb;
|
struct vb2_buffer *vb;
|
||||||
unsigned long phys;
|
unsigned long phys;
|
||||||
|
|
||||||
if (!list_empty(&pcdev->active_bufs)) {
|
if (!list_empty(&pcdev->active_bufs)) {
|
||||||
buf = list_entry(pcdev->active_bufs.next,
|
buf = list_entry(pcdev->active_bufs.next,
|
||||||
struct mx2_buffer, vb.queue);
|
struct mx2_buffer, queue);
|
||||||
|
|
||||||
BUG_ON(buf->bufnum != bufnum);
|
BUG_ON(buf->bufnum != bufnum);
|
||||||
|
|
||||||
vb = &buf->vb;
|
vb = &buf->vb;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
phys = videobuf_to_dma_contig(vb);
|
phys = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||||
if (prp->cfg.channel == 1) {
|
if (prp->cfg.channel == 1) {
|
||||||
if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
|
if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
|
||||||
4 * bufnum) != phys) {
|
4 * bufnum) != phys) {
|
||||||
|
@ -1194,16 +1150,15 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
|
dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%p %lu\n", __func__, vb,
|
||||||
vb->baddr, vb->bsize);
|
vb2_plane_vaddr(vb, 0),
|
||||||
|
vb2_get_plane_payload(vb, 0));
|
||||||
|
|
||||||
list_del(&vb->queue);
|
list_del_init(&buf->queue);
|
||||||
vb->state = state;
|
do_gettimeofday(&vb->v4l2_buf.timestamp);
|
||||||
do_gettimeofday(&vb->ts);
|
|
||||||
vb->field_count = pcdev->frame_count * 2;
|
|
||||||
pcdev->frame_count++;
|
pcdev->frame_count++;
|
||||||
|
vb->v4l2_buf.sequence = pcdev->frame_count;
|
||||||
wake_up(&vb->done);
|
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list_empty(&pcdev->capture)) {
|
if (list_empty(&pcdev->capture)) {
|
||||||
|
@ -1227,16 +1182,16 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = list_entry(pcdev->capture.next,
|
buf = list_entry(pcdev->capture.next,
|
||||||
struct mx2_buffer, vb.queue);
|
struct mx2_buffer, queue);
|
||||||
|
|
||||||
buf->bufnum = !bufnum;
|
buf->bufnum = !bufnum;
|
||||||
|
|
||||||
list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
|
list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
|
||||||
|
|
||||||
vb = &buf->vb;
|
vb = &buf->vb;
|
||||||
vb->state = VIDEOBUF_ACTIVE;
|
buf->state = MX2_STATE_ACTIVE;
|
||||||
|
|
||||||
phys = videobuf_to_dma_contig(vb);
|
phys = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||||
if (prp->cfg.channel == 1) {
|
if (prp->cfg.channel == 1) {
|
||||||
writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
|
writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1280,14 +1235,14 @@ static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
|
||||||
* to first
|
* to first
|
||||||
*/
|
*/
|
||||||
buf = list_entry(pcdev->active_bufs.next,
|
buf = list_entry(pcdev->active_bufs.next,
|
||||||
struct mx2_buffer, vb.queue);
|
struct mx2_buffer, queue);
|
||||||
mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
|
mx27_camera_frame_done_emma(pcdev, buf->bufnum);
|
||||||
status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
|
status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
|
||||||
}
|
}
|
||||||
if ((status & (1 << 6)) || (status & (1 << 4)))
|
if ((status & (1 << 6)) || (status & (1 << 4)))
|
||||||
mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
|
mx27_camera_frame_done_emma(pcdev, 0);
|
||||||
if ((status & (1 << 5)) || (status & (1 << 3)))
|
if ((status & (1 << 5)) || (status & (1 << 3)))
|
||||||
mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
|
mx27_camera_frame_done_emma(pcdev, 1);
|
||||||
|
|
||||||
writel(status, pcdev->base_emma + PRP_INTRSTATUS);
|
writel(status, pcdev->base_emma + PRP_INTRSTATUS);
|
||||||
|
|
||||||
|
@ -1449,6 +1404,12 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
|
||||||
pcdev->soc_host.priv = pcdev;
|
pcdev->soc_host.priv = pcdev;
|
||||||
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
|
pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
|
||||||
pcdev->soc_host.nr = pdev->id;
|
pcdev->soc_host.nr = pdev->id;
|
||||||
|
|
||||||
|
pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
|
||||||
|
if (IS_ERR(pcdev->alloc_ctx)) {
|
||||||
|
err = PTR_ERR(pcdev->alloc_ctx);
|
||||||
|
goto eallocctx;
|
||||||
|
}
|
||||||
err = soc_camera_host_register(&pcdev->soc_host);
|
err = soc_camera_host_register(&pcdev->soc_host);
|
||||||
if (err)
|
if (err)
|
||||||
goto exit_free_emma;
|
goto exit_free_emma;
|
||||||
|
@ -1459,6 +1420,8 @@ static int __devinit mx2_camera_probe(struct platform_device *pdev)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
exit_free_emma:
|
exit_free_emma:
|
||||||
|
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
|
||||||
|
eallocctx:
|
||||||
if (cpu_is_mx27()) {
|
if (cpu_is_mx27()) {
|
||||||
free_irq(pcdev->irq_emma, pcdev);
|
free_irq(pcdev->irq_emma, pcdev);
|
||||||
clk_disable(pcdev->clk_emma);
|
clk_disable(pcdev->clk_emma);
|
||||||
|
@ -1496,6 +1459,8 @@ static int __devexit mx2_camera_remove(struct platform_device *pdev)
|
||||||
|
|
||||||
soc_camera_host_unregister(&pcdev->soc_host);
|
soc_camera_host_unregister(&pcdev->soc_host);
|
||||||
|
|
||||||
|
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
|
||||||
|
|
||||||
iounmap(pcdev->base_csi);
|
iounmap(pcdev->base_csi);
|
||||||
|
|
||||||
if (cpu_is_mx27()) {
|
if (cpu_is_mx27()) {
|
||||||
|
|
Loading…
Reference in New Issue