diff options
Diffstat (limited to 'drivers/media/platform/omap/omap_vout.c')
-rw-r--r-- | drivers/media/platform/omap/omap_vout.c | 1045 |
1 files changed, 281 insertions, 764 deletions
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index cb6a9e3946b6..513b99bf963b 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -40,9 +40,9 @@ #include <linux/dma-mapping.h> #include <linux/slab.h> -#include <media/videobuf-dma-contig.h> #include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <video/omapvrfb.h> #include <video/omapfb_dss.h> @@ -63,33 +63,12 @@ enum omap_vout_channels { OMAP_VIDEO2, }; -static struct videobuf_queue_ops video_vbq_ops; /* Variables configurable through module params*/ -static u32 video1_numbuffers = 3; -static u32 video2_numbuffers = 3; -static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE; -static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE; static bool vid1_static_vrfb_alloc; static bool vid2_static_vrfb_alloc; static bool debug; /* Module parameters */ -module_param(video1_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video1_numbuffers, - "Number of buffers to be allocated at init time for Video1 device."); - -module_param(video2_numbuffers, uint, S_IRUGO); -MODULE_PARM_DESC(video2_numbuffers, - "Number of buffers to be allocated at init time for Video2 device."); - -module_param(video1_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video1_bufsize, - "Size of the buffer to be allocated for video1 device"); - -module_param(video2_bufsize, uint, S_IRUGO); -MODULE_PARM_DESC(video2_bufsize, - "Size of the buffer to be allocated for video2 device"); - module_param(vid1_static_vrfb_alloc, bool, S_IRUGO); MODULE_PARM_DESC(vid1_static_vrfb_alloc, "Static allocation of the VRFB buffer for video1 device"); @@ -114,14 +93,12 @@ static const struct v4l2_fmtdesc omap_formats[] = { * Byte 0 Byte 1 * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3 */ - .description = "RGB565, le", .pixelformat = V4L2_PIX_FMT_RGB565, }, { /* Note: V4L2 defines RGB32 as: RGB-8-8-8-8 we use * this for RGB24 unpack mode, the last 8 bits are ignored * */ - .description = "RGB32, le", .pixelformat = V4L2_PIX_FMT_RGB32, }, { @@ -129,15 +106,12 @@ static const struct v4l2_fmtdesc omap_formats[] = { * this for RGB24 packed mode * */ - .description = "RGB24, le", .pixelformat = V4L2_PIX_FMT_RGB24, }, { - .description = "YUYV (YUV 4:2:2), packed", .pixelformat = V4L2_PIX_FMT_YUYV, }, { - .description = "UYVY, packed", .pixelformat = V4L2_PIX_FMT_UYVY, }, }; @@ -164,13 +138,13 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) ifmt = 0; pix->pixelformat = omap_formats[ifmt].pixelformat; - pix->field = V4L2_FIELD_ANY; + pix->field = V4L2_FIELD_NONE; switch (pix->pixelformat) { case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: default: - pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->colorspace = V4L2_COLORSPACE_SRGB; bpp = YUYV_BPP; break; case V4L2_PIX_FMT_RGB565: @@ -195,56 +169,6 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix) } /* - * omap_vout_get_userptr: Convert user space virtual address to physical - * address. - */ -static int omap_vout_get_userptr(struct videobuf_buffer *vb, long virtp, - u32 *physp) -{ - struct frame_vector *vec; - int ret; - - /* For kernel direct-mapped memory, take the easy way */ - if (virtp >= PAGE_OFFSET) { - *physp = virt_to_phys((void *)virtp); - return 0; - } - - vec = frame_vector_create(1); - if (!vec) - return -ENOMEM; - - ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec); - if (ret != 1) { - frame_vector_destroy(vec); - return -EINVAL; - } - *physp = __pfn_to_phys(frame_vector_pfns(vec)[0]); - vb->priv = vec; - - return 0; -} - -/* - * Free the V4L2 buffers - */ -void omap_vout_free_buffers(struct omap_vout_device *vout) -{ - int i, numbuffers; - - /* Allocate memory for the buffers */ - numbuffers = (vout->vid) ? video2_numbuffers : video1_numbuffers; - vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize; - - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_phy_addr[i] = 0; - vout->buf_virt_addr[i] = 0; - } -} - -/* * Convert V4L2 rotation to DSS rotation * V4L2 understand 0, 90, 180, 270. * Convert to 0, 1, 2 and 3 respectively for DSS @@ -537,9 +461,9 @@ static int omapvid_handle_interlace_display(struct omap_vout_device *vout, if (vout->cur_frm == vout->next_frm) goto err; - vout->cur_frm->ts = ts; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm->vbuf.vb2_buf.timestamp = ts; + vout->cur_frm->vbuf.sequence = vout->sequence++; + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); vout->cur_frm = vout->next_frm; } else { if (list_empty(&vout->dma_queue) || @@ -562,9 +486,6 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) struct omap_dss_device *cur_display; struct omap_vout_device *vout = (struct omap_vout_device *)arg; - if (!vout->streaming) - return; - ovid = &vout->vid_info; ovl = ovid->overlays[0]; @@ -608,9 +529,9 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) } if (!vout->first_int && (vout->cur_frm != vout->next_frm)) { - vout->cur_frm->ts = ts; - vout->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&vout->cur_frm->done); + vout->cur_frm->vbuf.vb2_buf.timestamp = ts; + vout->cur_frm->vbuf.sequence = vout->sequence++; + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_DONE); vout->cur_frm = vout->next_frm; } @@ -619,12 +540,10 @@ static void omap_vout_isr(void *arg, unsigned int irqstatus) goto vout_isr_err; vout->next_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); + struct omap_vout_buffer, queue); list_del(&vout->next_frm->queue); - vout->next_frm->state = VIDEOBUF_ACTIVE; - - addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i] + addr = (unsigned long)vout->queued_buf_addr[vout->next_frm->vbuf.vb2_buf.index] + vout->cropped_offset; /* First save the configuration in ovelray structure */ @@ -644,394 +563,6 @@ vout_isr_err: spin_unlock(&vout->vbq_lock); } -/* Video buffer call backs */ - -/* - * Buffer setup function is called by videobuf layer when REQBUF ioctl is - * called. This is used to setup buffers and return size and count of - * buffers allocated. After the call to this buffer, videobuf layer will - * setup buffer queue depending on the size and count of buffers - */ -static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) -{ - int startindex = 0, i, j; - u32 phy_addr = 0, virt_addr = 0; - struct omap_vout_device *vout = q->priv_data; - struct omapvideo_info *ovid = &vout->vid_info; - int vid_max_buf_size; - - if (!vout) - return -EINVAL; - - vid_max_buf_size = vout->vid == OMAP_VIDEO1 ? video1_bufsize : - video2_bufsize; - - if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type) - return -EINVAL; - - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - if (V4L2_MEMORY_MMAP == vout->memory && *count < startindex) - *count = startindex; - - if (ovid->rotation_type == VOUT_ROT_VRFB) { - if (omap_vout_vrfb_buffer_setup(vout, count, startindex)) - return -ENOMEM; - } - - if (V4L2_MEMORY_MMAP != vout->memory) - return 0; - - /* Now allocated the V4L2 buffers */ - *size = PAGE_ALIGN(vout->pix.width * vout->pix.height * vout->bpp); - startindex = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - /* Check the size of the buffer */ - if (*size > vid_max_buf_size) { - v4l2_err(&vout->vid_dev->v4l2_dev, - "buffer allocation mismatch [%u] [%u]\n", - *size, vout->buffer_size); - return -ENOMEM; - } - - for (i = startindex; i < *count; i++) { - vout->buffer_size = *size; - - virt_addr = omap_vout_alloc_buffer(vout->buffer_size, - &phy_addr); - if (!virt_addr) { - if (ovid->rotation_type == VOUT_ROT_NONE) - break; - - if (!is_rotation_enabled(vout)) - break; - - /* Free the VRFB buffers if no space for V4L2 buffers */ - for (j = i; j < *count; j++) { - omap_vout_free_buffer(vout->smsshado_virt_addr[j], - vout->smsshado_size); - vout->smsshado_virt_addr[j] = 0; - vout->smsshado_phy_addr[j] = 0; - } - } - vout->buf_virt_addr[i] = virt_addr; - vout->buf_phy_addr[i] = phy_addr; - } - *count = vout->buffer_allocated = i; - - return 0; -} - -/* - * Free the V4L2 buffers additionally allocated than default - * number of buffers - */ -static void omap_vout_free_extra_buffers(struct omap_vout_device *vout) -{ - int num_buffers = 0, i; - - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - - for (i = num_buffers; i < vout->buffer_allocated; i++) { - if (vout->buf_virt_addr[i]) - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - vout->buffer_allocated = num_buffers; -} - -/* - * This function will be called when VIDIOC_QBUF ioctl is called. - * It prepare buffers before give out for the display. This function - * converts user space virtual address into physical address if userptr memory - * exchange mechanism is used. If rotation is enabled, it copies entire - * buffer into VRFB memory space before giving it to the DSS. - */ -static int omap_vout_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct omap_vout_device *vout = q->priv_data; - struct omapvideo_info *ovid = &vout->vid_info; - - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = vout->pix.width; - vb->height = vout->pix.height; - vb->size = vb->width * vb->height * vout->bpp; - vb->field = field; - } - vb->state = VIDEOBUF_PREPARED; - /* if user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == vb->memory) { - int ret; - - if (0 == vb->baddr) - return -EINVAL; - /* Physical address */ - ret = omap_vout_get_userptr(vb, vb->baddr, - (u32 *)&vout->queued_buf_addr[vb->i]); - if (ret < 0) - return ret; - } else { - unsigned long addr, dma_addr; - unsigned long size; - - addr = (unsigned long) vout->buf_virt_addr[vb->i]; - size = (unsigned long) vb->size; - - dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr, - size, DMA_TO_DEVICE); - if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr)) - v4l2_err(&vout->vid_dev->v4l2_dev, - "dma_map_single failed\n"); - - vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; - } - - if (ovid->rotation_type == VOUT_ROT_VRFB) - return omap_vout_prepare_vrfb(vout, vb); - else - return 0; -} - -/* - * Buffer queue function will be called from the videobuf layer when _QBUF - * ioctl is called. It is used to enqueue buffer, which is ready to be - * displayed. - */ -static void omap_vout_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct omap_vout_device *vout = q->priv_data; - - /* Driver is also maintainig a queue. So enqueue buffer in the driver - * queue */ - list_add_tail(&vb->queue, &vout->dma_queue); - - vb->state = VIDEOBUF_QUEUED; -} - -/* - * Buffer release function is called from videobuf layer to release buffer - * which are already allocated - */ -static void omap_vout_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - vb->state = VIDEOBUF_NEEDS_INIT; - if (vb->memory == V4L2_MEMORY_USERPTR && vb->priv) { - struct frame_vector *vec = vb->priv; - - put_vaddr_frames(vec); - frame_vector_destroy(vec); - } -} - -/* - * File operations - */ -static __poll_t omap_vout_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct omap_vout_device *vout = file->private_data; - struct videobuf_queue *q = &vout->vbq; - - return videobuf_poll_stream(file, q, wait); -} - -static void omap_vout_vm_open(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count++; -} - -static void omap_vout_vm_close(struct vm_area_struct *vma) -{ - struct omap_vout_device *vout = vma->vm_private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end); - vout->mmap_count--; -} - -static const struct vm_operations_struct omap_vout_vm_ops = { - .open = omap_vout_vm_open, - .close = omap_vout_vm_close, -}; - -static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma) -{ - int i; - void *pos; - unsigned long start = vma->vm_start; - unsigned long size = (vma->vm_end - vma->vm_start); - struct omap_vout_device *vout = file->private_data; - struct videobuf_queue *q = &vout->vbq; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - " %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__, - vma->vm_pgoff, vma->vm_start, vma->vm_end); - - /* look for the buffer to map */ - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - if (NULL == q->bufs[i]) - continue; - if (V4L2_MEMORY_MMAP != q->bufs[i]->memory) - continue; - if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT)) - break; - } - - if (VIDEO_MAX_FRAME == i) { - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, - "offset invalid [offset=0x%lx]\n", - (vma->vm_pgoff << PAGE_SHIFT)); - return -EINVAL; - } - /* Check the size of the buffer */ - if (size > vout->buffer_size) { - v4l2_err(&vout->vid_dev->v4l2_dev, - "insufficient memory [%lu] [%u]\n", - size, vout->buffer_size); - return -ENOMEM; - } - - q->bufs[i]->baddr = vma->vm_start; - - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); - vma->vm_ops = &omap_vout_vm_ops; - vma->vm_private_data = (void *) vout; - pos = (void *)vout->buf_virt_addr[i]; - vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT; - while (size > 0) { - unsigned long pfn; - pfn = virt_to_phys((void *) pos) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; - } - vout->mmap_count++; - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - - return 0; -} - -static int omap_vout_release(struct file *file) -{ - unsigned int ret, i; - struct videobuf_queue *q; - struct omapvideo_info *ovid; - struct omap_vout_device *vout = file->private_data; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - ovid = &vout->vid_info; - - if (!vout) - return 0; - - q = &vout->vbq; - /* Disable all the overlay managers connected with this interface */ - for (i = 0; i < ovid->num_overlays; i++) { - struct omap_overlay *ovl = ovid->overlays[i]; - struct omap_dss_device *dssdev = ovl->get_device(ovl); - - if (dssdev) - ovl->disable(ovl); - } - /* Turn off the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) - v4l2_warn(&vout->vid_dev->v4l2_dev, - "Unable to apply changes\n"); - - /* Free all buffers */ - omap_vout_free_extra_buffers(vout); - - /* Free the VRFB buffers only if they are allocated - * during reqbufs. Don't free if init time allocated - */ - if (ovid->rotation_type == VOUT_ROT_VRFB) { - if (!vout->vrfb_static_allocation) - omap_vout_free_vrfb_buffers(vout); - } - videobuf_mmap_free(q); - - /* Even if apply changes fails we should continue - freeing allocated memory */ - if (vout->streaming) { - u32 mask = 0; - - mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | - DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; - omap_dispc_unregister_isr(omap_vout_isr, vout, mask); - vout->streaming = false; - - videobuf_streamoff(q); - videobuf_queue_cancel(q); - } - - if (vout->mmap_count != 0) - vout->mmap_count = 0; - - vout->opened -= 1; - file->private_data = NULL; - - if (vout->buffer_allocated) - videobuf_mmap_free(q); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return ret; -} - -static int omap_vout_open(struct file *file) -{ - struct videobuf_queue *q; - struct omap_vout_device *vout = NULL; - - vout = video_drvdata(file); - - if (vout == NULL) - return -ENODEV; - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Entering %s\n", __func__); - - /* for now, we only support single open */ - if (vout->opened) - return -EBUSY; - - vout->opened += 1; - - file->private_data = vout; - vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - q = &vout->vbq; - video_vbq_ops.buf_setup = omap_vout_buffer_setup; - video_vbq_ops.buf_prepare = omap_vout_buffer_prepare; - video_vbq_ops.buf_release = omap_vout_buffer_release; - video_vbq_ops.buf_queue = omap_vout_buffer_queue; - spin_lock_init(&vout->vbq_lock); - - videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev, - &vout->vbq_lock, vout->type, V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), vout, NULL); - - v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__); - return 0; -} /* * V4L2 ioctls @@ -1039,15 +570,12 @@ static int omap_vout_open(struct file *file) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); strscpy(cap->driver, VOUT_NAME, sizeof(cap->driver)); strscpy(cap->card, vout->vfd->name, sizeof(cap->card)); - cap->bus_info[0] = '\0'; - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s.%d", VOUT_NAME, vout->vid); return 0; } @@ -1060,8 +588,6 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, return -EINVAL; fmt->flags = omap_formats[index].flags; - strscpy(fmt->description, omap_formats[index].description, - sizeof(fmt->description)); fmt->pixelformat = omap_formats[index].pixelformat; return 0; @@ -1070,7 +596,7 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *fh, static int vidioc_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); f->fmt.pix = vout->pix; return 0; @@ -1083,7 +609,7 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *fh, struct omap_overlay *ovl; struct omapvideo_info *ovid; struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_dss_device *dssdev; ovid = &vout->vid_info; @@ -1110,14 +636,12 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, struct omap_overlay *ovl; struct omapvideo_info *ovid; struct omap_video_timings *timing; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_dss_device *dssdev; - if (vout->streaming) + if (vb2_is_busy(&vout->vq)) return -EBUSY; - mutex_lock(&vout->lock); - ovid = &vout->vid_info; ovl = ovid->overlays[0]; dssdev = ovl->get_device(ovl); @@ -1168,7 +692,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, ret = 0; s_fmt_vid_out_exit: - mutex_unlock(&vout->lock); return ret; } @@ -1176,7 +699,7 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) { int ret = 0; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay *ovl; struct omapvideo_info *ovid; struct v4l2_window *win = &f->fmt.win; @@ -1186,12 +709,8 @@ static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh, ret = omap_vout_try_window(&vout->fbuf, win); - if (!ret) { - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - win->global_alpha = 255; - else - win->global_alpha = f->fmt.win.global_alpha; - } + if (!ret && !(ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA)) + win->global_alpha = 0; return ret; } @@ -1202,35 +721,53 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh, int ret = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_window *win = &f->fmt.win; - mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; ret = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win); if (!ret) { + enum omap_dss_trans_key_type key_type = + OMAP_DSS_COLOR_KEY_GFX_DST; + int enable; + /* Video1 plane does not support global alpha on OMAP3 */ - if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) - vout->win.global_alpha = 255; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) + vout->win.global_alpha = win->global_alpha; + else + win->global_alpha = 0; + if (vout->fbuf.flags & (V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_SRC_CHROMAKEY)) + enable = 1; else - vout->win.global_alpha = f->fmt.win.global_alpha; + enable = 0; + if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) + key_type = OMAP_DSS_COLOR_KEY_VID_SRC; + + if (ovl->manager && ovl->manager->get_manager_info && + ovl->manager->set_manager_info) { + struct omap_overlay_manager_info info; - vout->win.chromakey = f->fmt.win.chromakey; + ovl->manager->get_manager_info(ovl->manager, &info); + info.trans_enabled = enable; + info.trans_key_type = key_type; + info.trans_key = vout->win.chromakey; + + if (ovl->manager->set_manager_info(ovl->manager, &info)) + return -EINVAL; + } } - mutex_unlock(&vout->lock); return ret; } static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, struct v4l2_format *f) { - u32 key_value = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; - struct omap_overlay_manager_info info; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_window *win = &f->fmt.win; ovid = &vout->vid_info; @@ -1238,19 +775,20 @@ static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh, win->w = vout->win.w; win->field = vout->win.field; - win->global_alpha = vout->win.global_alpha; - - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); - key_value = info.trans_key; - } - win->chromakey = key_value; + win->chromakey = vout->win.chromakey; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) + win->global_alpha = vout->win.global_alpha; + else + win->global_alpha = 0; + win->clips = NULL; + win->clipcount = 0; + win->bitmap = NULL; return 0; } static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct v4l2_pix_format *pix = &vout->pix; if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1277,7 +815,7 @@ static int vidioc_g_selection(struct file *file, void *fh, struct v4l2_selection static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection *sel) { int ret = -EINVAL; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omapvideo_info *ovid; struct omap_overlay *ovl; struct omap_video_timings *timing; @@ -1289,10 +827,9 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - if (vout->streaming) + if (vb2_is_busy(&vout->vq)) return -EBUSY; - mutex_lock(&vout->lock); ovid = &vout->vid_info; ovl = ovid->overlays[0]; /* get the display device attached to the overlay */ @@ -1317,7 +854,6 @@ static int vidioc_s_selection(struct file *file, void *fh, struct v4l2_selection &vout->fbuf, &sel->r); s_crop_err: - mutex_unlock(&vout->lock); return ret; } @@ -1334,26 +870,21 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovid = &vout->vid_info; - mutex_lock(&vout->lock); if (rotation && ovid->rotation_type == VOUT_ROT_NONE) { - mutex_unlock(&vout->lock); ret = -ERANGE; break; } if (rotation && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } if (v4l2_rot_to_dss_rot(rotation, &vout->rotation, vout->mirror)) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } - mutex_unlock(&vout->lock); break; } case V4L2_CID_BG_COLOR: @@ -1364,9 +895,7 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovl = vout->vid_info.overlays[0]; - mutex_lock(&vout->lock); if (!ovl->manager || !ovl->manager->get_manager_info) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } @@ -1374,11 +903,9 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovl->manager->get_manager_info(ovl->manager, &info); info.default_color = color; if (ovl->manager->set_manager_info(ovl->manager, &info)) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } - mutex_unlock(&vout->lock); break; } case V4L2_CID_VFLIP: @@ -1388,20 +915,16 @@ static int omap_vout_s_ctrl(struct v4l2_ctrl *ctrl) ovid = &vout->vid_info; - mutex_lock(&vout->lock); if (mirror && ovid->rotation_type == VOUT_ROT_NONE) { - mutex_unlock(&vout->lock); ret = -ERANGE; break; } if (mirror && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) { - mutex_unlock(&vout->lock); ret = -EINVAL; break; } vout->mirror = mirror; - mutex_unlock(&vout->lock); break; } default: @@ -1414,185 +937,94 @@ static const struct v4l2_ctrl_ops omap_vout_ctrl_ops = { .s_ctrl = omap_vout_s_ctrl, }; -static int vidioc_reqbufs(struct file *file, void *fh, - struct v4l2_requestbuffers *req) +static int omap_vout_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *nbufs, + unsigned int *num_planes, unsigned int sizes[], + struct device *alloc_devs[]) { - int ret = 0; - unsigned int i, num_buffers = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; - - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - /* if memory is not mmp or userptr - return error */ - if ((V4L2_MEMORY_MMAP != req->memory) && - (V4L2_MEMORY_USERPTR != req->memory)) - return -EINVAL; - - mutex_lock(&vout->lock); - /* Cannot be requested when streaming is on */ - if (vout->streaming) { - ret = -EBUSY; - goto reqbuf_err; - } + struct omap_vout_device *vout = vb2_get_drv_priv(vq); + int size = vout->pix.sizeimage; - /* If buffers are already allocated free them */ - if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) { - if (vout->mmap_count) { - ret = -EBUSY; - goto reqbuf_err; - } - num_buffers = (vout->vid == OMAP_VIDEO1) ? - video1_numbuffers : video2_numbuffers; - for (i = num_buffers; i < vout->buffer_allocated; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } - vout->buffer_allocated = num_buffers; - videobuf_mmap_free(q); - } else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) { - if (vout->buffer_allocated) { - videobuf_mmap_free(q); - for (i = 0; i < vout->buffer_allocated; i++) { - kfree(q->bufs[i]); - q->bufs[i] = NULL; - } - vout->buffer_allocated = 0; - } + if (is_rotation_enabled(vout) && vq->num_buffers + *nbufs > VRFB_NUM_BUFS) { + *nbufs = VRFB_NUM_BUFS - vq->num_buffers; + if (*nbufs == 0) + return -EINVAL; } - /*store the memory type in data structure */ - vout->memory = req->memory; - - INIT_LIST_HEAD(&vout->dma_queue); - - /* call videobuf_reqbufs api */ - ret = videobuf_reqbufs(q, req); - if (ret < 0) - goto reqbuf_err; - - vout->buffer_allocated = req->count; - -reqbuf_err: - mutex_unlock(&vout->lock); - return ret; -} - -static int vidioc_querybuf(struct file *file, void *fh, - struct v4l2_buffer *b) -{ - struct omap_vout_device *vout = fh; + if (*num_planes) + return sizes[0] < size ? -EINVAL : 0; - return videobuf_querybuf(&vout->vbq, b); + *num_planes = 1; + sizes[0] = size; + return 0; } -static int vidioc_qbuf(struct file *file, void *fh, - struct v4l2_buffer *buffer) +static int omap_vout_vb2_prepare(struct vb2_buffer *vb) { - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); + struct omapvideo_info *ovid = &vout->vid_info; + struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); + dma_addr_t buf_phy_addr = vb2_dma_contig_plane_dma_addr(vb, 0); - if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) || - (buffer->index >= vout->buffer_allocated) || - (q->bufs[buffer->index]->memory != buffer->memory)) { + if (vb2_plane_size(vb, 0) < vout->pix.sizeimage) { + v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, + "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), vout->pix.sizeimage); return -EINVAL; } - if (V4L2_MEMORY_USERPTR == buffer->memory) { - if ((buffer->length < vout->pix.sizeimage) || - (0 == buffer->m.userptr)) { - return -EINVAL; - } - } - if ((is_rotation_enabled(vout)) && - vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) { - v4l2_warn(&vout->vid_dev->v4l2_dev, - "DMA Channel not allocated for Rotation\n"); - return -EINVAL; - } + vb2_set_plane_payload(vb, 0, vout->pix.sizeimage); + voutbuf->vbuf.field = V4L2_FIELD_NONE; - return videobuf_qbuf(q, buffer); + vout->queued_buf_addr[vb->index] = (u8 *)buf_phy_addr; + if (ovid->rotation_type == VOUT_ROT_VRFB) + return omap_vout_prepare_vrfb(vout, vb); + return 0; } -static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b) +static void omap_vout_vb2_queue(struct vb2_buffer *vb) { - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vb->vb2_queue); + struct omap_vout_buffer *voutbuf = vb2_to_omap_vout_buffer(vb); - int ret; - u32 addr; - unsigned long size; - struct videobuf_buffer *vb; - - if (!vout->streaming) - return -EINVAL; - - ret = videobuf_dqbuf(q, b, !!(file->f_flags & O_NONBLOCK)); - if (ret) - return ret; - - vb = q->bufs[b->index]; - - addr = (unsigned long) vout->buf_phy_addr[vb->i]; - size = (unsigned long) vb->size; - dma_unmap_single(vout->vid_dev->v4l2_dev.dev, addr, - size, DMA_TO_DEVICE); - return 0; + list_add_tail(&voutbuf->queue, &vout->dma_queue); } -static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) +static int omap_vout_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) { - int ret = 0, j; - u32 addr = 0, mask = 0; - struct omap_vout_device *vout = fh; - struct videobuf_queue *q = &vout->vbq; + struct omap_vout_device *vout = vb2_get_drv_priv(vq); struct omapvideo_info *ovid = &vout->vid_info; - - mutex_lock(&vout->lock); - - if (vout->streaming) { - ret = -EBUSY; - goto streamon_err; - } - - ret = videobuf_streamon(q); - if (ret) - goto streamon_err; - - if (list_empty(&vout->dma_queue)) { - ret = -EIO; - goto streamon_err1; - } + struct omap_vout_buffer *buf, *tmp; + u32 addr = 0, mask = 0; + int ret, j; /* Get the next frame from the buffer queue */ vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next, - struct videobuf_buffer, queue); + struct omap_vout_buffer, queue); /* Remove buffer from the buffer queue */ list_del(&vout->cur_frm->queue); - /* Mark state of the current frame to active */ - vout->cur_frm->state = VIDEOBUF_ACTIVE; /* Initialize field_id and started member */ vout->field_id = 0; - - /* set flag here. Next QBUF will start DMA */ - vout->streaming = true; - vout->first_int = 1; + vout->sequence = 0; if (omap_vout_calculate_offset(vout)) { ret = -EINVAL; - goto streamon_err1; + goto out; } - addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i] + if (ovid->rotation_type == VOUT_ROT_VRFB) + if (omap_vout_vrfb_buffer_setup(vout, &count, 0)) { + ret = -ENOMEM; + goto out; + } + + addr = (unsigned long)vout->queued_buf_addr[vout->cur_frm->vbuf.vb2_buf.index] + vout->cropped_offset; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; - /* First save the configuration in ovelray structure */ + /* First save the configuration in overlay structure */ ret = omapvid_init(vout, addr); if (ret) { v4l2_err(&vout->vid_dev->v4l2_dev, @@ -1617,28 +1049,43 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) goto streamon_err1; } } - - ret = 0; + return 0; streamon_err1: - if (ret) - ret = videobuf_streamoff(q); -streamon_err: - mutex_unlock(&vout->lock); + mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD + | DISPC_IRQ_VSYNC2; + + omap_dispc_unregister_isr(omap_vout_isr, vout, mask); + + for (j = 0; j < ovid->num_overlays; j++) { + struct omap_overlay *ovl = ovid->overlays[j]; + struct omap_dss_device *dssdev = ovl->get_device(ovl); + + if (dssdev) + ovl->disable(ovl); + } + /* Turn of the pipeline */ + if (omapvid_apply_changes(vout)) + v4l2_err(&vout->vid_dev->v4l2_dev, + "failed to change mode in streamoff\n"); + +out: + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED); + } return ret; } -static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) +static void omap_vout_vb2_stop_streaming(struct vb2_queue *vq) { - u32 mask = 0; - int ret = 0, j; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = vb2_get_drv_priv(vq); struct omapvideo_info *ovid = &vout->vid_info; + struct omap_vout_buffer *buf, *tmp; + u32 mask = 0; + int j; - if (!vout->streaming) - return -EINVAL; - - vout->streaming = false; mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_VSYNC2; @@ -1651,17 +1098,18 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) if (dssdev) ovl->disable(ovl); } - /* Turn of the pipeline */ - ret = omapvid_apply_changes(vout); - if (ret) + if (omapvid_apply_changes(vout)) v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in streamoff\n"); - INIT_LIST_HEAD(&vout->dma_queue); - ret = videobuf_streamoff(&vout->vbq); - - return ret; + if (vout->next_frm != vout->cur_frm) + vb2_buffer_done(&vout->next_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + vb2_buffer_done(&vout->cur_frm->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + list_for_each_entry_safe(buf, tmp, &vout->dma_queue, queue) { + list_del(&buf->queue); + vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_ERROR); + } } static int vidioc_s_fbuf(struct file *file, void *fh, @@ -1670,7 +1118,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, int enable = 0; struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay_manager_info info; enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST; @@ -1741,17 +1189,36 @@ static int vidioc_g_fbuf(struct file *file, void *fh, { struct omap_overlay *ovl; struct omapvideo_info *ovid; - struct omap_vout_device *vout = fh; + struct omap_vout_device *vout = video_drvdata(file); struct omap_overlay_manager_info info; + struct omap_video_timings *timing; + struct omap_dss_device *dssdev; ovid = &vout->vid_info; ovl = ovid->overlays[0]; + /* get the display device attached to the overlay */ + dssdev = ovl->get_device(ovl); + + if (!dssdev) + return -EINVAL; + + timing = &dssdev->panel.timings; - /* The video overlay must stay within the framebuffer and can't be - positioned independently. */ - a->flags = V4L2_FBUF_FLAG_OVERLAY; - a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY - | V4L2_FBUF_CAP_SRC_CHROMAKEY; + vout->fbuf.fmt.height = timing->y_res; + vout->fbuf.fmt.width = timing->x_res; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.pixelformat = V4L2_PIX_FMT_RGBA32; + a->fmt.height = vout->fbuf.fmt.height; + a->fmt.width = vout->fbuf.fmt.width; + a->fmt.bytesperline = vout->fbuf.fmt.width * 4; + a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; + a->base = vout->fbuf.base; + + a->flags = vout->fbuf.flags; + a->capability = vout->fbuf.capability; + a->flags &= ~(V4L2_FBUF_FLAG_SRC_CHROMAKEY | V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_LOCAL_ALPHA); if (ovl->manager && ovl->manager->get_manager_info) { ovl->manager->get_manager_info(ovl->manager, &info); @@ -1759,9 +1226,6 @@ static int vidioc_g_fbuf(struct file *file, void *fh, a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY; if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST) a->flags |= V4L2_FBUF_FLAG_CHROMAKEY; - } - if (ovl->manager && ovl->manager->get_manager_info) { - ovl->manager->get_manager_info(ovl->manager, &info); if (info.partial_alpha_enabled) a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA; } @@ -1769,6 +1233,27 @@ static int vidioc_g_fbuf(struct file *file, void *fh, return 0; } +static int vidioc_enum_output(struct file *file, void *priv_fh, + struct v4l2_output *out) +{ + if (out->index) + return -EINVAL; + snprintf(out->name, sizeof(out->name), "Overlay"); + out->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; + return 0; +} + +static int vidioc_g_output(struct file *file, void *priv_fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +static int vidioc_s_output(struct file *file, void *priv_fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + static const struct v4l2_ioctl_ops vout_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, @@ -1782,21 +1267,38 @@ static const struct v4l2_ioctl_ops vout_ioctl_ops = { .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_overlay, .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct v4l2_file_operations omap_vout_fops = { .owner = THIS_MODULE, - .poll = omap_vout_poll, .unlocked_ioctl = video_ioctl2, - .mmap = omap_vout_mmap, - .open = omap_vout_open, - .release = omap_vout_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .open = v4l2_fh_open, + .release = vb2_fop_release, +}; + +static const struct vb2_ops omap_vout_vb2_ops = { + .queue_setup = omap_vout_vb2_queue_setup, + .buf_queue = omap_vout_vb2_queue, + .buf_prepare = omap_vout_vb2_prepare, + .start_streaming = omap_vout_vb2_start_streaming, + .stop_streaming = omap_vout_vb2_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* Init functions used during driver initialization */ @@ -1808,6 +1310,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) struct omap_overlay *ovl = vout->vid_info.overlays[0]; struct omap_dss_device *display = ovl->get_device(ovl); struct v4l2_ctrl_handler *hdl; + struct vb2_queue *vq; + int ret; /* set the default pix */ pix = &vout->pix; @@ -1818,37 +1322,48 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) /* Default pixel format is RGB 5-6-5 */ pix->pixelformat = V4L2_PIX_FMT_RGB565; - pix->field = V4L2_FIELD_ANY; + pix->field = V4L2_FIELD_NONE; pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; - pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->colorspace = V4L2_COLORSPACE_SRGB; vout->bpp = RGB565_BPP; vout->fbuf.fmt.width = display->panel.timings.x_res; vout->fbuf.fmt.height = display->panel.timings.y_res; + vout->cropped_offset = 0; /* Set the data structures for the overlay parameters*/ - vout->win.global_alpha = 255; - vout->fbuf.flags = 0; + vout->fbuf.flags = V4L2_FBUF_FLAG_OVERLAY; vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA | - V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY; - vout->win.chromakey = 0; + V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_EXTERNOVERLAY; + if (ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) { + vout->win.global_alpha = 255; + vout->fbuf.capability |= V4L2_FBUF_CAP_GLOBAL_ALPHA; + vout->fbuf.flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA; + } else { + vout->win.global_alpha = 0; + } + vout->win.field = V4L2_FIELD_NONE; omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win); hdl = &vout->ctrl_handler; v4l2_ctrl_handler_init(hdl, 3); - v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, - V4L2_CID_ROTATE, 0, 270, 90, 0); + if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) { + v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, + V4L2_CID_ROTATE, 0, 270, 90, 0); + v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + } v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, V4L2_CID_BG_COLOR, 0, 0xffffff, 1, 0); - v4l2_ctrl_new_std(hdl, &omap_vout_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); if (hdl->error) return hdl->error; vout->rotation = 0; vout->mirror = false; + INIT_LIST_HEAD(&vout->dma_queue); if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) vout->vrfb_bpp = 2; @@ -1870,63 +1385,54 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) vfd->fops = &omap_vout_fops; vfd->v4l2_dev = &vout->vid_dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_TX; - mutex_init(&vout->lock); - vfd->minor = -1; - return 0; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + mutex_init(&vout->lock); + vq = &vout->vq; + vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + vq->io_modes = VB2_MMAP | VB2_DMABUF; + vq->drv_priv = vout; + vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->buf_struct_size = sizeof(struct omap_vout_buffer); + vq->dev = vfd->v4l2_dev->dev; + + vq->ops = &omap_vout_vb2_ops; + vq->mem_ops = &vb2_dma_contig_memops; + vq->lock = &vout->lock; + vq->min_buffers_needed = 1; + vfd->queue = vq; + + ret = vb2_queue_init(vq); + if (ret) { + v4l2_ctrl_handler_free(hdl); + video_device_release(vfd); + } + return ret; } /* Setup video buffers */ static int __init omap_vout_setup_video_bufs(struct platform_device *pdev, int vid_num) { - u32 numbuffers; - int ret = 0, i; struct omapvideo_info *ovid; struct omap_vout_device *vout; struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); + int ret = 0; vout = vid_dev->vouts[vid_num]; ovid = &vout->vid_info; - numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers; - vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize; - dev_info(&pdev->dev, "Buffer Size = %d\n", vout->buffer_size); - - for (i = 0; i < numbuffers; i++) { - vout->buf_virt_addr[i] = - omap_vout_alloc_buffer(vout->buffer_size, - (u32 *) &vout->buf_phy_addr[i]); - if (!vout->buf_virt_addr[i]) { - numbuffers = i; - ret = -ENOMEM; - goto free_buffers; - } - } - - vout->cropped_offset = 0; - if (ovid->rotation_type == VOUT_ROT_VRFB) { bool static_vrfb_allocation = (vid_num == 0) ? vid1_static_vrfb_alloc : vid2_static_vrfb_alloc; ret = omap_vout_setup_vrfb_bufs(pdev, vid_num, static_vrfb_allocation); } - - return ret; - -free_buffers: - for (i = 0; i < numbuffers; i++) { - omap_vout_free_buffer(vout->buf_virt_addr[i], - vout->buffer_size); - vout->buf_virt_addr[i] = 0; - vout->buf_phy_addr[i] = 0; - } return ret; - } /* Create video out devices */ @@ -1938,6 +1444,10 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct omap2video_device *vid_dev = container_of(v4l2_dev, struct omap2video_device, v4l2_dev); + struct omap_overlay *ovl = vid_dev->overlays[0]; + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); for (k = 0; k < pdev->num_resources; k++) { @@ -1958,6 +1468,15 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) vout->vid_info.overlays[0] = vid_dev->overlays[k + 1]; vout->vid_info.num_overlays = 1; vout->vid_info.id = k + 1; + spin_lock_init(&vout->vbq_lock); + /* + * Set the framebuffer base, this allows applications to find + * the fb corresponding to this overlay. + * + * To be precise: fbuf.base should match smem_start of + * struct fb_fix_screeninfo. + */ + vout->fbuf.base = (void *)info.paddr; /* Set VRFB as rotation_type for omap2 and omap3 */ if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) @@ -2000,7 +1519,6 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) error2: if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) omap_vout_release_vrfb(vout); - omap_vout_free_buffers(vout); error1: video_device_release(vfd); error: @@ -2045,7 +1563,6 @@ static void omap_vout_cleanup_device(struct omap_vout_device *vout) if (vout->vrfb_static_allocation) omap_vout_free_vrfb_buffers(vout); } - omap_vout_free_buffers(vout); kfree(vout); } |