mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
[media] davinci: vpif display: migrate driver to videobuf2
This patch migrates VPIF 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:
parent
60aa38d87d
commit
2401dd25c7
3 changed files with 295 additions and 325 deletions
|
@ -1,7 +1,7 @@
|
|||
config DISPLAY_DAVINCI_DM646X_EVM
|
||||
tristate "DM646x EVM Video Display"
|
||||
depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
|
||||
select VIDEOBUF_DMA_CONTIG
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select VIDEO_DAVINCI_VPIF
|
||||
select VIDEO_ADV7343
|
||||
select VIDEO_THS7303
|
||||
|
|
|
@ -82,89 +82,38 @@ static struct vpif_config_params config_params = {
|
|||
|
||||
static struct vpif_device vpif_obj = { {NULL} };
|
||||
static struct device *vpif_dev;
|
||||
static void vpif_calculate_offsets(struct channel_obj *ch);
|
||||
static void vpif_config_addr(struct channel_obj *ch, int muxmode);
|
||||
|
||||
/*
|
||||
* vpif_uservirt_to_phys: This function is used to convert user
|
||||
* space virtual address to physical address.
|
||||
*/
|
||||
static u32 vpif_uservirt_to_phys(u32 virtp)
|
||||
{
|
||||
struct mm_struct *mm = current->mm;
|
||||
unsigned long physp = 0;
|
||||
struct vm_area_struct *vma;
|
||||
|
||||
vma = find_vma(mm, virtp);
|
||||
|
||||
/* For kernel direct-mapped memory, take the easy way */
|
||||
if (virtp >= PAGE_OFFSET) {
|
||||
physp = virt_to_phys((void *)virtp);
|
||||
} else if (vma && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) {
|
||||
/* this will catch, kernel-allocated, mmaped-to-usermode addr */
|
||||
physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
|
||||
} else {
|
||||
/* otherwise, use get_user_pages() for general userland pages */
|
||||
int res, nr_pages = 1;
|
||||
struct page *pages;
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
|
||||
res = get_user_pages(current, current->mm,
|
||||
virtp, nr_pages, 1, 0, &pages, NULL);
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
|
||||
if (res == nr_pages) {
|
||||
physp = __pa(page_address(&pages[0]) +
|
||||
(virtp & ~PAGE_MASK));
|
||||
} else {
|
||||
vpif_err("get_user_pages failed\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return physp;
|
||||
}
|
||||
|
||||
/*
|
||||
* buffer_prepare: This is the callback function called from videobuf_qbuf()
|
||||
* buffer_prepare: 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 vpif_buffer_prepare(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb,
|
||||
enum v4l2_field field)
|
||||
static int vpif_buffer_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vpif_fh *fh = q->priv_data;
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct vb2_queue *q = vb->vb2_queue;
|
||||
struct common_obj *common;
|
||||
unsigned long addr;
|
||||
|
||||
common = &fh->channel->common[VPIF_VIDEO_INDEX];
|
||||
if (VIDEOBUF_NEEDS_INIT == vb->state) {
|
||||
vb->width = common->width;
|
||||
vb->height = common->height;
|
||||
vb->size = vb->width * vb->height;
|
||||
vb->field = field;
|
||||
}
|
||||
vb->state = VIDEOBUF_PREPARED;
|
||||
if (vb->state != VB2_BUF_STATE_ACTIVE &&
|
||||
vb->state != VB2_BUF_STATE_PREPARED) {
|
||||
vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
|
||||
if (vb2_plane_vaddr(vb, 0) &&
|
||||
vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
|
||||
goto buf_align_exit;
|
||||
|
||||
/* if user pointer memory mechanism is used, get the physical
|
||||
* address of the buffer */
|
||||
if (V4L2_MEMORY_USERPTR == common->memory) {
|
||||
if (!vb->baddr) {
|
||||
vpif_err("buffer_address is 0\n");
|
||||
return -EINVAL;
|
||||
addr = vb2_dma_contig_plane_dma_addr(vb, 0);
|
||||
if (q->streaming &&
|
||||
(V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
|
||||
if (!ISALIGNED(addr + common->ytop_off) ||
|
||||
!ISALIGNED(addr + common->ybtm_off) ||
|
||||
!ISALIGNED(addr + common->ctop_off) ||
|
||||
!ISALIGNED(addr + common->cbtm_off))
|
||||
goto buf_align_exit;
|
||||
}
|
||||
|
||||
vb->boff = vpif_uservirt_to_phys(vb->baddr);
|
||||
if (!ISALIGNED(vb->boff))
|
||||
goto buf_align_exit;
|
||||
}
|
||||
|
||||
addr = vb->boff;
|
||||
if (q->streaming && (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
|
||||
if (!ISALIGNED(addr + common->ytop_off) ||
|
||||
!ISALIGNED(addr + common->ybtm_off) ||
|
||||
!ISALIGNED(addr + common->ctop_off) ||
|
||||
!ISALIGNED(addr + common->cbtm_off))
|
||||
goto buf_align_exit;
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -174,104 +123,251 @@ static int vpif_buffer_prepare(struct videobuf_queue *q,
|
|||
}
|
||||
|
||||
/*
|
||||
* vpif_buffer_setup: This function allocates memory for the buffers
|
||||
* vpif_buffer_queue_setup: This function allocates memory for the buffers
|
||||
*/
|
||||
static int vpif_buffer_setup(struct videobuf_queue *q, unsigned int *count,
|
||||
unsigned int *size)
|
||||
static int vpif_buffer_queue_setup(struct vb2_queue *vq,
|
||||
const struct v4l2_format *fmt,
|
||||
unsigned int *nbuffers, unsigned int *nplanes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct vpif_fh *fh = q->priv_data;
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vq);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
unsigned long size;
|
||||
|
||||
if (V4L2_MEMORY_MMAP != common->memory)
|
||||
return 0;
|
||||
|
||||
*size = config_params.channel_bufsize[ch->channel_id];
|
||||
|
||||
/*
|
||||
* Checking if the buffer size exceeds the available buffer
|
||||
* ycmux_mode = 0 means 1 channel mode HD and
|
||||
* ycmux_mode = 1 means 2 channels mode SD
|
||||
*/
|
||||
if (ch->vpifparams.std_info.ycmux_mode == 0) {
|
||||
if (config_params.video_limit[ch->channel_id])
|
||||
while (*size * *count > (config_params.video_limit[0]
|
||||
+ config_params.video_limit[1]))
|
||||
(*count)--;
|
||||
} else {
|
||||
if (config_params.video_limit[ch->channel_id])
|
||||
while (*size * *count >
|
||||
if (V4L2_MEMORY_MMAP == common->memory) {
|
||||
size = config_params.channel_bufsize[ch->channel_id];
|
||||
/*
|
||||
* Checking if the buffer size exceeds the available buffer
|
||||
* ycmux_mode = 0 means 1 channel mode HD and
|
||||
* ycmux_mode = 1 means 2 channels mode SD
|
||||
*/
|
||||
if (ch->vpifparams.std_info.ycmux_mode == 0) {
|
||||
if (config_params.video_limit[ch->channel_id])
|
||||
while (size * *nbuffers >
|
||||
(config_params.video_limit[0]
|
||||
+ config_params.video_limit[1]))
|
||||
(*nbuffers)--;
|
||||
} else {
|
||||
if (config_params.video_limit[ch->channel_id])
|
||||
while (size * *nbuffers >
|
||||
config_params.video_limit[ch->channel_id])
|
||||
(*count)--;
|
||||
(*nbuffers)--;
|
||||
}
|
||||
} else {
|
||||
size = common->fmt.fmt.pix.sizeimage;
|
||||
}
|
||||
|
||||
if (*count < config_params.min_numbuffers)
|
||||
*count = config_params.min_numbuffers;
|
||||
if (*nbuffers < config_params.min_numbuffers)
|
||||
*nbuffers = config_params.min_numbuffers;
|
||||
|
||||
*nplanes = 1;
|
||||
sizes[0] = size;
|
||||
alloc_ctxs[0] = common->alloc_ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* vpif_buffer_queue: This function adds the buffer to DMA queue
|
||||
*/
|
||||
static void vpif_buffer_queue(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
static void vpif_buffer_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vpif_fh *fh = q->priv_data;
|
||||
struct common_obj *common;
|
||||
|
||||
common = &fh->channel->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
/* add the buffer to the DMA queue */
|
||||
list_add_tail(&vb->queue, &common->dma_queue);
|
||||
vb->state = VIDEOBUF_QUEUED;
|
||||
}
|
||||
|
||||
/*
|
||||
* vpif_buffer_release: This function is called from the videobuf layer to
|
||||
* free memory allocated to the buffers
|
||||
*/
|
||||
static void vpif_buffer_release(struct videobuf_queue *q,
|
||||
struct videobuf_buffer *vb)
|
||||
{
|
||||
struct vpif_fh *fh = q->priv_data;
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct vpif_disp_buffer *buf = container_of(vb,
|
||||
struct vpif_disp_buffer, vb);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
unsigned int buf_size = 0;
|
||||
|
||||
common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
videobuf_dma_contig_free(q, vb);
|
||||
vb->state = VIDEOBUF_NEEDS_INIT;
|
||||
|
||||
if (V4L2_MEMORY_MMAP != common->memory)
|
||||
return;
|
||||
|
||||
buf_size = config_params.channel_bufsize[ch->channel_id];
|
||||
/* add the buffer to the DMA queue */
|
||||
list_add_tail(&buf->list, &common->dma_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
* vpif_buf_cleanup: This function is called from the videobuf2 layer to
|
||||
* free memory allocated to the buffers
|
||||
*/
|
||||
static void vpif_buf_cleanup(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct vpif_disp_buffer *buf = container_of(vb,
|
||||
struct vpif_disp_buffer, vb);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
unsigned long flags;
|
||||
|
||||
common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
spin_lock_irqsave(&common->irqlock, flags);
|
||||
if (vb->state == VB2_BUF_STATE_ACTIVE)
|
||||
list_del_init(&buf->list);
|
||||
spin_unlock_irqrestore(&common->irqlock, flags);
|
||||
}
|
||||
|
||||
static void vpif_wait_prepare(struct vb2_queue *vq)
|
||||
{
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vq);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
|
||||
common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
mutex_unlock(&common->lock);
|
||||
}
|
||||
|
||||
static void vpif_wait_finish(struct vb2_queue *vq)
|
||||
{
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vq);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
|
||||
common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
mutex_lock(&common->lock);
|
||||
}
|
||||
|
||||
static int vpif_buffer_init(struct vb2_buffer *vb)
|
||||
{
|
||||
struct vpif_disp_buffer *buf = container_of(vb,
|
||||
struct vpif_disp_buffer, vb);
|
||||
|
||||
INIT_LIST_HEAD(&buf->list);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct videobuf_queue_ops video_qops = {
|
||||
.buf_setup = vpif_buffer_setup,
|
||||
.buf_prepare = vpif_buffer_prepare,
|
||||
.buf_queue = vpif_buffer_queue,
|
||||
.buf_release = vpif_buffer_release,
|
||||
};
|
||||
static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
|
||||
|
||||
static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||
{
|
||||
struct vpif_display_config *vpif_config_data =
|
||||
vpif_dev->platform_data;
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vq);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
struct vpif_params *vpif = &ch->vpifparams;
|
||||
unsigned long addr = 0;
|
||||
int ret;
|
||||
|
||||
/* If buffer queue is empty, return error */
|
||||
if (list_empty(&common->dma_queue)) {
|
||||
vpif_err("buffer queue is empty\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Get the next frame from the buffer queue */
|
||||
common->next_frm = common->cur_frm =
|
||||
list_entry(common->dma_queue.next,
|
||||
struct vpif_disp_buffer, list);
|
||||
|
||||
list_del(&common->cur_frm->list);
|
||||
/* Mark state of the current frame to active */
|
||||
common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
|
||||
|
||||
/* Initialize field_id and started member */
|
||||
ch->field_id = 0;
|
||||
common->started = 1;
|
||||
addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
|
||||
/* Calculate the offset for Y and C data in the buffer */
|
||||
vpif_calculate_offsets(ch);
|
||||
|
||||
if ((ch->vpifparams.std_info.frm_fmt &&
|
||||
((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
|
||||
&& (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
|
||||
|| (!ch->vpifparams.std_info.frm_fmt
|
||||
&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
|
||||
vpif_err("conflict in field format and std format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clock settings */
|
||||
ret =
|
||||
vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
|
||||
ch->vpifparams.std_info.hd_sd);
|
||||
if (ret < 0) {
|
||||
vpif_err("can't set clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set the parameters and addresses */
|
||||
ret = vpif_set_video_params(vpif, ch->channel_id + 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
common->started = ret;
|
||||
vpif_config_addr(ch, ret);
|
||||
common->set_addr((addr + common->ytop_off),
|
||||
(addr + common->ybtm_off),
|
||||
(addr + common->ctop_off),
|
||||
(addr + common->cbtm_off));
|
||||
|
||||
/* Set interrupt for both the fields in VPIF
|
||||
Register enable channel in VPIF register */
|
||||
if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
|
||||
channel2_intr_assert();
|
||||
channel2_intr_enable(1);
|
||||
enable_channel2(1);
|
||||
}
|
||||
|
||||
if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
|
||||
|| (common->started == 2)) {
|
||||
channel3_intr_assert();
|
||||
channel3_intr_enable(1);
|
||||
enable_channel3(1);
|
||||
}
|
||||
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* abort streaming and wait for last buffer */
|
||||
static int vpif_stop_streaming(struct vb2_queue *vq)
|
||||
{
|
||||
struct vpif_fh *fh = vb2_get_drv_priv(vq);
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
|
||||
if (!vb2_is_streaming(vq))
|
||||
return 0;
|
||||
|
||||
common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
/* release all active buffers */
|
||||
while (!list_empty(&common->dma_queue)) {
|
||||
common->next_frm = list_entry(common->dma_queue.next,
|
||||
struct vpif_disp_buffer, list);
|
||||
list_del(&common->next_frm->list);
|
||||
vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vb2_ops video_qops = {
|
||||
.queue_setup = vpif_buffer_queue_setup,
|
||||
.wait_prepare = vpif_wait_prepare,
|
||||
.wait_finish = vpif_wait_finish,
|
||||
.buf_init = vpif_buffer_init,
|
||||
.buf_prepare = vpif_buffer_prepare,
|
||||
.start_streaming = vpif_start_streaming,
|
||||
.stop_streaming = vpif_stop_streaming,
|
||||
.buf_cleanup = vpif_buf_cleanup,
|
||||
.buf_queue = vpif_buffer_queue,
|
||||
};
|
||||
|
||||
static void process_progressive_mode(struct common_obj *common)
|
||||
{
|
||||
unsigned long addr = 0;
|
||||
|
||||
/* Get the next buffer from buffer queue */
|
||||
common->next_frm = list_entry(common->dma_queue.next,
|
||||
struct videobuf_buffer, queue);
|
||||
struct vpif_disp_buffer, list);
|
||||
/* Remove that buffer from the buffer queue */
|
||||
list_del(&common->next_frm->queue);
|
||||
list_del(&common->next_frm->list);
|
||||
/* Mark status of the buffer as active */
|
||||
common->next_frm->state = VIDEOBUF_ACTIVE;
|
||||
common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
|
||||
|
||||
/* Set top and bottom field addrs in VPIF registers */
|
||||
addr = videobuf_to_dma_contig(common->next_frm);
|
||||
addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0);
|
||||
common->set_addr(addr + common->ytop_off,
|
||||
addr + common->ybtm_off,
|
||||
addr + common->ctop_off,
|
||||
|
@ -289,11 +385,10 @@ static void process_interlaced_mode(int fid, struct common_obj *common)
|
|||
/* one frame is displayed If next frame is
|
||||
* available, release cur_frm and move on */
|
||||
/* Copy frame display time */
|
||||
do_gettimeofday(&common->cur_frm->ts);
|
||||
do_gettimeofday(&common->cur_frm->vb.v4l2_buf.timestamp);
|
||||
/* Change status of the cur_frm */
|
||||
common->cur_frm->state = VIDEOBUF_DONE;
|
||||
/* unlock semaphore on cur_frm */
|
||||
wake_up_interruptible(&common->cur_frm->done);
|
||||
vb2_buffer_done(&common->cur_frm->vb,
|
||||
VB2_BUF_STATE_DONE);
|
||||
/* Make cur_frm pointing to next_frm */
|
||||
common->cur_frm = common->next_frm;
|
||||
|
||||
|
@ -344,9 +439,10 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
|
|||
if (!channel_first_int[i][channel_id]) {
|
||||
/* Mark status of the cur_frm to
|
||||
* done and unlock semaphore on it */
|
||||
do_gettimeofday(&common->cur_frm->ts);
|
||||
common->cur_frm->state = VIDEOBUF_DONE;
|
||||
wake_up_interruptible(&common->cur_frm->done);
|
||||
do_gettimeofday(&common->cur_frm->vb.
|
||||
v4l2_buf.timestamp);
|
||||
vb2_buffer_done(&common->cur_frm->vb,
|
||||
VB2_BUF_STATE_DONE);
|
||||
/* Make cur_frm pointing to next_frm */
|
||||
common->cur_frm = common->next_frm;
|
||||
}
|
||||
|
@ -464,10 +560,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
|
|||
vid_ch->buf_field = common->fmt.fmt.pix.field;
|
||||
}
|
||||
|
||||
if (V4L2_MEMORY_USERPTR == common->memory)
|
||||
sizeimage = common->fmt.fmt.pix.sizeimage;
|
||||
else
|
||||
sizeimage = config_params.channel_bufsize[ch->channel_id];
|
||||
sizeimage = common->fmt.fmt.pix.sizeimage;
|
||||
|
||||
hpitch = common->fmt.fmt.pix.bytesperline;
|
||||
vpitch = sizeimage / (hpitch * 2);
|
||||
|
@ -544,10 +637,7 @@ static int vpif_check_format(struct channel_obj *ch,
|
|||
if (pixfmt->bytesperline <= 0)
|
||||
goto invalid_pitch_exit;
|
||||
|
||||
if (V4L2_MEMORY_USERPTR == common->memory)
|
||||
sizeimage = pixfmt->sizeimage;
|
||||
else
|
||||
sizeimage = config_params.channel_bufsize[ch->channel_id];
|
||||
sizeimage = pixfmt->sizeimage;
|
||||
|
||||
if (vpif_update_resolution(ch))
|
||||
return -EINVAL;
|
||||
|
@ -604,7 +694,7 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
|
|||
|
||||
vpif_dbg(2, debug, "vpif_mmap\n");
|
||||
|
||||
return videobuf_mmap_mapper(&common->buffer_queue, vma);
|
||||
return vb2_mmap(&common->buffer_queue, vma);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -617,7 +707,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table *wait)
|
|||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
if (common->started)
|
||||
return videobuf_poll_stream(filep, &common->buffer_queue, wait);
|
||||
return vb2_poll(&common->buffer_queue, filep, wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -686,9 +776,11 @@ static int vpif_release(struct file *filep)
|
|||
channel3_intr_enable(0);
|
||||
}
|
||||
common->started = 0;
|
||||
|
||||
/* Free buffers allocated */
|
||||
videobuf_queue_cancel(&common->buffer_queue);
|
||||
videobuf_mmap_free(&common->buffer_queue);
|
||||
vb2_queue_release(&common->buffer_queue);
|
||||
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
|
||||
|
||||
common->numbuffers =
|
||||
config_params.numbuffers[ch->channel_id];
|
||||
}
|
||||
|
@ -827,6 +919,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
|
|||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common;
|
||||
enum v4l2_field field;
|
||||
struct vb2_queue *q;
|
||||
u8 index = 0;
|
||||
|
||||
/* This file handle has not initialized the channel,
|
||||
|
@ -848,7 +941,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
|
|||
|
||||
if (common->fmt.type != reqbuf->type || !vpif_dev)
|
||||
return -EINVAL;
|
||||
|
||||
if (0 != common->io_usrs)
|
||||
return -EBUSY;
|
||||
|
||||
|
@ -860,14 +952,21 @@ static int vpif_reqbufs(struct file *file, void *priv,
|
|||
} else {
|
||||
field = V4L2_VBI_INTERLACED;
|
||||
}
|
||||
/* Initialize videobuf2 queue as per the buffer type */
|
||||
common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
|
||||
if (!common->alloc_ctx) {
|
||||
vpif_err("Failed to get the context\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
q = &common->buffer_queue;
|
||||
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 vpif_disp_buffer);
|
||||
|
||||
/* Initialize videobuf queue as per the buffer type */
|
||||
videobuf_queue_dma_contig_init(&common->buffer_queue,
|
||||
&video_qops, vpif_dev,
|
||||
&common->irqlock,
|
||||
reqbuf->type, field,
|
||||
sizeof(struct videobuf_buffer), fh,
|
||||
&common->lock);
|
||||
vb2_queue_init(q);
|
||||
|
||||
/* Set io allowed member of file handle to TRUE */
|
||||
fh->io_allowed[index] = 1;
|
||||
|
@ -876,9 +975,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
|
|||
/* Store type of memory requested in channel object */
|
||||
common->memory = reqbuf->memory;
|
||||
INIT_LIST_HEAD(&common->dma_queue);
|
||||
|
||||
/* Allocate buffers */
|
||||
return videobuf_reqbufs(&common->buffer_queue, reqbuf);
|
||||
return vb2_reqbufs(&common->buffer_queue, reqbuf);
|
||||
}
|
||||
|
||||
static int vpif_querybuf(struct file *file, void *priv,
|
||||
|
@ -891,22 +989,25 @@ static int vpif_querybuf(struct file *file, void *priv,
|
|||
if (common->fmt.type != tbuf->type)
|
||||
return -EINVAL;
|
||||
|
||||
return videobuf_querybuf(&common->buffer_queue, tbuf);
|
||||
return vb2_querybuf(&common->buffer_queue, tbuf);
|
||||
}
|
||||
|
||||
static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
||||
{
|
||||
struct vpif_fh *fh = NULL;
|
||||
struct channel_obj *ch = NULL;
|
||||
struct common_obj *common = NULL;
|
||||
|
||||
struct vpif_fh *fh = priv;
|
||||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
struct v4l2_buffer tbuf = *buf;
|
||||
struct videobuf_buffer *buf1;
|
||||
unsigned long addr = 0;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
if (!buf || !priv)
|
||||
return -EINVAL;
|
||||
|
||||
if (common->fmt.type != tbuf.type)
|
||||
fh = priv;
|
||||
ch = fh->channel;
|
||||
if (!ch)
|
||||
return -EINVAL;
|
||||
|
||||
common = &(ch->common[VPIF_VIDEO_INDEX]);
|
||||
if (common->fmt.type != buf->type)
|
||||
return -EINVAL;
|
||||
|
||||
if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
|
||||
|
@ -914,73 +1015,7 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
|
|||
return -EACCES;
|
||||
}
|
||||
|
||||
if (!(list_empty(&common->dma_queue)) ||
|
||||
(common->cur_frm != common->next_frm) ||
|
||||
!(common->started) ||
|
||||
(common->started && (0 == ch->field_id)))
|
||||
return videobuf_qbuf(&common->buffer_queue, buf);
|
||||
|
||||
/* bufferqueue is empty store buffer address in VPIF registers */
|
||||
mutex_lock(&common->buffer_queue.vb_lock);
|
||||
buf1 = common->buffer_queue.bufs[tbuf.index];
|
||||
if (buf1->memory != tbuf.memory) {
|
||||
vpif_err("invalid buffer type\n");
|
||||
goto qbuf_exit;
|
||||
}
|
||||
|
||||
if ((buf1->state == VIDEOBUF_QUEUED) ||
|
||||
(buf1->state == VIDEOBUF_ACTIVE)) {
|
||||
vpif_err("invalid state\n");
|
||||
goto qbuf_exit;
|
||||
}
|
||||
|
||||
switch (buf1->memory) {
|
||||
case V4L2_MEMORY_MMAP:
|
||||
if (buf1->baddr == 0)
|
||||
goto qbuf_exit;
|
||||
break;
|
||||
|
||||
case V4L2_MEMORY_USERPTR:
|
||||
if (tbuf.length < buf1->bsize)
|
||||
goto qbuf_exit;
|
||||
|
||||
if ((VIDEOBUF_NEEDS_INIT != buf1->state)
|
||||
&& (buf1->baddr != tbuf.m.userptr)) {
|
||||
vpif_buffer_release(&common->buffer_queue, buf1);
|
||||
buf1->baddr = tbuf.m.userptr;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
goto qbuf_exit;
|
||||
}
|
||||
|
||||
local_irq_save(flags);
|
||||
ret = vpif_buffer_prepare(&common->buffer_queue, buf1,
|
||||
common->buffer_queue.field);
|
||||
if (ret < 0) {
|
||||
local_irq_restore(flags);
|
||||
goto qbuf_exit;
|
||||
}
|
||||
|
||||
buf1->state = VIDEOBUF_ACTIVE;
|
||||
addr = buf1->boff;
|
||||
common->next_frm = buf1;
|
||||
if (tbuf.type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
|
||||
common->set_addr((addr + common->ytop_off),
|
||||
(addr + common->ybtm_off),
|
||||
(addr + common->ctop_off),
|
||||
(addr + common->cbtm_off));
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
list_add_tail(&buf1->stream, &common->buffer_queue.stream);
|
||||
mutex_unlock(&common->buffer_queue.vb_lock);
|
||||
return 0;
|
||||
|
||||
qbuf_exit:
|
||||
mutex_unlock(&common->buffer_queue.vb_lock);
|
||||
return -EINVAL;
|
||||
return vb2_qbuf(&common->buffer_queue, buf);
|
||||
}
|
||||
|
||||
static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
|
||||
|
@ -1047,7 +1082,7 @@ static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
|
|||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
|
||||
return videobuf_dqbuf(&common->buffer_queue, p,
|
||||
return vb2_dqbuf(&common->buffer_queue, p,
|
||||
(file->f_flags & O_NONBLOCK));
|
||||
}
|
||||
|
||||
|
@ -1058,10 +1093,6 @@ static int vpif_streamon(struct file *file, void *priv,
|
|||
struct channel_obj *ch = fh->channel;
|
||||
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
|
||||
struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
|
||||
struct vpif_params *vpif = &ch->vpifparams;
|
||||
struct vpif_display_config *vpif_config_data =
|
||||
vpif_dev->platform_data;
|
||||
unsigned long addr = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
|
@ -1093,82 +1124,13 @@ static int vpif_streamon(struct file *file, void *priv,
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/* Call videobuf_streamon to start streaming in videobuf */
|
||||
ret = videobuf_streamon(&common->buffer_queue);
|
||||
/* Call vb2_streamon to start streaming in videobuf2 */
|
||||
ret = vb2_streamon(&common->buffer_queue, buftype);
|
||||
if (ret < 0) {
|
||||
vpif_err("videobuf_streamon\n");
|
||||
vpif_err("vb2_streamon\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If buffer queue is empty, return error */
|
||||
if (list_empty(&common->dma_queue)) {
|
||||
vpif_err("buffer queue is empty\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Get the next frame from the buffer queue */
|
||||
common->next_frm = common->cur_frm =
|
||||
list_entry(common->dma_queue.next,
|
||||
struct videobuf_buffer, queue);
|
||||
|
||||
list_del(&common->cur_frm->queue);
|
||||
/* Mark state of the current frame to active */
|
||||
common->cur_frm->state = VIDEOBUF_ACTIVE;
|
||||
|
||||
/* Initialize field_id and started member */
|
||||
ch->field_id = 0;
|
||||
common->started = 1;
|
||||
if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
|
||||
addr = common->cur_frm->boff;
|
||||
/* Calculate the offset for Y and C data in the buffer */
|
||||
vpif_calculate_offsets(ch);
|
||||
|
||||
if ((ch->vpifparams.std_info.frm_fmt &&
|
||||
((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
|
||||
&& (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
|
||||
|| (!ch->vpifparams.std_info.frm_fmt
|
||||
&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
|
||||
vpif_err("conflict in field format and std format\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* clock settings */
|
||||
ret =
|
||||
vpif_config_data->set_clock(ch->vpifparams.std_info.ycmux_mode,
|
||||
ch->vpifparams.std_info.hd_sd);
|
||||
if (ret < 0) {
|
||||
vpif_err("can't set clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set the parameters and addresses */
|
||||
ret = vpif_set_video_params(vpif, ch->channel_id + 2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
common->started = ret;
|
||||
vpif_config_addr(ch, ret);
|
||||
common->set_addr((addr + common->ytop_off),
|
||||
(addr + common->ybtm_off),
|
||||
(addr + common->ctop_off),
|
||||
(addr + common->cbtm_off));
|
||||
|
||||
/* Set interrupt for both the fields in VPIF
|
||||
Register enable channel in VPIF register */
|
||||
if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
|
||||
channel2_intr_assert();
|
||||
channel2_intr_enable(1);
|
||||
enable_channel2(1);
|
||||
}
|
||||
|
||||
if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
|
||||
|| (common->started == 2)) {
|
||||
channel3_intr_assert();
|
||||
channel3_intr_enable(1);
|
||||
enable_channel3(1);
|
||||
}
|
||||
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1208,7 +1170,7 @@ static int vpif_streamoff(struct file *file, void *priv,
|
|||
}
|
||||
|
||||
common->started = 0;
|
||||
return videobuf_streamoff(&common->buffer_queue);
|
||||
return vb2_streamoff(&common->buffer_queue, buftype);
|
||||
}
|
||||
|
||||
static int vpif_cropcap(struct file *file, void *priv,
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/videobuf-core.h>
|
||||
#include <media/videobuf-dma-contig.h>
|
||||
#include <media/videobuf2-dma-contig.h>
|
||||
#include <media/davinci/vpif_types.h>
|
||||
|
||||
#include "vpif.h"
|
||||
|
@ -73,21 +73,29 @@ struct vbi_obj {
|
|||
* vbi data */
|
||||
};
|
||||
|
||||
struct vpif_disp_buffer {
|
||||
struct vb2_buffer vb;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct common_obj {
|
||||
/* Buffer specific parameters */
|
||||
u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for
|
||||
* storing frames */
|
||||
u32 numbuffers; /* number of buffers */
|
||||
struct videobuf_buffer *cur_frm; /* Pointer pointing to current
|
||||
* videobuf_buffer */
|
||||
struct videobuf_buffer *next_frm; /* Pointer pointing to next
|
||||
* videobuf_buffer */
|
||||
struct vpif_disp_buffer *cur_frm; /* Pointer pointing to current
|
||||
* vb2_buffer */
|
||||
struct vpif_disp_buffer *next_frm; /* Pointer pointing to next
|
||||
* vb2_buffer */
|
||||
enum v4l2_memory memory; /* This field keeps track of
|
||||
* type of buffer exchange
|
||||
* method user has selected */
|
||||
struct v4l2_format fmt; /* Used to store the format */
|
||||
struct videobuf_queue buffer_queue; /* Buffer queue used in
|
||||
struct vb2_queue buffer_queue; /* Buffer queue used in
|
||||
* video-buf */
|
||||
/* allocator-specific contexts for each plane */
|
||||
struct vb2_alloc_ctx *alloc_ctx;
|
||||
|
||||
struct list_head dma_queue; /* Queue of filled frames */
|
||||
spinlock_t irqlock; /* Used in video-buf */
|
||||
|
||||
|
|
Loading…
Reference in a new issue