diff options
Diffstat (limited to 'drivers/media/video/davinci')
-rw-r--r-- | drivers/media/video/davinci/Kconfig | 30 | ||||
-rw-r--r-- | drivers/media/video/davinci/Makefile | 8 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpbe_display.c | 4 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif.c | 45 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif.h | 45 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif_capture.c | 694 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif_capture.h | 16 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif_display.c | 684 | ||||
-rw-r--r-- | drivers/media/video/davinci/vpif_display.h | 23 |
9 files changed, 884 insertions, 665 deletions
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig index 9337b5605c90..52c5ca68cb3d 100644 --- a/drivers/media/video/davinci/Kconfig +++ b/drivers/media/video/davinci/Kconfig @@ -1,30 +1,34 @@ -config DISPLAY_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Display" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG +config VIDEO_DAVINCI_VPIF_DISPLAY + tristate "DM646x/DA850/OMAPL138 EVM Video Display" + depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + select VIDEOBUF2_DMA_CONTIG select VIDEO_DAVINCI_VPIF - select VIDEO_ADV7343 - select VIDEO_THS7303 + select VIDEO_ADV7343 if VIDEO_HELPER_CHIPS_AUTO + select VIDEO_THS7303 if VIDEO_HELPER_CHIPS_AUTO help - Support for DM6467 based display device. + Enables Davinci VPIF module used for display devices. + This module is common for following DM6467/DA850/OMAPL138 + based display devices. To compile this driver as a module, choose M here: the module will be called vpif_display. -config CAPTURE_DAVINCI_DM646X_EVM - tristate "DM646x EVM Video Capture" - depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM - select VIDEOBUF_DMA_CONTIG +config VIDEO_DAVINCI_VPIF_CAPTURE + tristate "DM646x/DA850/OMAPL138 EVM Video Capture" + depends on VIDEO_DEV && (MACH_DAVINCI_DM6467_EVM || MACH_DAVINCI_DA850_EVM) + select VIDEOBUF2_DMA_CONTIG select VIDEO_DAVINCI_VPIF help - Support for DM6467 based capture device. + Enables Davinci VPIF module used for captur devices. + This module is common for following DM6467/DA850/OMAPL138 + based capture devices. To compile this driver as a module, choose M here: the module will be called vpif_capture. config VIDEO_DAVINCI_VPIF tristate "DaVinci VPIF Driver" - depends on DISPLAY_DAVINCI_DM646X_EVM + depends on VIDEO_DAVINCI_VPIF_DISPLAY || VIDEO_DAVINCI_VPIF_CAPTURE help Support for DaVinci VPIF Driver. diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile index ae7dafb689ab..74ed92d09257 100644 --- a/drivers/media/video/davinci/Makefile +++ b/drivers/media/video/davinci/Makefile @@ -5,10 +5,10 @@ # VPIF obj-$(CONFIG_VIDEO_DAVINCI_VPIF) += vpif.o -#DM646x EVM Display driver -obj-$(CONFIG_DISPLAY_DAVINCI_DM646X_EVM) += vpif_display.o -#DM646x EVM Capture driver -obj-$(CONFIG_CAPTURE_DAVINCI_DM646X_EVM) += vpif_capture.o +#VPIF Display driver +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_DISPLAY) += vpif_display.o +#VPIF Capture driver +obj-$(CONFIG_VIDEO_DAVINCI_VPIF_CAPTURE) += vpif_capture.o # Capture: DM6446 and DM355 obj-$(CONFIG_VIDEO_VPSS_SYSTEM) += vpss.o diff --git a/drivers/media/video/davinci/vpbe_display.c b/drivers/media/video/davinci/vpbe_display.c index e106b72810a9..6fe7034bea7c 100644 --- a/drivers/media/video/davinci/vpbe_display.c +++ b/drivers/media/video/davinci/vpbe_display.c @@ -1083,7 +1083,7 @@ vpbe_display_s_dv_preset(struct file *file, void *priv, } /* Set the given standard in the encoder */ - if (NULL != vpbe_dev->ops.s_dv_preset) + if (!vpbe_dev->ops.s_dv_preset) return -EINVAL; ret = vpbe_dev->ops.s_dv_preset(vpbe_dev, preset); @@ -1517,6 +1517,8 @@ static int vpbe_display_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { struct v4l2_dbg_match *match = ®->match; + struct vpbe_fh *fh = file->private_data; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; if (match->type >= 2) { v4l2_subdev_call(vpbe_dev->venc, diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c index af9680273ff9..b3637aff8fee 100644 --- a/drivers/media/video/davinci/vpif.c +++ b/drivers/media/video/davinci/vpif.c @@ -1,5 +1,5 @@ /* - * vpif - DM646x Video Port Interface driver + * vpif - Video Port Interface driver * VPIF is a receiver and transmitter for video data. It has two channels(0, 1) * that receiveing video byte stream and two channels(2, 3) for video output. * The hardware supports SDTV, HDTV formats, raw data capture. @@ -23,6 +23,8 @@ #include <linux/spinlock.h> #include <linux/kernel.h> #include <linux/io.h> +#include <linux/clk.h> +#include <linux/err.h> #include <mach/hardware.h> #include "vpif.h" @@ -40,6 +42,7 @@ static struct resource *res; spinlock_t vpif_lock; void __iomem *vpif_base; +struct clk *vpif_clk; /** * ch_params: video standard configuration parameters for vpif @@ -346,7 +349,7 @@ static void config_vpif_params(struct vpif_params *vpifparams, value = regr(reg); /* Set data width */ - value &= ((~(unsigned int)(0x3)) << + value &= ~(0x3u << VPIF_CH_DATA_WIDTH_BIT); value |= ((vpifparams->params.data_sz) << VPIF_CH_DATA_WIDTH_BIT); @@ -434,10 +437,19 @@ static int __init vpif_probe(struct platform_device *pdev) goto fail; } + vpif_clk = clk_get(&pdev->dev, "vpif"); + if (IS_ERR(vpif_clk)) { + status = PTR_ERR(vpif_clk); + goto clk_fail; + } + clk_enable(vpif_clk); + spin_lock_init(&vpif_lock); dev_info(&pdev->dev, "vpif probe success\n"); return 0; +clk_fail: + iounmap(vpif_base); fail: release_mem_region(res->start, res_len); return status; @@ -445,15 +457,44 @@ fail: static int __devexit vpif_remove(struct platform_device *pdev) { + if (vpif_clk) { + clk_disable(vpif_clk); + clk_put(vpif_clk); + } + iounmap(vpif_base); release_mem_region(res->start, res_len); return 0; } +#ifdef CONFIG_PM +static int vpif_suspend(struct device *dev) +{ + clk_disable(vpif_clk); + return 0; +} + +static int vpif_resume(struct device *dev) +{ + clk_enable(vpif_clk); + return 0; +} + +static const struct dev_pm_ops vpif_pm = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +#define vpif_pm_ops (&vpif_pm) +#else +#define vpif_pm_ops NULL +#endif + static struct platform_driver vpif_driver = { .driver = { .name = "vpif", .owner = THIS_MODULE, + .pm = vpif_pm_ops, }, .remove = __devexit_p(vpif_remove), .probe = vpif_probe, diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h index 8bcac65f9294..c2ce4d97c279 100644 --- a/drivers/media/video/davinci/vpif.h +++ b/drivers/media/video/davinci/vpif.h @@ -211,6 +211,12 @@ static inline void vpif_clr_bit(u32 reg, u32 bit) #define VPIF_CH3_INT_CTRL_SHIFT (6) #define VPIF_CH_INT_CTRL_SHIFT (6) +#define VPIF_CH2_CLIP_ANC_EN 14 +#define VPIF_CH2_CLIP_ACTIVE_EN 13 + +#define VPIF_CH3_CLIP_ANC_EN 14 +#define VPIF_CH3_CLIP_ACTIVE_EN 13 + /* enabled interrupt on both the fields on vpid_ch0_ctrl register */ #define channel0_intr_assert() (regw((regr(VPIF_CH0_CTRL)|\ (VPIF_INT_BOTH << VPIF_CH0_INT_CTRL_SHIFT)), VPIF_CH0_CTRL)) @@ -515,6 +521,30 @@ static inline void channel3_raw_enable(int enable, u8 index) vpif_clr_bit(VPIF_CH3_CTRL, mask); } +/* function to enable clipping (for both active and blanking regions) on ch 2 */ +static inline void channel2_clipping_enable(int enable) +{ + if (enable) { + vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN); + vpif_set_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN); + } else { + vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ANC_EN); + vpif_clr_bit(VPIF_CH2_CTRL, VPIF_CH2_CLIP_ACTIVE_EN); + } +} + +/* function to enable clipping (for both active and blanking regions) on ch 2 */ +static inline void channel3_clipping_enable(int enable) +{ + if (enable) { + vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN); + vpif_set_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN); + } else { + vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ANC_EN); + vpif_clr_bit(VPIF_CH3_CTRL, VPIF_CH3_CLIP_ACTIVE_EN); + } +} + /* inline function to set buffer addresses in case of Y/C non mux mode */ static inline void ch2_set_videobuf_addr_yc_nmux(unsigned long top_strt_luma, unsigned long btm_strt_luma, @@ -569,6 +599,21 @@ static inline void ch3_set_vbi_addr(unsigned long top_strt_luma, regw(btm_strt_luma, VPIF_CH3_BTM_STRT_ADD_VANC); } +static inline int vpif_intr_status(int channel) +{ + int status = 0; + int mask; + + if (channel < 0 || channel > 3) + return 0; + + mask = 1 << channel; + status = regr(VPIF_STATUS) & mask; + regw(status, VPIF_STATUS_CLR); + + return status; +} + #define VPIF_MAX_NAME (30) /* This structure will store size parameters as per the mode selected by user */ diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c index 96046957bf21..266025e5d81d 100644 --- a/drivers/media/video/davinci/vpif_capture.c +++ b/drivers/media/video/davinci/vpif_capture.c @@ -80,108 +80,45 @@ static struct vpif_config_params config_params = { /* global variables */ static struct vpif_device vpif_obj = { {NULL} }; static struct device *vpif_dev; - -/** - * vpif_uservirt_to_phys : translate user/virtual address to phy address - * @virtp: user/virtual address - * - * This inline function is used to convert user space virtual address to - * physical address. - */ -static inline u32 vpif_uservirt_to_phys(u32 virtp) -{ - unsigned long physp = 0; - struct mm_struct *mm = current->mm; - 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 - * addresses - */ - 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; -} +static void vpif_calculate_offsets(struct channel_obj *ch); +static void vpif_config_addr(struct channel_obj *ch, int muxmode); /** * buffer_prepare : callback function for buffer prepare - * @q : buffer queue ptr - * @vb: ptr to video buffer - * @field: field info + * @vb: ptr to vb2_buffer * - * This is the callback function for buffer prepare when videobuf_qbuf() + * This is the callback function for buffer prepare when vb2_qbuf() * function is called. The buffer is prepared and user space virtual address * or user 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) { /* Get the file handle object and channel object */ - 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 channel_obj *ch = fh->channel; struct common_obj *common; unsigned long addr; - vpif_dbg(2, debug, "vpif_buffer_prepare\n"); common = &ch->common[VPIF_VIDEO_INDEX]; - /* If buffer is not initialized, initialize it */ - 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 user pointer memory mechanism is used, get the physical - * address of the buffer - */ - if (V4L2_MEMORY_USERPTR == common->memory) { - if (0 == vb->baddr) { - vpif_dbg(1, debug, "buffer address is 0\n"); - return -EINVAL; - - } - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!IS_ALIGNED(vb->boff, 8)) + 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 exit; - } + addr = vb2_dma_contig_plane_dma_addr(vb, 0); - addr = vb->boff; - if (q->streaming) { - if (!IS_ALIGNED((addr + common->ytop_off), 8) || - !IS_ALIGNED((addr + common->ybtm_off), 8) || - !IS_ALIGNED((addr + common->ctop_off), 8) || - !IS_ALIGNED((addr + common->cbtm_off), 8)) - goto exit; + if (q->streaming) { + if (!IS_ALIGNED((addr + common->ytop_off), 8) || + !IS_ALIGNED((addr + common->ybtm_off), 8) || + !IS_ALIGNED((addr + common->ctop_off), 8) || + !IS_ALIGNED((addr + common->cbtm_off), 8)) + goto exit; + } } return 0; exit: @@ -190,49 +127,79 @@ exit: } /** - * vpif_buffer_setup : Callback function for buffer setup. - * @q: buffer queue ptr - * @count: number of buffers - * @size: size of the buffer + * vpif_buffer_queue_setup : Callback function for buffer setup. + * @vq: vb2_queue ptr + * @fmt: v4l2 format + * @nbuffers: ptr to number of buffers requested by application + * @nplanes:: contains number of distinct video planes needed to hold a frame + * @sizes[]: contains the size (in bytes) of each plane. + * @alloc_ctxs: ptr to allocation context * * This callback function is called when reqbuf() is called to adjust * the buffer count and buffer size */ -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[]) { /* Get the file handle object and channel object */ - 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; + unsigned long size; common = &ch->common[VPIF_VIDEO_INDEX]; vpif_dbg(2, debug, "vpif_buffer_setup\n"); /* If memory type is not mmap, return */ - if (V4L2_MEMORY_MMAP != common->memory) - return 0; + if (V4L2_MEMORY_MMAP == common->memory) { + /* Calculate the size of the buffer */ + 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]) + (*nbuffers)--; + } + + } else { + size = common->fmt.fmt.pix.sizeimage; + } + + if (*nbuffers < config_params.min_numbuffers) + *nbuffers = config_params.min_numbuffers; - /* Calculate the size of the buffer */ - *size = config_params.channel_bufsize[ch->channel_id]; + *nplanes = 1; + sizes[0] = size; + alloc_ctxs[0] = common->alloc_ctx; - if (*count < config_params.min_numbuffers) - *count = config_params.min_numbuffers; return 0; } /** * vpif_buffer_queue : Callback function to add buffer to DMA queue - * @q: ptr to videobuf_queue - * @vb: ptr to videobuf_buffer + * @vb: ptr to vb2_buffer */ -static void vpif_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buffer_queue(struct vb2_buffer *vb) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); struct channel_obj *ch = fh->channel; + struct vpif_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); struct common_obj *common; common = &ch->common[VPIF_VIDEO_INDEX]; @@ -240,43 +207,189 @@ static void vpif_buffer_queue(struct videobuf_queue *q, vpif_dbg(2, debug, "vpif_buffer_queue\n"); /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; + list_add_tail(&buf->list, &common->dma_queue); } /** - * vpif_buffer_release : Callback function to free buffer - * @q: buffer queue ptr - * @vb: ptr to video buffer + * vpif_buf_cleanup : Callback function to free buffer + * @vb: ptr to vb2_buffer * - * This function is called from the videobuf layer to free memory + * This function is called from the videobuf2 layer to free memory * allocated to the buffers */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpif_buf_cleanup(struct vb2_buffer *vb) { /* Get the file handle object and channel object */ - struct vpif_fh *fh = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vpif_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long flags; common = &ch->common[VPIF_VIDEO_INDEX]; - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; + 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 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 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_cap_buffer *buf = container_of(vb, + struct vpif_cap_buffer, vb); + + INIT_LIST_HEAD(&buf->list); + + return 0; +} static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = { {1, 1} }; +static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpif_capture_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_dbg(1, debug, "buffer queue is empty\n"); + return -EIO; + } + + /* Get the next frame from the buffer queue */ + common->cur_frm = common->next_frm = list_entry(common->dma_queue.next, + struct vpif_cap_buffer, list); + /* Remove buffer from the buffer queue */ + 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 ((vpif->std_info.frm_fmt && + ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && + (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || + (!vpif->std_info.frm_fmt && + (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { + vpif_dbg(1, debug, "conflict in field format and std format\n"); + return -EINVAL; + } + + /* configure 1 or 2 channel mode */ + ret = vpif_config_data->setup_input_channel_mode + (vpif->std_info.ycmux_mode); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set vpif channel mode\n"); + return ret; + } + + /* Call vpif_set_params function to set the parameters and addresses */ + ret = vpif_set_video_params(vpif, ch->channel_id); + + if (ret < 0) { + vpif_dbg(1, debug, "can't set video params\n"); + 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_CHANNEL0_VIDEO == ch->channel_id)) { + channel0_intr_assert(); + channel0_intr_enable(1); + enable_channel0(1); + } + if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || + (common->started == 2)) { + channel1_intr_assert(); + channel1_intr_enable(1); + enable_channel1(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_cap_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, +}; + /** * vpif_process_buffer_complete: process a completed buffer * @common: ptr to common channel object @@ -287,9 +400,9 @@ static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = */ static void vpif_process_buffer_complete(struct common_obj *common) { - 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 curFrm pointing to nextFrm */ common->cur_frm = common->next_frm; } @@ -307,14 +420,11 @@ static void vpif_schedule_next_buffer(struct common_obj *common) unsigned long addr = 0; common->next_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); + struct vpif_cap_buffer, list); /* Remove that buffer from the buffer queue */ - list_del(&common->next_frm->queue); - common->next_frm->state = VIDEOBUF_ACTIVE; - if (V4L2_MEMORY_USERPTR == common->memory) - addr = common->next_frm->boff; - else - addr = videobuf_to_dma_contig(common->next_frm); + list_del(&common->next_frm->list); + common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; + addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); /* Set top and bottom field addresses in VPIF registers */ common->set_addr(addr + common->ytop_off, @@ -341,6 +451,9 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) int fid = -1, i; channel_id = *(int *)(dev_id); + if (!vpif_intr_status(channel_id)) + return IRQ_NONE; + ch = dev->dev[channel_id]; field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; @@ -485,10 +598,7 @@ static void vpif_calculate_offsets(struct channel_obj *ch) } else 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); @@ -640,10 +750,7 @@ static int vpif_check_format(struct channel_obj *ch, hpitch = vpif_params->std_info.width; } - if (V4L2_MEMORY_USERPTR == common->memory) - sizeimage = pixfmt->sizeimage; - else - sizeimage = config_params.channel_bufsize[ch->channel_id]; + sizeimage = pixfmt->sizeimage; vpitch = sizeimage / (hpitch * 2); @@ -703,7 +810,7 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode) } /** - * vpfe_mmap : It is used to map kernel space buffers into user spaces + * vpif_mmap : It is used to map kernel space buffers into user spaces * @filep: file pointer * @vma: ptr to vm_area_struct */ @@ -716,7 +823,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); } /** @@ -733,7 +840,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait) vpif_dbg(2, debug, "vpif_poll\n"); if (common->started) - return videobuf_poll_stream(filep, &common->buffer_queue, wait); + return vb2_poll(&common->buffer_queue, filep, wait); return 0; } @@ -812,7 +919,7 @@ static int vpif_open(struct file *filep) * vpif_release : function to clean up file close * @filep: file pointer * - * This function deletes buffer queue, frees the buffers and the vpfe file + * This function deletes buffer queue, frees the buffers and the vpif file * handle */ static int vpif_release(struct file *filep) @@ -841,8 +948,8 @@ static int vpif_release(struct file *filep) } 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); } /* Decrement channel usrs counter */ @@ -872,6 +979,7 @@ static int vpif_reqbufs(struct file *file, void *priv, struct channel_obj *ch = fh->channel; struct common_obj *common; u8 index = 0; + struct vb2_queue *q; vpif_dbg(2, debug, "vpif_reqbufs\n"); @@ -887,7 +995,7 @@ static int vpif_reqbufs(struct file *file, void *priv, } } - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type) + if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev) return -EINVAL; index = VPIF_VIDEO_INDEX; @@ -897,14 +1005,21 @@ static int vpif_reqbufs(struct file *file, void *priv, if (0 != common->io_usrs) return -EBUSY; - /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&common->buffer_queue, - &video_qops, NULL, - &common->irqlock, - reqbuf->type, - common->fmt.fmt.pix.field, - sizeof(struct videobuf_buffer), fh, - &common->lock); + /* 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_CAPTURE; + 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_cap_buffer); + + vb2_queue_init(q); /* Set io allowed member of file handle to TRUE */ fh->io_allowed[index] = 1; @@ -915,7 +1030,7 @@ static int vpif_reqbufs(struct file *file, void *priv, INIT_LIST_HEAD(&common->dma_queue); /* Allocate buffers */ - return videobuf_reqbufs(&common->buffer_queue, reqbuf); + return vb2_reqbufs(&common->buffer_queue, reqbuf); } /** @@ -941,7 +1056,7 @@ static int vpif_querybuf(struct file *file, void *priv, return -EINVAL; } - return videobuf_querybuf(&common->buffer_queue, buf); + return vb2_querybuf(&common->buffer_queue, buf); } /** @@ -957,10 +1072,6 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) 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; vpif_dbg(2, debug, "vpif_qbuf\n"); @@ -970,76 +1081,11 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) } if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { - vpif_err("fh io not allowed \n"); + vpif_err("fh io not allowed\n"); 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->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; - - if (V4L2_MEMORY_USERPTR == common->memory) - addr = buf1->boff; - else - addr = videobuf_to_dma_contig(buf1); - - common->next_frm = buf1; - 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); } /** @@ -1056,8 +1102,8 @@ static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) vpif_dbg(2, debug, "vpif_dqbuf\n"); - return videobuf_dqbuf(&common->buffer_queue, buf, - file->f_flags & O_NONBLOCK); + return vb2_dqbuf(&common->buffer_queue, buf, + (file->f_flags & O_NONBLOCK)); } /** @@ -1070,13 +1116,11 @@ static int vpif_streamon(struct file *file, void *priv, enum v4l2_buf_type buftype) { - struct vpif_capture_config *config = vpif_dev->platform_data; struct vpif_fh *fh = 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; - unsigned long addr = 0; int ret = 0; vpif_dbg(2, debug, "vpif_streamon\n"); @@ -1122,95 +1166,13 @@ static int vpif_streamon(struct file *file, void *priv, 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) { - vpif_dbg(1, debug, "videobuf_streamon\n"); + vpif_dbg(1, debug, "vb2_streamon\n"); return ret; } - /* If buffer queue is empty, return error */ - if (list_empty(&common->dma_queue)) { - vpif_dbg(1, debug, "buffer queue is empty\n"); - ret = -EIO; - goto exit; - } - - /* Get the next frame from the buffer queue */ - common->cur_frm = list_entry(common->dma_queue.next, - struct videobuf_buffer, queue); - common->next_frm = common->cur_frm; - - /* Remove buffer from the 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 (V4L2_MEMORY_USERPTR == common->memory) - addr = common->cur_frm->boff; - else - addr = videobuf_to_dma_contig(common->cur_frm); - - /* Calculate the offset for Y and C data in the buffer */ - vpif_calculate_offsets(ch); - - if ((vpif->std_info.frm_fmt && - ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) && - (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) || - (!vpif->std_info.frm_fmt && - (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) { - vpif_dbg(1, debug, "conflict in field format and std format\n"); - ret = -EINVAL; - goto exit; - } - - /* configure 1 or 2 channel mode */ - ret = config->setup_input_channel_mode(vpif->std_info.ycmux_mode); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set vpif channel mode\n"); - goto exit; - } - - /* Call vpif_set_params function to set the parameters and addresses */ - ret = vpif_set_video_params(vpif, ch->channel_id); - - if (ret < 0) { - vpif_dbg(1, debug, "can't set video params\n"); - goto exit; - } - - 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_CHANNEL0_VIDEO == ch->channel_id)) { - channel0_intr_assert(); - channel0_intr_enable(1); - enable_channel0(1); - } - if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) || - (common->started == 2)) { - channel1_intr_assert(); - channel1_intr_enable(1); - enable_channel1(1); - } - channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1; - return ret; - -exit: - videobuf_streamoff(&common->buffer_queue); return ret; } @@ -1265,7 +1227,7 @@ static int vpif_streamoff(struct file *file, void *priv, if (ret && (ret != -ENOIOCTLCMD)) vpif_dbg(1, debug, "stream off failed in subdev\n"); - return videobuf_streamoff(&common->buffer_queue); + return vb2_streamoff(&common->buffer_queue, buftype); } /** @@ -1679,7 +1641,7 @@ static int vpif_querycap(struct file *file, void *priv, cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; strlcpy(cap->driver, "vpif capture", sizeof(cap->driver)); - strlcpy(cap->bus_info, "DM646x Platform", sizeof(cap->bus_info)); + strlcpy(cap->bus_info, "VPIF Platform", sizeof(cap->bus_info)); strlcpy(cap->card, config->card_name, sizeof(cap->card)); return 0; @@ -2168,6 +2130,7 @@ static __init int vpif_probe(struct platform_device *pdev) struct video_device *vfd; struct resource *res; int subdev_count; + size_t size; vpif_dev = &pdev->dev; @@ -2186,8 +2149,8 @@ static __init int vpif_probe(struct platform_device *pdev) k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Capture", + if (request_irq(i, vpif_channel_isr, IRQF_SHARED, + "VPIF_Capture", (void *)(&vpif_obj.dev[k]->channel_id))) { err = -EBUSY; i--; @@ -2216,12 +2179,29 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFCapture_DRIVER_V%s", + "VPIF_Capture_DRIVER_V%s", VPIF_CAPTURE_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + size = resource_size(res); + /* The resources are divided into two equal memory and when we + * have HD output we can add them together + */ + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + /* only enabled if second resource exists */ + config_params.video_limit[ch->channel_id] = 0; + if (size) + config_params.video_limit[ch->channel_id] = + size/2; + } + } + for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; ch->channel_id = j; @@ -2275,8 +2255,7 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.sd[i]->grp_id = 1 << i; } - v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF capture driver initialized\n"); + v4l2_info(&vpif_obj.v4l2_dev, "VPIF capture driver initialized\n"); return 0; probe_subdev_out: @@ -2333,26 +2312,70 @@ static int vpif_remove(struct platform_device *device) return 0; } +#ifdef CONFIG_PM /** * vpif_suspend: vpif device suspend - * - * TODO: Add suspend code here */ -static int -vpif_suspend(struct device *dev) +static int vpif_suspend(struct device *dev) { - return -1; + + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (ch->usrs && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL0_VIDEO) { + enable_channel0(0); + channel0_intr_enable(0); + } + if (ch->channel_id == VPIF_CHANNEL1_VIDEO || + common->started == 2) { + enable_channel1(0); + channel1_intr_enable(0); + } + } + mutex_unlock(&common->lock); + } + + return 0; } -/** +/* * vpif_resume: vpif device suspend - * - * TODO: Add resume code here */ -static int -vpif_resume(struct device *dev) +static int vpif_resume(struct device *dev) { - return -1; + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (ch->usrs && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL0_VIDEO) { + enable_channel0(1); + channel0_intr_enable(1); + } + if (ch->channel_id == VPIF_CHANNEL1_VIDEO || + common->started == 2) { + enable_channel1(1); + channel1_intr_enable(1); + } + } + mutex_unlock(&common->lock); + } + + return 0; } static const struct dev_pm_ops vpif_dev_pm_ops = { @@ -2360,11 +2383,16 @@ static const struct dev_pm_ops vpif_dev_pm_ops = { .resume = vpif_resume, }; +#define vpif_pm_ops (&vpif_dev_pm_ops) +#else +#define vpif_pm_ops NULL +#endif + static __refdata struct platform_driver vpif_driver = { .driver = { .name = "vpif_capture", .owner = THIS_MODULE, - .pm = &vpif_dev_pm_ops, + .pm = vpif_pm_ops, }, .probe = vpif_probe, .remove = vpif_remove, diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h index a693d4ebda55..3511510f43ee 100644 --- a/drivers/media/video/davinci/vpif_capture.h +++ b/drivers/media/video/davinci/vpif_capture.h @@ -26,7 +26,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" @@ -60,11 +60,16 @@ struct video_obj { u32 input_idx; }; +struct vpif_cap_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + struct common_obj { /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; + struct vpif_cap_buffer *cur_frm; /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *next_frm; + struct vpif_cap_buffer *next_frm; /* * This field keeps track of type of buffer exchange mechanism * user has selected @@ -73,7 +78,9 @@ struct common_obj { /* Used to store pixel format */ struct v4l2_format fmt; /* 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 */ @@ -151,6 +158,7 @@ struct vpif_config_params { u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS]; u8 default_device[VPIF_CAPTURE_NUM_CHANNELS]; + u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS]; u8 max_device_type; }; /* Struct which keeps track of the line numbers for the sliced vbi service */ diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c index e6488ee7db18..e129c98921ad 100644 --- a/drivers/media/video/davinci/vpif_display.c +++ b/drivers/media/video/davinci/vpif_display.c @@ -46,7 +46,7 @@ MODULE_DESCRIPTION("TI DaVinci VPIF Display driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(VPIF_DISPLAY_VERSION); -#define DM646X_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) +#define VPIF_V4L2_STD (V4L2_STD_525_60 | V4L2_STD_625_50) #define vpif_err(fmt, arg...) v4l2_err(&vpif_obj.v4l2_dev, fmt, ## arg) #define vpif_dbg(level, debug, fmt, arg...) \ @@ -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 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; - } - - vb->boff = vpif_uservirt_to_phys(vb->baddr); - if (!ISALIGNED(vb->boff)) + 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; - } - 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; + 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; + } } return 0; @@ -174,86 +123,255 @@ buf_align_exit: } /* - * 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) { + 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]) + (*nbuffers)--; + } + } else { + size = common->fmt.fmt.pix.sizeimage; + } - if (V4L2_MEMORY_MMAP != common->memory) - return 0; - - *size = config_params.channel_bufsize[ch->channel_id]; - 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 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; - common = &fh->channel->common[VPIF_VIDEO_INDEX]; + common = &ch->common[VPIF_VIDEO_INDEX]; /* add the buffer to the DMA queue */ - list_add_tail(&vb->queue, &common->dma_queue); - vb->state = VIDEOBUF_QUEUED; + list_add_tail(&buf->list, &common->dma_queue); } /* - * vpif_buffer_release: This function is called from the videobuf layer to + * vpif_buf_cleanup: This function is called from the videobuf2 layer to * free memory allocated to the buffers */ -static void vpif_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +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 = q->priv_data; + struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common; - unsigned int buf_size = 0; common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_unlock(&common->lock); +} - videobuf_dma_contig_free(q, vb); - vb->state = VIDEOBUF_NEEDS_INIT; +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; - if (V4L2_MEMORY_MMAP != common->memory) - return; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); +} - buf_size = config_params.channel_bufsize[ch->channel_id]; +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_config_data->ch2_clip_en) + channel2_clipping_enable(1); + } + + if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) + || (common->started == 2)) { + channel3_intr_assert(); + channel3_intr_enable(1); + enable_channel3(1); + if (vpif_config_data->ch3_clip_en) + channel3_clipping_enable(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, @@ -271,11 +389,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; @@ -307,6 +424,9 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) int channel_id = 0; channel_id = *(int *)(dev_id); + if (!vpif_intr_status(channel_id + 2)) + return IRQ_NONE; + ch = dev->dev[channel_id]; field = ch->common[VPIF_VIDEO_INDEX].fmt.fmt.pix.field; for (i = 0; i < VPIF_NUMOBJECTS; i++) { @@ -323,9 +443,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; } @@ -443,10 +564,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); @@ -523,10 +641,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; @@ -583,7 +698,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); } /* @@ -596,7 +711,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; } @@ -665,9 +780,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]; } @@ -806,6 +923,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, @@ -825,9 +943,8 @@ static int vpif_reqbufs(struct file *file, void *priv, common = &ch->common[index]; - if (common->fmt.type != reqbuf->type) + if (common->fmt.type != reqbuf->type || !vpif_dev) return -EINVAL; - if (0 != common->io_usrs) return -EBUSY; @@ -839,14 +956,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, NULL, - &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; @@ -855,9 +979,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, @@ -870,22 +993,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; + + fh = priv; + ch = fh->channel; + if (!ch) + return -EINVAL; - if (common->fmt.type != tbuf.type) + common = &(ch->common[VPIF_VIDEO_INDEX]); + if (common->fmt.type != buf->type) return -EINVAL; if (!fh->io_allowed[VPIF_VIDEO_INDEX]) { @@ -893,73 +1019,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) @@ -969,7 +1029,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; int ret = 0; - if (!(*std_id & DM646X_V4L2_STD)) + if (!(*std_id & VPIF_V4L2_STD)) return -EINVAL; if (common->started) { @@ -1026,7 +1086,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)); } @@ -1037,10 +1097,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) { @@ -1072,82 +1128,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; } @@ -1157,6 +1144,8 @@ static int vpif_streamoff(struct file *file, void *priv, struct vpif_fh *fh = priv; struct channel_obj *ch = fh->channel; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; + struct vpif_display_config *vpif_config_data = + vpif_dev->platform_data; if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) { vpif_err("buffer type not supported\n"); @@ -1176,18 +1165,22 @@ static int vpif_streamoff(struct file *file, void *priv, if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) { /* disable channel */ if (VPIF_CHANNEL2_VIDEO == ch->channel_id) { + if (vpif_config_data->ch2_clip_en) + channel2_clipping_enable(0); enable_channel2(0); channel2_intr_enable(0); } if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) || (2 == common->started)) { + if (vpif_config_data->ch3_clip_en) + channel3_clipping_enable(0); enable_channel3(0); channel3_intr_enable(0); } } 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, @@ -1220,7 +1213,7 @@ static int vpif_enum_output(struct file *file, void *fh, strcpy(output->name, config->output[output->index]); output->type = V4L2_OUTPUT_TYPE_ANALOG; - output->std = DM646X_V4L2_STD; + output->std = VPIF_V4L2_STD; return 0; } @@ -1605,7 +1598,7 @@ static struct video_device vpif_video_template = { .name = "vpif", .fops = &vpif_fops, .ioctl_ops = &vpif_ioctl_ops, - .tvnorms = DM646X_V4L2_STD, + .tvnorms = VPIF_V4L2_STD, .current_norm = V4L2_STD_625_50, }; @@ -1687,9 +1680,9 @@ static __init int vpif_probe(struct platform_device *pdev) struct video_device *vfd; struct resource *res; int subdev_count; + size_t size; vpif_dev = &pdev->dev; - err = initialize_vpif(); if (err) { @@ -1706,8 +1699,8 @@ static __init int vpif_probe(struct platform_device *pdev) k = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { - if (request_irq(i, vpif_channel_isr, IRQF_DISABLED, - "DM646x_Display", + if (request_irq(i, vpif_channel_isr, IRQF_SHARED, + "VPIF_Display", (void *)(&vpif_obj.dev[k]->channel_id))) { err = -EBUSY; goto vpif_int_err; @@ -1737,13 +1730,31 @@ static __init int vpif_probe(struct platform_device *pdev) vfd->v4l2_dev = &vpif_obj.v4l2_dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), - "DM646x_VPIFDisplay_DRIVER_V%s", + "VPIF_Display_DRIVER_V%s", VPIF_DISPLAY_VERSION); /* Set video_dev to the video device */ ch->video_dev = vfd; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + size = resource_size(res); + /* The resources are divided into two equal memory and when + * we have HD output we can add them together + */ + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { + ch = vpif_obj.dev[j]; + ch->channel_id = j; + + /* only enabled if second resource exists */ + config_params.video_limit[ch->channel_id] = 0; + if (size) + config_params.video_limit[ch->channel_id] = + size/2; + } + } + for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) { ch = vpif_obj.dev[j]; /* Initialize field of the channel objects */ @@ -1823,7 +1834,7 @@ static __init int vpif_probe(struct platform_device *pdev) } v4l2_info(&vpif_obj.v4l2_dev, - "DM646x VPIF display driver initialized\n"); + " VPIF display driver initialized\n"); return 0; probe_subdev_out: @@ -1871,10 +1882,81 @@ static int vpif_remove(struct platform_device *device) return 0; } +#ifdef CONFIG_PM +static int vpif_suspend(struct device *dev) +{ + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (atomic_read(&ch->usrs) && common->io_usrs) { + /* Disable channel */ + if (ch->channel_id == VPIF_CHANNEL2_VIDEO) { + enable_channel2(0); + channel2_intr_enable(0); + } + if (ch->channel_id == VPIF_CHANNEL3_VIDEO || + common->started == 2) { + enable_channel3(0); + channel3_intr_enable(0); + } + } + mutex_unlock(&common->lock); + } + + return 0; +} + +static int vpif_resume(struct device *dev) +{ + + struct common_obj *common; + struct channel_obj *ch; + int i; + + for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) { + /* Get the pointer to the channel object */ + ch = vpif_obj.dev[i]; + common = &ch->common[VPIF_VIDEO_INDEX]; + mutex_lock(&common->lock); + if (atomic_read(&ch->usrs) && common->io_usrs) { + /* Enable channel */ + if (ch->channel_id == VPIF_CHANNEL2_VIDEO) { + enable_channel2(1); + channel2_intr_enable(1); + } + if (ch->channel_id == VPIF_CHANNEL3_VIDEO || + common->started == 2) { + enable_channel3(1); + channel3_intr_enable(1); + } + } + mutex_unlock(&common->lock); + } + + return 0; +} + +static const struct dev_pm_ops vpif_pm = { + .suspend = vpif_suspend, + .resume = vpif_resume, +}; + +#define vpif_pm_ops (&vpif_pm) +#else +#define vpif_pm_ops NULL +#endif + static __refdata struct platform_driver vpif_driver = { .driver = { .name = "vpif_display", .owner = THIS_MODULE, + .pm = vpif_pm_ops, }, .probe = vpif_probe, .remove = vpif_remove, diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h index 56879d1a0684..8967ffb44058 100644 --- a/drivers/media/video/davinci/vpif_display.h +++ b/drivers/media/video/davinci/vpif_display.h @@ -1,5 +1,5 @@ /* - * DM646x display header file + * VPIF display header file * * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ * @@ -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 */ @@ -158,6 +166,7 @@ struct vpif_config_params { u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS]; u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS]; + u32 video_limit[VPIF_DISPLAY_NUM_CHANNELS]; u8 min_numbuffers; }; |