[media] media: davinci: vpbe: migrate driver to videobuf2

This patch migrates VPBE display driver to videobuf2 framework.

Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
Signed-off-by: Manjunath Hadli <manjunath.hadli@ti.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Lad, Prabhakar 2012-10-22 09:27:13 -03:00 committed by Mauro Carvalho Chehab
parent baa29837a7
commit 13fc23d306
3 changed files with 188 additions and 125 deletions

View File

@ -101,7 +101,7 @@ config VIDEO_DM644X_VPBE
tristate "DM644X VPBE HW module"
depends on ARCH_DAVINCI_DM644x
select VIDEO_VPSS_SYSTEM
select VIDEOBUF_DMA_CONTIG
select VIDEOBUF2_DMA_CONTIG
help
Enables VPBE modules used for display on a DM644x
SoC.

View File

@ -47,6 +47,9 @@ static int debug;
module_param(debug, int, 0644);
static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
struct vpbe_layer *layer);
static int venc_is_second_field(struct vpbe_display *disp_dev)
{
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
@ -73,10 +76,11 @@ static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
if (layer->cur_frm == layer->next_frm)
return;
ktime_get_ts(&timevalue);
layer->cur_frm->ts.tv_sec = timevalue.tv_sec;
layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC;
layer->cur_frm->state = VIDEOBUF_DONE;
wake_up_interruptible(&layer->cur_frm->done);
layer->cur_frm->vb.v4l2_buf.timestamp.tv_sec =
timevalue.tv_sec;
layer->cur_frm->vb.v4l2_buf.timestamp.tv_usec =
timevalue.tv_nsec / NSEC_PER_USEC;
vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_DONE);
/* Make cur_frm pointing to next_frm */
layer->cur_frm = layer->next_frm;
}
@ -99,16 +103,14 @@ static void vpbe_isr_odd_field(struct vpbe_display *disp_obj,
* otherwise hold on current frame
* Get next from the buffer queue
*/
layer->next_frm = list_entry(
layer->dma_queue.next,
struct videobuf_buffer,
queue);
layer->next_frm = list_entry(layer->dma_queue.next,
struct vpbe_disp_buffer, list);
/* Remove that from the buffer queue */
list_del(&layer->next_frm->queue);
list_del(&layer->next_frm->list);
spin_unlock(&disp_obj->dma_queue_lock);
/* Mark state of the frame to active */
layer->next_frm->state = VIDEOBUF_ACTIVE;
addr = videobuf_to_dma_contig(layer->next_frm);
layer->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
addr = vb2_dma_contig_plane_dma_addr(&layer->next_frm->vb, 0);
osd_device->ops.start_layer(osd_device,
layer->layer_info.id,
addr,
@ -199,39 +201,29 @@ static irqreturn_t venc_isr(int irq, void *arg)
/*
* vpbe_buffer_prepare()
* This is the callback function called from videobuf_qbuf() function
* This is the callback function called from vb2_qbuf() function
* the buffer is prepared and user space virtual address is converted into
* physical address
*/
static int vpbe_buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
static int vpbe_buffer_prepare(struct vb2_buffer *vb)
{
struct vpbe_fh *fh = q->priv_data;
struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_queue *q = vb->vb2_queue;
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
unsigned long addr;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe_buffer_prepare\n");
/* If buffer is not initialized, initialize it */
if (VIDEOBUF_NEEDS_INIT == vb->state) {
vb->width = layer->pix_fmt.width;
vb->height = layer->pix_fmt.height;
vb->size = layer->pix_fmt.sizeimage;
vb->field = field;
ret = videobuf_iolock(q, vb, NULL);
if (ret < 0) {
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \
user address\n");
if (vb->state != VB2_BUF_STATE_ACTIVE &&
vb->state != VB2_BUF_STATE_PREPARED) {
vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage);
if (vb2_plane_vaddr(vb, 0) &&
vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
return -EINVAL;
}
addr = videobuf_to_dma_contig(vb);
addr = vb2_dma_contig_plane_dma_addr(vb, 0);
if (q->streaming) {
if (!IS_ALIGNED(addr, 8)) {
v4l2_err(&vpbe_dev->v4l2_dev,
@ -240,7 +232,6 @@ static int vpbe_buffer_prepare(struct videobuf_queue *q,
return -EINVAL;
}
}
vb->state = VIDEOBUF_PREPARED;
}
return 0;
}
@ -249,22 +240,26 @@ static int vpbe_buffer_prepare(struct videobuf_queue *q,
* vpbe_buffer_setup()
* This function allocates memory for the buffers
*/
static int vpbe_buffer_setup(struct videobuf_queue *q,
unsigned int *count,
unsigned int *size)
static int
vpbe_buffer_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
/* Get the file handle object and layer object */
struct vpbe_fh *fh = q->priv_data;
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
*size = layer->pix_fmt.sizeimage;
/* Store number of buffers allocated in numbuffer member */
if (*count < VPBE_DEFAULT_NUM_BUFS)
*count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
if (*nbuffers < VPBE_DEFAULT_NUM_BUFS)
*nbuffers = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
*nplanes = 1;
sizes[0] = layer->pix_fmt.sizeimage;
alloc_ctxs[0] = layer->alloc_ctx;
return 0;
}
@ -273,11 +268,12 @@ static int vpbe_buffer_setup(struct videobuf_queue *q,
* vpbe_buffer_queue()
* This function adds the buffer to DMA queue
*/
static void vpbe_buffer_queue(struct videobuf_queue *q,
struct videobuf_buffer *vb)
static void vpbe_buffer_queue(struct vb2_buffer *vb)
{
/* Get the file handle object and layer object */
struct vpbe_fh *fh = q->priv_data;
struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vpbe_disp_buffer *buf = container_of(vb,
struct vpbe_disp_buffer, vb);
struct vpbe_layer *layer = fh->layer;
struct vpbe_display *disp = fh->disp_dev;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
@ -288,39 +284,125 @@ static void vpbe_buffer_queue(struct videobuf_queue *q,
/* add the buffer to the DMA queue */
spin_lock_irqsave(&disp->dma_queue_lock, flags);
list_add_tail(&vb->queue, &layer->dma_queue);
list_add_tail(&buf->list, &layer->dma_queue);
spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
/* Change state of the buffer */
vb->state = VIDEOBUF_QUEUED;
}
/*
* vpbe_buffer_release()
* This function is called from the videobuf layer to free memory allocated to
* vpbe_buf_cleanup()
* This function is called from the vb2 layer to free memory allocated to
* the buffers
*/
static void vpbe_buffer_release(struct videobuf_queue *q,
struct videobuf_buffer *vb)
static void vpbe_buf_cleanup(struct vb2_buffer *vb)
{
/* Get the file handle object and layer object */
struct vpbe_fh *fh = q->priv_data;
struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
struct vpbe_disp_buffer *buf = container_of(vb,
struct vpbe_disp_buffer, vb);
unsigned long flags;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe_buffer_release\n");
"vpbe_buf_cleanup\n");
if (V4L2_MEMORY_USERPTR != layer->memory)
videobuf_dma_contig_free(q, vb);
vb->state = VIDEOBUF_NEEDS_INIT;
spin_lock_irqsave(&layer->irqlock, flags);
if (vb->state == VB2_BUF_STATE_ACTIVE)
list_del_init(&buf->list);
spin_unlock_irqrestore(&layer->irqlock, flags);
}
static struct videobuf_queue_ops video_qops = {
.buf_setup = vpbe_buffer_setup,
static void vpbe_wait_prepare(struct vb2_queue *vq)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
mutex_unlock(&layer->opslock);
}
static void vpbe_wait_finish(struct vb2_queue *vq)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
mutex_lock(&layer->opslock);
}
static int vpbe_buffer_init(struct vb2_buffer *vb)
{
struct vpbe_disp_buffer *buf = container_of(vb,
struct vpbe_disp_buffer, vb);
INIT_LIST_HEAD(&buf->list);
return 0;
}
static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
int ret;
/* If buffer queue is empty, return error */
if (list_empty(&layer->dma_queue)) {
v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
return -EINVAL;
}
/* Get the next frame from the buffer queue */
layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
struct vpbe_disp_buffer, list);
/* Remove buffer from the buffer queue */
list_del(&layer->cur_frm->list);
/* Mark state of the current frame to active */
layer->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
/* Initialize field_id and started member */
layer->field_id = 0;
/* Set parameters in OSD and VENC */
ret = vpbe_set_osd_display_params(fh->disp_dev, layer);
if (ret < 0)
return ret;
/*
* if request format is yuv420 semiplanar, need to
* enable both video windows
*/
layer->started = 1;
layer->layer_first_int = 1;
return ret;
}
static int vpbe_stop_streaming(struct vb2_queue *vq)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
if (!vb2_is_streaming(vq))
return 0;
/* release all active buffers */
while (!list_empty(&layer->dma_queue)) {
layer->next_frm = list_entry(layer->dma_queue.next,
struct vpbe_disp_buffer, list);
list_del(&layer->next_frm->list);
vb2_buffer_done(&layer->next_frm->vb, VB2_BUF_STATE_ERROR);
}
return 0;
}
static struct vb2_ops video_qops = {
.queue_setup = vpbe_buffer_queue_setup,
.wait_prepare = vpbe_wait_prepare,
.wait_finish = vpbe_wait_finish,
.buf_init = vpbe_buffer_init,
.buf_prepare = vpbe_buffer_prepare,
.start_streaming = vpbe_start_streaming,
.stop_streaming = vpbe_stop_streaming,
.buf_cleanup = vpbe_buf_cleanup,
.buf_queue = vpbe_buffer_queue,
.buf_release = vpbe_buffer_release,
};
static
@ -345,7 +427,7 @@ static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev,
unsigned long addr;
int ret;
addr = videobuf_to_dma_contig(layer->cur_frm);
addr = vb2_dma_contig_plane_dma_addr(&layer->cur_frm->vb, 0);
/* Set address in the display registers */
osd_device->ops.start_layer(osd_device,
layer->layer_info.id,
@ -1161,7 +1243,7 @@ static int vpbe_display_streamoff(struct file *file, void *priv,
osd_device->ops.disable_layer(osd_device,
layer->layer_info.id);
layer->started = 0;
ret = videobuf_streamoff(&layer->buffer_queue);
ret = vb2_streamoff(&layer->buffer_queue, buf_type);
return ret;
}
@ -1199,46 +1281,15 @@ static int vpbe_display_streamon(struct file *file, void *priv,
}
/*
* Call videobuf_streamon to start streaming
* Call vb2_streamon to start streaming
* in videobuf
*/
ret = videobuf_streamon(&layer->buffer_queue);
ret = vb2_streamon(&layer->buffer_queue, buf_type);
if (ret) {
v4l2_err(&vpbe_dev->v4l2_dev,
"error in videobuf_streamon\n");
"error in vb2_streamon\n");
return ret;
}
/* If buffer queue is empty, return error */
if (list_empty(&layer->dma_queue)) {
v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
goto streamoff;
}
/* Get the next frame from the buffer queue */
layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
struct videobuf_buffer, queue);
/* Remove buffer from the buffer queue */
list_del(&layer->cur_frm->queue);
/* Mark state of the current frame to active */
layer->cur_frm->state = VIDEOBUF_ACTIVE;
/* Initialize field_id and started member */
layer->field_id = 0;
/* Set parameters in OSD and VENC */
ret = vpbe_set_osd_display_params(disp_dev, layer);
if (ret < 0)
goto streamoff;
/*
* if request format is yuv420 semiplanar, need to
* enable both video windows
*/
layer->started = 1;
layer->layer_first_int = 1;
return ret;
streamoff:
ret = videobuf_streamoff(&layer->buffer_queue);
return ret;
}
@ -1265,10 +1316,10 @@ static int vpbe_display_dqbuf(struct file *file, void *priv,
}
if (file->f_flags & O_NONBLOCK)
/* Call videobuf_dqbuf for non blocking mode */
ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1);
ret = vb2_dqbuf(&layer->buffer_queue, buf, 1);
else
/* Call videobuf_dqbuf for blocking mode */
ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0);
ret = vb2_dqbuf(&layer->buffer_queue, buf, 0);
return ret;
}
@ -1295,7 +1346,7 @@ static int vpbe_display_qbuf(struct file *file, void *priv,
return -EACCES;
}
return videobuf_qbuf(&layer->buffer_queue, p);
return vb2_qbuf(&layer->buffer_queue, p);
}
static int vpbe_display_querybuf(struct file *file, void *priv,
@ -1304,7 +1355,6 @@ static int vpbe_display_querybuf(struct file *file, void *priv,
struct vpbe_fh *fh = file->private_data;
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"VIDIOC_QUERYBUF, layer id = %d\n",
@ -1314,11 +1364,8 @@ static int vpbe_display_querybuf(struct file *file, void *priv,
v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
return -EINVAL;
}
/* Call videobuf_querybuf to get information */
ret = videobuf_querybuf(&layer->buffer_queue, buf);
return ret;
/* Call vb2_querybuf to get information */
return vb2_querybuf(&layer->buffer_queue, buf);
}
static int vpbe_display_reqbufs(struct file *file, void *priv,
@ -1327,8 +1374,8 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
struct vpbe_fh *fh = file->private_data;
struct vpbe_layer *layer = fh->layer;
struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
struct vb2_queue *q;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
@ -1342,15 +1389,26 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
return -EBUSY;
}
/* Initialize videobuf queue as per the buffer type */
videobuf_queue_dma_contig_init(&layer->buffer_queue,
&video_qops,
vpbe_dev->pdev,
&layer->irqlock,
V4L2_BUF_TYPE_VIDEO_OUTPUT,
layer->pix_fmt.field,
sizeof(struct videobuf_buffer),
fh, NULL);
layer->alloc_ctx = vb2_dma_contig_init_ctx(vpbe_dev->pdev);
if (!layer->alloc_ctx) {
v4l2_err(&vpbe_dev->v4l2_dev, "Failed to get the context\n");
return -EINVAL;
}
q = &layer->buffer_queue;
memset(q, 0, sizeof(*q));
q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
q->io_modes = VB2_MMAP | VB2_USERPTR;
q->drv_priv = fh;
q->ops = &video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct vpbe_disp_buffer);
ret = vb2_queue_init(q);
if (ret) {
v4l2_err(&vpbe_dev->v4l2_dev, "vb2_queue_init() failed\n");
vb2_dma_contig_cleanup_ctx(layer->alloc_ctx);
return ret;
}
/* Set io allowed member of file handle to TRUE */
fh->io_allowed = 1;
/* Increment io usrs member of layer object to 1 */
@ -1360,9 +1418,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv,
/* Initialize buffer queue */
INIT_LIST_HEAD(&layer->dma_queue);
/* Allocate buffers */
ret = videobuf_reqbufs(&layer->buffer_queue, req_buf);
return ret;
return vb2_reqbufs(q, req_buf);
}
/*
@ -1381,7 +1437,7 @@ static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
if (mutex_lock_interruptible(&layer->opslock))
return -ERESTARTSYS;
ret = videobuf_mmap_mapper(&layer->buffer_queue, vma);
ret = vb2_mmap(&layer->buffer_queue, vma);
mutex_unlock(&layer->opslock);
return ret;
}
@ -1398,7 +1454,7 @@ static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
if (layer->started) {
mutex_lock(&layer->opslock);
err = videobuf_poll_stream(filep, &layer->buffer_queue, wait);
err = vb2_poll(&layer->buffer_queue, filep, wait);
mutex_unlock(&layer->opslock);
}
return err;
@ -1488,8 +1544,8 @@ static int vpbe_display_release(struct file *file)
layer->layer_info.id);
layer->started = 0;
/* Free buffers allocated */
videobuf_queue_cancel(&layer->buffer_queue);
videobuf_mmap_free(&layer->buffer_queue);
vb2_queue_release(&layer->buffer_queue);
vb2_dma_contig_cleanup_ctx(&layer->buffer_queue);
}
/* Decrement layer usrs counter */

View File

@ -16,7 +16,7 @@
/* Header files */
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/videobuf-dma-contig.h>
#include <media/videobuf2-dma-contig.h>
#include <media/davinci/vpbe_types.h>
#include <media/davinci/vpbe_osd.h>
#include <media/davinci/vpbe.h>
@ -62,6 +62,11 @@ struct display_layer_info {
enum osd_v_exp_ratio v_exp;
};
struct vpbe_disp_buffer {
struct vb2_buffer vb;
struct list_head list;
};
/* vpbe display object structure */
struct vpbe_layer {
/* number of buffers in fbuffers */
@ -69,13 +74,15 @@ struct vpbe_layer {
/* Pointer to the vpbe_display */
struct vpbe_display *disp_dev;
/* Pointer pointing to current v4l2_buffer */
struct videobuf_buffer *cur_frm;
struct vpbe_disp_buffer *cur_frm;
/* Pointer pointing to next v4l2_buffer */
struct videobuf_buffer *next_frm;
struct vpbe_disp_buffer *next_frm;
/* videobuf specific parameters
* Buffer queue used in video-buf
*/
struct videobuf_queue buffer_queue;
struct vb2_queue buffer_queue;
/* allocator-specific contexts for each plane */
struct vb2_alloc_ctx *alloc_ctx;
/* Queue of filled frames */
struct list_head dma_queue;
/* Used in video-buf */