From 020860ded7fdc61f0e09e3d0ef895fa977fcf7b0 Mon Sep 17 00:00:00 2001 From: jintao xu Date: Thu, 31 Aug 2017 16:21:23 +0800 Subject: [PATCH] ionvideo: omx support osd display PD#150258: omx support osd display Change-Id: I566e530e0ec2dc5e7eb73e33b90345552f6ae7fc Signed-off-by: jintao xu --- MAINTAINERS | 6 + arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts | 2 +- .../boot/dts/amlogic/gxl_p212_1g_buildroot.dts | 2 +- arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts | 2 +- .../boot/dts/amlogic/gxl_p212_2g_buildroot.dts | 2 +- arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts | 2 +- arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts | 2 +- .../boot/dts/amlogic/gxl_p231_2g_buildroot.dts | 2 +- arch/arm64/boot/dts/amlogic/gxl_skt.dts | 2 +- arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts | 2 +- arch/arm64/boot/dts/amlogic/gxm_skt.dts | 2 +- .../media/video_processor/ionvideo/Makefile | 1 - .../media/video_processor/ionvideo/ion_priv.h | 279 ---------- .../media/video_processor/ionvideo/ionvideo.c | 582 ++++++++------------- .../media/video_processor/ionvideo/ionvideo.h | 135 ++++- .../media/video_processor/ionvideo/videobuf2-ion.c | 334 ------------ .../media/video_processor/ionvideo/videobuf2-ion.h | 25 - 17 files changed, 363 insertions(+), 1019 deletions(-) delete mode 100644 drivers/amlogic/media/video_processor/ionvideo/ion_priv.h delete mode 100644 drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c delete mode 100644 drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h diff --git a/MAINTAINERS b/MAINTAINERS index 7c7a391f7..2801ac5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14056,3 +14056,9 @@ AMLOGIC ADD PARTITION NORMAL & AB DTS M: Xindong Xu F: arch/arm64/boot/dts/amlogic/partition_mbox_ab.dtsi F: arch/arm64/boot/dts/amlogic/partition_mbox_normal.dtsi + +AMLOGIC multimedia +M: JinTao Xu +F: drivers/amlogic/media/video_processor/ionvideo/ion_priv.h +F: drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c +F: drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h \ No newline at end of file diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts index a87429e..1e26019 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts @@ -81,7 +81,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_1g_buildroot.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_1g_buildroot.dts index 23111bd..8c6a0e5 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_1g_buildroot.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_1g_buildroot.dts @@ -81,7 +81,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts index 3fd649e..da5583a7 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts @@ -90,7 +90,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts b/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts index c7dfaf7..7084f79 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p212_2g_buildroot.dts @@ -82,7 +82,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts b/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts index 6b2aa49..39a3836 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p231_1g.dts @@ -82,7 +82,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts b/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts index 35274c7..a24d8b0 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p231_2g.dts @@ -82,7 +82,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_p231_2g_buildroot.dts b/arch/arm64/boot/dts/amlogic/gxl_p231_2g_buildroot.dts index 370f943..59fea62 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_p231_2g_buildroot.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_p231_2g_buildroot.dts @@ -82,7 +82,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxl_skt.dts b/arch/arm64/boot/dts/amlogic/gxl_skt.dts index 8395537..ac6ffe0 100644 --- a/arch/arm64/boot/dts/amlogic/gxl_skt.dts +++ b/arch/arm64/boot/dts/amlogic/gxl_skt.dts @@ -80,7 +80,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts index 67f5845..76b3f38 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts @@ -81,7 +81,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/arch/arm64/boot/dts/amlogic/gxm_skt.dts b/arch/arm64/boot/dts/amlogic/gxm_skt.dts index 773b4ee0..cbc9295 100644 --- a/arch/arm64/boot/dts/amlogic/gxm_skt.dts +++ b/arch/arm64/boot/dts/amlogic/gxm_skt.dts @@ -81,7 +81,7 @@ ion_reserved:linux,ion-dev { compatible = "shared-dma-pool"; reusable; - size = <0x0 0x2000000>; + size = <0x0 0x5000000>; alignment = <0x0 0x400000>; }; diff --git a/drivers/amlogic/media/video_processor/ionvideo/Makefile b/drivers/amlogic/media/video_processor/ionvideo/Makefile index 53f9cf7..54a0bea 100644 --- a/drivers/amlogic/media/video_processor/ionvideo/Makefile +++ b/drivers/amlogic/media/video_processor/ionvideo/Makefile @@ -1,5 +1,4 @@ asflags-y=-mfloat-abi=softfp -mfpu=neon ccflags-y += -Idrivers/staging/android/ion -obj-$(CONFIG_AMLOGIC_VIDEOBUF2_ION) += videobuf2-ion.o obj-$(CONFIG_AMLOGIC_IONVIDEO) += ionvideo.o ppmgr2.o diff --git a/drivers/amlogic/media/video_processor/ionvideo/ion_priv.h b/drivers/amlogic/media/video_processor/ionvideo/ion_priv.h deleted file mode 100644 index c301dbb..0000000 --- a/drivers/amlogic/media/video_processor/ionvideo/ion_priv.h +++ /dev/null @@ -1,279 +0,0 @@ -/* - * drivers/amlogic/media/video_processor/ionvideo/ion_priv.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ION_PRIV_H -#define _ION_PRIV_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct ion_buffer *ion_handle_buffer(struct ion_handle *handle); - -/** - * struct ion_buffer - metadata for a particular buffer - * @ref: refernce count - * @node: node in the ion_device buffers tree - * @dev: back pointer to the ion_device - * @heap: back pointer to the heap the buffer came from - * @flags: buffer specific flags - * @size: size of the buffer - * @priv_virt: private data to the buffer representable as - * a void * - * @priv_phys: private data to the buffer representable as - * an ion_phys_addr_t (and someday a phys_addr_t) - * @lock: protects the buffers cnt fields - * @kmap_cnt: number of times the buffer is mapped to the kernel - * @vaddr: the kenrel mapping if kmap_cnt is not zero - * @dmap_cnt: number of times the buffer is mapped for dma - * @sg_table: the sg table for the buffer if dmap_cnt is not zero - * @dirty: bitmask representing which pages of this buffer have - * been dirtied by the cpu and need cache maintenance - * before dma - * @vmas: list of vma's mapping this buffer - * @handle_count: count of handles referencing this buffer - * @task_comm: taskcomm of last client to reference this buffer in a - * handle, used for debugging - * @pid: pid of last client to reference this buffer in a - * handle, used for debugging - */ -struct ion_buffer { - struct kref ref; - struct rb_node node; - struct ion_device *dev; - struct ion_heap *heap; - unsigned long flags; - size_t size; - union { - void *priv_virt; - ion_phys_addr_t priv_phys; - }; - struct mutex lock; - int kmap_cnt; - void *vaddr; - int dmap_cnt; - struct sg_table *sg_table; - unsigned long *dirty; - struct list_head vmas; - /* used to track orphaned buffers */ - int handle_count; - char task_comm[TASK_COMM_LEN]; - pid_t pid; -}; - -/** - * struct ion_heap_ops - ops to operate on a given heap - * @allocate: allocate memory - * @free: free memory - * @phys get physical address of a buffer (only define on - * physically contiguous heaps) - * @map_dma map the memory for dma to a scatterlist - * @unmap_dma unmap the memory for dma - * @map_kernel map memory to the kernel - * @unmap_kernel unmap memory to the kernel - * @map_user map memory to userspace - */ -struct ion_heap_ops { - int (*allocate)(struct ion_heap *heap, - struct ion_buffer *buffer, unsigned long len, - unsigned long align, unsigned long flags); - void (*free)(struct ion_buffer *buffer); - int (*phys)(struct ion_heap *heap, struct ion_buffer *buffer, - ion_phys_addr_t *addr, size_t *len); - struct sg_table * (*map_dma)(struct ion_heap *heap, - struct ion_buffer *buffer); - void (*unmap_dma)(struct ion_heap *heap, struct ion_buffer *buffer); - void * (*map_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); - void (*unmap_kernel)(struct ion_heap *heap, struct ion_buffer *buffer); - int (*map_user)(struct ion_heap *mapper, struct ion_buffer *buffer, - struct vm_area_struct *vma); -}; - -/** - * struct ion_heap - represents a heap in the system - * @node: rb node to put the heap on the device's tree of heaps - * @dev: back pointer to the ion_device - * @type: type of heap - * @ops: ops struct as above - * @id: id of heap, also indicates priority of this heap when - * allocating. These are specified by platform data and - * MUST be unique - * @name: used for debugging - * @debug_show: called when heap debug file is read to add any - * heap specific debug info to output - * - * Represents a pool of memory from which buffers can be made. In some - * systems the only heap is regular system memory allocated via vmalloc. - * On others, some blocks might require large physically contiguous buffers - * that are allocated from a specially reserved heap. - */ -struct ion_heap { - struct plist_node node; - struct ion_device *dev; - enum ion_heap_type type; - struct ion_heap_ops *ops; - unsigned int id; - const char *name; - int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *); -}; - -/** - * ion_buffer_cached - this ion buffer is cached - * @buffer: buffer - * - * indicates whether this ion buffer is cached - */ -bool ion_buffer_cached(struct ion_buffer *buffer); - -/** - * ion_buffer_fault_user_mappings - fault in user mappings of this buffer - * @buffer: buffer - * - * indicates whether userspace mappings of this buffer will be faulted - * in, this can affect how buffers are allocated from the heap. - */ -bool ion_buffer_fault_user_mappings(struct ion_buffer *buffer); - -/** - * ion_device_create - allocates and returns an ion device - * @custom_ioctl: arch specific ioctl function if applicable - * - * returns a valid device or -PTR_ERR - */ -struct ion_device *ion_device_create(long (*custom_ioctl) - (struct ion_client *client, - unsigned int cmd, - unsigned long arg)); - -/** - * ion_device_destroy - free and device and it's resource - * @dev: the device - */ -void ion_device_destroy(struct ion_device *dev); - -/** - * ion_device_add_heap - adds a heap to the ion device - * @dev: the device - * @heap: the heap to add - */ -void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap); - -/** - * some helpers for common operations on buffers using the sg_table - * and vaddr fields - */ -void *ion_heap_map_kernel(struct ion_heap *heap, struct ion_buffer *buffer); -void ion_heap_unmap_kernel(struct ion_heap *heap, struct ion_buffer *buffer); -int ion_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer, - struct vm_area_struct *area); -int ion_heap_buffer_zero(struct ion_buffer *buffer); - - -/** - * functions for creating and destroying the built in ion heaps. - * architectures can add their own custom architecture specific - * heaps as appropriate. - */ - -struct ion_heap *ion_heap_create(struct ion_platform_heap *platform_heap); -void ion_heap_destroy(struct ion_heap *heap); - -struct ion_heap * - ion_system_heap_create(struct ion_platform_heap *platform_heap); - -void ion_system_heap_destroy(struct ion_heap *heap); - -struct ion_heap * - ion_system_contig_heap_create(struct ion_platform_heap *platform_heap); - -void ion_system_contig_heap_destroy(struct ion_heap *heap); - -struct ion_heap * - ion_carveout_heap_create(struct ion_platform_heap *platform_heap); - -void ion_carveout_heap_destroy(struct ion_heap *heap); - -struct ion_heap *ion_chunk_heap_create(struct ion_platform_heap *platform_heap); -void ion_chunk_heap_destroy(struct ion_heap *heap); -/** - * kernel api to allocate/free from carveout -- used when carveout is - * used to back an architecture specific custom heap - */ -ion_phys_addr_t ion_carveout_allocate(struct ion_heap *heap, unsigned long size, - unsigned long align); -void ion_carveout_free(struct ion_heap *heap, ion_phys_addr_t addr, - unsigned long size); -/** - * The carveout heap returns physical addresses, since 0 may be a valid - * physical address, this is used to indicate allocation failed - */ -#define ION_CARVEOUT_ALLOCATE_FAIL -1 - -/** - * functions for creating and destroying a heap pool -- allows you - * to keep a pool of pre allocated memory to use from your heap. Keeping - * a pool of memory that is ready for dma, ie any cached mapping have been - * invalidated from the cache, provides a significant performance benefit on - * many systems - */ - -/** - * struct ion_page_pool - pagepool struct - * @high_count: number of highmem items in the pool - * @low_count: number of lowmem items in the pool - * @high_items: list of highmem items - * @low_items: list of lowmem items - * @shrinker: a shrinker for the items - * @mutex: lock protecting this struct and especially the count - * item list - * @alloc: function to be used to allocate pageory when the pool - * is empty - * @free: function to be used to free pageory back to the system - * when the shrinker fires - * @gfp_mask: gfp_mask to use from alloc - * @order: order of pages in the pool - * @list: plist node for list of pools - * - * Allows you to keep a pool of pre allocated pages to use from your heap. - * Keeping a pool of pages that is ready for dma, ie any cached mapping have - * been invalidated from the cache, provides a significant performance benefit - * on many systems - */ -struct ion_page_pool { - int high_count; - int low_count; - struct list_head high_items; - struct list_head low_items; - struct mutex mutex; - void * (*alloc)(struct ion_page_pool *pool); - void (*free)(struct ion_page_pool *pool, struct page *page); - gfp_t gfp_mask; - unsigned int order; - struct plist_node list; -}; - -struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order); -void ion_page_pool_destroy(struct ion_page_pool *pool); -void *ion_page_pool_alloc(struct ion_page_pool *pool); -void ion_page_pool_free(struct ion_page_pool *pool, struct page *page); - -#endif /* _ION_PRIV_H */ diff --git a/drivers/amlogic/media/video_processor/ionvideo/ionvideo.c b/drivers/amlogic/media/video_processor/ionvideo/ionvideo.c index 8fd9f57..1760f89 100644 --- a/drivers/amlogic/media/video_processor/ionvideo/ionvideo.c +++ b/drivers/amlogic/media/video_processor/ionvideo/ionvideo.c @@ -23,14 +23,16 @@ #include #include #include +#include #define IONVIDEO_MODULE_NAME "ionvideo" #define IONVIDEO_VERSION "1.0" #define RECEIVER_NAME "ionvideo" +#define IONVIDEO_DEVICE_NAME "ionvideo" #define V4L2_CID_USER_AMLOGIC_IONVIDEO_BASE (V4L2_CID_USER_BASE + 0x1100) - +#define SCALE_4K_TO_1080P 1 static struct mutex ppmgr2_ge2d_canvas_mutex; static unsigned int video_nr_base = 13; @@ -226,13 +228,10 @@ static int canvas_is_valid(struct ionvideo_dev *dev, int index) #endif static int ionvideo_fillbuff(struct ionvideo_dev *dev, - struct ionvideo_buffer *buf) + struct v4l2_buffer *buf) { struct vframe_s *vf; -#ifdef IONVIDEO_DEBUG - struct vb2_buffer *vb = &(buf->vb); -#endif int ret = 0; /* ------------------------------------------------------- */ #if 0 @@ -256,26 +255,7 @@ static int ionvideo_fillbuff(struct ionvideo_dev *dev, } if (dev->freerun_mode == 0) { - if ((vf->type & 0x1) == VIDTYPE_INTERLACE) { - if ((dev->ppmgr2_dev.bottom_first - && (vf->type & 0x2)) || (dev - ->ppmgr2_dev - .bottom_first - == 0 - && ((vf - ->type - & 0x2) - == 0))) { - buf->pts = vf->pts; - buf->duration = vf->duration; - } - } else { - buf->pts = vf->pts; - buf->duration = vf->duration; - } -#ifdef IONVIDEO_DEBUG - ret = ppmgr2_process(vf, &dev->ppmgr2_dev, vb->v4l2_buf.index); -#endif + ret = ppmgr2_process(vf, &dev->ppmgr2_dev, buf->index); if (ret) { vf_put(vf, dev->vf_receiver_name); return ret; @@ -300,7 +280,19 @@ static int ionvideo_fillbuff(struct ionvideo_dev *dev, dev->ppmgr2_dev.dst_width = vf->width; if (vf->height <= dev->height) dev->ppmgr2_dev.dst_height = vf->height; - +#if SCALE_4K_TO_1080P + if (vf->width > dev->width || vf->height > dev->height) { + if (vf->width*dev->height >= dev->width*vf->height) { + dev->ppmgr2_dev.dst_width = dev->width; + dev->ppmgr2_dev.dst_height = vf->height + * dev->width / vf->width; + } else { + dev->ppmgr2_dev.dst_width = vf->width + * dev->height / vf->height; + dev->ppmgr2_dev.dst_height = dev->height; + } + } +#endif if ((dev->ppmgr2_dev.dst_width >= 1920) && (dev->ppmgr2_dev .dst_height >= 1080) @@ -312,21 +304,22 @@ static int ionvideo_fillbuff(struct ionvideo_dev *dev, * scaling_rate / 100; } -#ifdef IONVIDEO_DEBUG - ret = ppmgr2_process(vf, &dev->ppmgr2_dev, vb->v4l2_buf.index); -#endif + ret = ppmgr2_process(vf, &dev->ppmgr2_dev, buf->index); if (ret) { vf_put(vf, dev->vf_receiver_name); return ret; } videoc_omx_compute_pts(dev, vf); + buf->timecode.frames = 0; + if (vf->flag & VFRAME_FLAG_ERROR_RECOVERY) + buf->timecode.frames |= 1; + if (vf->flag & VFRAME_FLAG_SYNCFRAME) + buf->timecode.frames |= 2; vf_put(vf, dev->vf_receiver_name); -#ifdef IONVIDEO_DEBUG - buf->vb.v4l2_buf.timestamp.tv_sec = dev->pts >> 32; - buf->vb.v4l2_buf.timestamp.tv_usec = dev->pts & 0xFFFFFFFF; - buf->vb.v4l2_buf.timecode.type = dev->ppmgr2_dev.dst_width; - buf->vb.v4l2_buf.timecode.flags = dev->ppmgr2_dev.dst_height; -#endif + buf->timestamp.tv_sec = dev->pts >> 32; + buf->timestamp.tv_usec = dev->pts & 0xFFFFFFFF; + buf->timecode.type = dev->ppmgr2_dev.dst_width; + buf->timecode.flags = dev->ppmgr2_dev.dst_height; } /* ------------------------------------------------------- */ return 0; @@ -348,8 +341,7 @@ static int ionvideo_size_changed(struct ionvideo_dev *dev, int aw, int ah) static void ionvideo_thread_tick(struct ionvideo_dev *dev) { struct ionvideo_dmaqueue *dma_q = &dev->vidq; - struct ionvideo_buffer *buf; - unsigned long flags = 0; + struct v4l2_buffer *buf; struct vframe_s *vf; int w, h; @@ -360,6 +352,14 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev) if (!dev) return; + if (dev->active_state == ION_INACTIVE_REQ) { + dev->active_state = ION_INACTIVE; + complete(&dev->inactive_done); + } + + if (dev->active_state == ION_INACTIVE) + return; + vf = vf_peek(dev->vf_receiver_name); if (!vf) { dev->vf_wait_cnt++; @@ -384,28 +384,25 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev) usleep_range(4000, 5000); return; } - spin_lock_irqsave(&dev->slock, flags); - if (list_empty(&dma_q->active)) { + mutex_lock(&dev->mutex_input); + if (v4l2q_empty(&dev->input_queue)) { dprintk(dev, 3, "No active queue to serve\n"); - spin_unlock_irqrestore(&dev->slock, flags); + mutex_unlock(&dev->mutex_input); schedule_timeout_interruptible(msecs_to_jiffies(20)); return; } - buf = list_entry(dma_q->active.next, struct ionvideo_buffer, list); - spin_unlock_irqrestore(&dev->slock, flags); + buf = v4l2q_pop(&dev->input_queue); + mutex_unlock(&dev->mutex_input); /* Fill buffer */ if (ionvideo_fillbuff(dev, buf)) return; dev->vf_wait_cnt = 0; - spin_lock_irqsave(&dev->slock, flags); - list_del(&buf->list); - spin_unlock_irqrestore(&dev->slock, flags); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); + mutex_lock(&dev->mutex_output); + v4l2q_push(&dev->output_queue, buf); dma_q->vb_ready++; -#ifdef IONVIDEO_DEBUG - dprintk(dev, 4, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); -#endif + mutex_unlock(&dev->mutex_output); + dprintk(dev, 4, "[%p/%d] done\n", buf, buf->index); } #define frames_to_ms(frames) \ @@ -455,11 +452,13 @@ static int ionvideo_thread(void *data) return 0; } -static int ionvideo_start_generating(struct ionvideo_dev *dev) +static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct ionvideo_dev *dev = video_drvdata(file); struct ionvideo_dmaqueue *dma_q = &dev->vidq; dev->is_omx_video_started = 1; + dma_q->vb_ready = 0; dprintk(dev, 2, "%s\n", __func__); @@ -483,8 +482,9 @@ static int ionvideo_start_generating(struct ionvideo_dev *dev) return 0; } -static void ionvideo_stop_generating(struct ionvideo_dev *dev) +static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct ionvideo_dev *dev = video_drvdata(file); struct ionvideo_dmaqueue *dma_q = &dev->vidq; dprintk(dev, 2, "%s\n", __func__); @@ -500,158 +500,9 @@ static void ionvideo_stop_generating(struct ionvideo_dev *dev) * Typical driver might need to wait here until dma engine stops. * In this case we can abort imiedetly, so it's just a noop. */ - - /* Release all active buffers */ - while (!list_empty(&dma_q->active)) { - struct ionvideo_buffer *buf; - - buf = list_entry(dma_q->active.next, struct ionvideo_buffer, - list); - list_del(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); -#ifdef IONVIDEO_DEBUG - dprintk(dev, 2, "[%p/%d] done\n", buf, buf->vb.v4l2_buf.index); -#endif - } -} -/* ------------------------------------------------------------------ - * Videobuf operations - * ------------------------------------------------------------------ - */ -#ifdef IONVIDEO_DEBUG -static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], void *alloc_ctxs[]) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vq); - unsigned long size; - - if (fmt) - size = fmt->fmt.pix.sizeimage; - else - size = (dev->width * dev->height * dev->pixelsize) >> 3; - - if (size == 0) - return -EINVAL; - - if (*nbuffers == 0) - *nbuffers = 32; - - while (size * *nbuffers > vid_limit * MAX_WIDTH * MAX_HEIGHT) - (*nbuffers)--; - - *nplanes = 1; - - sizes[0] = size; - - /* - * videobuf2-vmalloc allocator is context-less so no need to set - * alloc_ctxs array. - */ - - dprintk(dev, 2, "%s, count=%d, size=%ld\n", __func__, *nbuffers, size); - - return 0; -} -#endif - -static int buffer_prepare(struct vb2_buffer *vb) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct ionvideo_buffer *buf = container_of(vb, struct ionvideo_buffer, - vb); - unsigned long size; -#ifdef IONVIDEO_DEBUG - dprintk(dev, 2, "%s, field=%d\n", __func__, vb->v4l2_buf.field); -#endif - WARN_ON(dev->fmt == NULL); - - /* - * Theses properties only change when queue is idle, see s_fmt. - * The below checks should not be performed here, on each - * buffer_prepare (i.e. on each qbuf). Most of the code in this function - * should thus be moved to buffer_init and s_fmt. - */ - if (dev->width < 48 || dev->width > MAX_WIDTH - || dev->height < 32 || dev->height > MAX_HEIGHT) - return -EINVAL; - - size = (dev->width * dev->height * dev->pixelsize) >> 3; - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(&buf->vb, 0, size); - - buf->fmt = dev->fmt; - return 0; } -static void buffer_queue(struct vb2_buffer *vb) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct ionvideo_buffer *buf = container_of(vb, struct ionvideo_buffer, - vb); - struct ionvideo_dmaqueue *vidq = &dev->vidq; - unsigned long flags = 0; - - dprintk(dev, 2, "%s\n", __func__); - - spin_lock_irqsave(&dev->slock, flags); - list_add_tail(&buf->list, &vidq->active); - spin_unlock_irqrestore(&dev->slock, flags); -} - -static int start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vq); - struct ionvideo_dmaqueue *dma_q = &dev->vidq; - - dev->is_actived = 1; - dma_q->vb_ready = 0; - dprintk(dev, 2, "%s\n", __func__); - return ionvideo_start_generating(dev); -} - -/* abort streaming and wait for last buffer */ -static void stop_streaming(struct vb2_queue *vq) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vq); - - dev->is_actived = 0; - dprintk(dev, 2, "%s\n", __func__); - ionvideo_stop_generating(dev); -} - -static void ionvideo_lock(struct vb2_queue *vq) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vq); - - mutex_lock(&dev->mutex); -} - -static void ionvideo_unlock(struct vb2_queue *vq) -{ - struct ionvideo_dev *dev = vb2_get_drv_priv(vq); - - mutex_unlock(&dev->mutex); -} - -static const struct vb2_ops ionvideo_video_qops = { -#ifdef IONVIDEO_DEBUG - .queue_setup = queue_setup, -#endif - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .start_streaming = start_streaming, - .stop_streaming = stop_streaming, - .wait_prepare = ionvideo_unlock, - .wait_finish = ionvideo_lock, -}; - /* ------------------------------------------------------------------ * IOCTL vidioc handling * ------------------------------------------------------------------ @@ -678,23 +529,22 @@ static int vidioc_open(struct file *file) dprintk(dev, 2, "vidioc_open\n"); IONVID_INFO("ionvideo open\n"); init_waitqueue_head(&dev->wq); - return v4l2_fh_open(file); + return 0; } -static int vidioc_release(struct file *file) +static int vidioc_close(struct file *file) { struct ionvideo_dev *dev = video_drvdata(file); - ionvideo_stop_generating(dev); - IONVID_INFO("ionvideo_stop_generating!!!!\n"); + IONVID_INFO("vidioc_close!!!!\n"); ppmgr2_release(&(dev->ppmgr2_dev)); - dprintk(dev, 2, "vidioc_release\n"); - IONVID_INFO("ionvideo release\n"); + dprintk(dev, 2, "vidioc_close\n"); + IONVID_INFO("vidioc_close\n"); if (dev->fd_num > 0) dev->fd_num--; dev->once_record = 0; - return vb2_fop_release(file); + return 0; } static int vidioc_querycap(struct file *file, void *priv, @@ -731,9 +581,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct ionvideo_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; - int ret = 0; - unsigned long flags; if (dev->freerun_mode == 0) { if (dev->c_width == 0 || dev->c_height == 0) @@ -741,11 +588,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = dev->c_width; f->fmt.pix.height = dev->c_height; - spin_lock_irqsave(&q->done_lock, flags); - ret = list_empty(&q->done_list); - spin_unlock_irqrestore(&q->done_lock, flags); - if (!ret) - return -EAGAIN; } else { f->fmt.pix.width = dev->width; @@ -793,17 +635,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct ionvideo_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_vidq; int ret = vidioc_try_fmt_vid_cap(file, priv, f); if (ret < 0) return ret; - if (vb2_is_busy(q)) { - dprintk(dev, 1, "%s device busy\n", __func__); - return -EBUSY; - } dev->fmt = get_format(f); dev->pixelsize = dev->fmt->depth; dev->width = f->fmt.pix.width; @@ -814,46 +651,31 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - static const struct v4l2_frmsize_stepwise sizes = { - 48, MAX_WIDTH, 4, 32, MAX_HEIGHT, 1}; - int i; - - if (fsize->index) - return -EINVAL; - for (i = 0; i < ARRAY_SIZE(formats); i++) - if (formats[i].fourcc == fsize->pixel_format) - break; - if (i == ARRAY_SIZE(formats)) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise = sizes; - return 0; -} - static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct ionvideo_dev *dev = video_drvdata(file); struct ionvideo_dmaqueue *dma_q = &dev->vidq; struct ppmgr2_device *ppmgr2_dev = &(dev->ppmgr2_dev); - int ret = 0; + struct dma_buf *dbuf = NULL; + struct ion_buffer *buffer = NULL; + struct sg_table *table = NULL; + struct page *page = NULL; + void *phy_addr = NULL; - p->length = 0; - ret = vb2_ioctl_qbuf(file, priv, p); - if (ret != 0) - return ret; + dev->ionvideo_input[p->index] = *p; + mutex_lock(&dev->mutex_input); + v4l2q_push(&dev->input_queue, &(dev->ionvideo_input[p->index])); + mutex_unlock(&dev->mutex_input); if (!ppmgr2_dev->phy_addr[p->index]) { - struct vb2_buffer *vb; - struct vb2_queue *q; - void *phy_addr = NULL; + dbuf = dma_buf_get(p->m.fd); + buffer = dbuf->priv; + table = buffer->sg_table; + page = sg_page(table->sgl); + phy_addr = (void *)PFN_PHYS(page_to_pfn(page)); + dma_buf_put(dbuf); - q = dev->vdev.queue; - vb = q->bufs[p->index]; - phy_addr = vb2_plane_cookie(vb, 0); ppmgr2_dev->phy_addr[p->index] = phy_addr; ppmgr2_dev->dst_buffer_width = ALIGN(dev->width, 32); ppmgr2_dev->dst_buffer_height = dev->height; @@ -870,9 +692,10 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) } } wake_up_interruptible(&dma_q->wq); - return ret; + return 0; } +/* static int vidioc_synchronization_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { @@ -886,7 +709,6 @@ static int vidioc_synchronization_dqbuf(struct file *file, void *priv, q = dev->vdev.queue; if (dev->receiver_register) { - /* clear the frame buffer queue */ while (!list_empty(&q->done_list)) { ret = vb2_ioctl_dqbuf(file, priv, p); if (ret) @@ -983,65 +805,43 @@ static int vidioc_synchronization_dqbuf(struct file *file, void *priv, return 0; } +*/ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) { struct ionvideo_dev *dev = video_drvdata(file); struct ionvideo_dmaqueue *dma_q = &dev->vidq; - int ret = 0; + struct v4l2_buffer *out_put = NULL; +/* if (dev->freerun_mode == 0) return vidioc_synchronization_dqbuf(file, priv, p); +*/ - ret = vb2_ioctl_dqbuf(file, priv, p); - if (ret == 0) - dma_q->vb_ready--; - return ret; -} - -#define NUM_INPUTS 10 -/* only one input in this sample driver */ -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index >= NUM_INPUTS) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - sprintf(inp->name, "Camera %u", inp->index); - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct ionvideo_dev *dev = video_drvdata(file); + mutex_lock(&dev->mutex_output); + out_put = v4l2q_pop(&dev->output_queue); - *i = dev->input; + if (out_put != NULL) { + dma_q->vb_ready--; + *p = *out_put; + } else { + mutex_unlock(&dev->mutex_output); + return -EAGAIN; + } + mutex_unlock(&dev->mutex_output); return 0; } -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct ionvideo_dev *dev = video_drvdata(file); - - if (i >= NUM_INPUTS) - return -EINVAL; - - if (i == dev->input) - return 0; - - dev->input = i; - return 0; -} +#define NUM_INPUTS 10 /* ------------------------------------------------------------------ * File operations for the device * ------------------------------------------------------------------ */ -static const struct v4l2_file_operations ionvideo_fops = { +static const struct v4l2_file_operations ionvideo_v4l2_fops = { .owner = THIS_MODULE, .open = vidioc_open, - .release = vidioc_release, + .release = vidioc_close, .read = vb2_fop_read, .poll = vb2_fop_poll, .unlocked_ioctl = video_ioctl2,/* V4L2 ioctl handler */ @@ -1054,29 +854,18 @@ static const struct v4l2_ioctl_ops ionvideo_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, .vidioc_s_ctrl = vidioc_s_ctrl, }; static const struct video_device ionvideo_template = { .name = "ionvideo", - .fops = &ionvideo_fops, + .fops = &ionvideo_v4l2_fops, .ioctl_ops = &ionvideo_ioctl_ops, - .release = video_device_release_empty, + .release = video_device_release, }; /* ----------------------------------------------------------------- @@ -1084,7 +873,7 @@ static const struct video_device ionvideo_template = { * ----------------------------------------------------------------- */ /* struct vb2_dc_conf * ionvideo_dma_ctx = NULL; */ -static int ionvideo_release(void) +static int ionvideo_v4l2_release(void) { struct ionvideo_dev *dev; struct list_head *list; @@ -1116,49 +905,45 @@ static int ionvideo_release(void) static int video_receiver_event_fun(int type, void *data, void *private_data) { -#ifdef CONFIG_AM_VOUT - char *configured[2]; - char framerate[20] = {0}; -#endif struct ionvideo_dev *dev = (struct ionvideo_dev *)private_data; if (type == VFRAME_EVENT_PROVIDER_UNREG) { dev->receiver_register = 0; dev->is_omx_video_started = 0; + if (dev->active_state == ION_ACTIVE) { + /*if player killed thread may have exit.*/ + dev->active_state = ION_INACTIVE_REQ; + wait_for_completion_timeout(&dev->inactive_done, + msecs_to_jiffies(100)); + } + /*tsync_avevent(VIDEO_STOP, 0);*/ IONVID_INFO("unreg:ionvideo\n"); } else if (type == VFRAME_EVENT_PROVIDER_REG) { dev->receiver_register = 1; dev->is_omx_video_started = 1; dev->ppmgr2_dev.interlaced_num = 0; + dev->active_state = ION_ACTIVE; + init_completion(&dev->inactive_done); + + v4l2q_init(&dev->input_queue, IONVIDEO_POOL_SIZE + 1, + &dev->ionvideo_input_queue[0]); + v4l2q_init(&dev->output_queue, IONVIDEO_POOL_SIZE + 1, + &dev->ionvideo_output_queue[0]); IONVID_INFO("reg:ionvideo\n"); } else if (type == VFRAME_EVENT_PROVIDER_QUREY_STATE) { if (dev->vf_wait_cnt > 1) return RECEIVER_INACTIVE; return RECEIVER_ACTIVE; } else if (type == VFRAME_EVENT_PROVIDER_FR_HINT) { - if ((data != NULL) && (ionvideo_seek_flag == 0)) { #ifdef CONFIG_AM_VOUT - /*set_vframe_rate_hint((unsigned long)(data));*/ - sprintf(framerate, "FRAME_RATE_HINT=%lu", - (unsigned long)data); - configured[0] = framerate; - configured[1] = NULL; - kobject_uevent_env(&(dev->vdev.dev.kobj), - KOBJ_CHANGE, configured); - pr_info("%s: sent uevent %s\n", - __func__, configured[0]); + if ((data != NULL) && (ionvideo_seek_flag == 0)) + set_vframe_rate_hint((unsigned long)(data)); #endif - } } else if (type == VFRAME_EVENT_PROVIDER_FR_END_HINT) { #ifdef CONFIG_AM_VOUT if (ionvideo_seek_flag == 0) { - configured[0] = "FRAME_RATE_END_HINT"; - configured[1] = NULL; - kobject_uevent_env(&(dev->vdev.dev.kobj), - KOBJ_CHANGE, configured); - pr_info("%s: sent uevent %s\n", - __func__, configured[0]); + set_vframe_rate_end_hint(); } #endif } @@ -1174,7 +959,6 @@ static int __init ionvideo_create_instance(int inst) { struct ionvideo_dev *dev; struct video_device *vfd; - struct vb2_queue *q; int ret; unsigned long flags; @@ -1199,26 +983,6 @@ static int __init ionvideo_create_instance(int inst) /* initialize locks */ spin_lock_init(&dev->slock); - /* initialize queue */ - q = &dev->vb_vidq; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct ionvideo_buffer); - q->ops = &ionvideo_video_qops; - q->mem_ops = &vb2_ion_memops; -#ifdef IONVIDEO_DEBUG - q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; -#else - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; -#endif - -#ifdef IONVIDEO_DEBUG - ret = vb2_queue_init(q); - if (ret) - goto unreg_dev; -#endif - mutex_init(&dev->mutex); /* init video dma queues */ @@ -1230,23 +994,19 @@ static int __init ionvideo_create_instance(int inst) *vfd = ionvideo_template; vfd->dev_debug = debug; vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = q; -#ifdef IONVIDEO_DEBUG - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); -#endif /* * Provide a mutex to v4l2 core. It will be used to protect * all fops and v4l2 ioctls. */ - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); ret = video_register_device(vfd, VFL_TYPE_GRABBER, inst + video_nr_base); if (ret < 0) goto unreg_dev; + video_set_drvdata(vfd, dev); + dev->inst = inst; snprintf(dev->vf_receiver_name, ION_VF_RECEIVER_NAME_SIZE, (inst == 0) ? RECEIVER_NAME : RECEIVER_NAME ".%x", @@ -1264,6 +1024,9 @@ static int __init ionvideo_create_instance(int inst) list_add_tail(&dev->ionvideo_devlist, &ionvideo_devlist); ionvideo_devlist_unlock(flags); + mutex_init(&dev->mutex_input); + mutex_init(&dev->mutex_output); + return 0; unreg_dev: @@ -1284,9 +1047,7 @@ int ionvideo_assign_map(char **receiver_name, int *inst) list_for_each(p, &ionvideo_devlist) { dev = list_entry(p, struct ionvideo_dev, ionvideo_devlist); - if ((dev->inst == *inst) && (!dev->mapped)) { - dev->mapped = true; - *inst = dev->inst; + if (dev->inst == *inst) { *receiver_name = dev->vf_receiver_name; ionvideo_devlist_unlock(flags); return 0; @@ -1297,8 +1058,9 @@ int ionvideo_assign_map(char **receiver_name, int *inst) return -ENODEV; } +EXPORT_SYMBOL(ionvideo_assign_map); -int ionvideo_alloc_map(char **receiver_name, int *inst) +int ionvideo_alloc_map(int *inst) { unsigned long flags; struct ionvideo_dev *dev = NULL; @@ -1312,7 +1074,6 @@ int ionvideo_alloc_map(char **receiver_name, int *inst) if ((dev->inst >= 0) && (!dev->mapped)) { dev->mapped = true; *inst = dev->inst; - *receiver_name = dev->vf_receiver_name; ionvideo_devlist_unlock(flags); return 0; } @@ -1424,6 +1185,67 @@ __ATTR_NULL }; static struct class ionvideo_class = {.name = "ionvideo", .class_attrs = ion_video_class_attrs, }; +static int ionvideo_open(struct inode *inode, struct file *file) +{ + return 0; +} + +static int ionvideo_release(struct inode *inode, struct file *file) +{ + return 0; +} + +static long ionvideo_ioctl(struct file *file, + unsigned int cmd, + ulong arg) +{ + long ret = 0; + void __user *argp = (void __user *)arg; + + switch (cmd) { + case IONVIDEO_IOCTL_ALLOC_ID:{ + u32 ionvideo_id = 0; + + ret = ionvideo_alloc_map(&ionvideo_id); + if (ret != 0) + break; + put_user(ionvideo_id, (u32 __user *)argp); + } + break; + case IONVIDEO_IOCTL_FREE_ID:{ + u32 ionvideo_id; + + get_user(ionvideo_id, (u32 __user *)argp); + ionvideo_release_map(ionvideo_id); + } + break; + default: + return -EINVAL; + } + return ret; +} + +#ifdef CONFIG_COMPAT +static long ionvideo_compat_ioctl(struct file *file, + unsigned int cmd, + ulong arg) +{ + long ret = 0; + + ret = ionvideo_ioctl(file, cmd, (ulong)compat_ptr(arg)); + return ret; +} +#endif +static const struct file_operations ionvideo_fops = { + .owner = THIS_MODULE, + .open = ionvideo_open, + .release = ionvideo_release, + .unlocked_ioctl = ionvideo_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = ionvideo_compat_ioctl, +#endif + .poll = NULL, +}; /* This routine allocates from 1 to n_devs virtual drivers. * The real maximum number of virtual drivers will depend on how many drivers * will succeed. This is limited to the maximum number of devices that @@ -1433,9 +1255,6 @@ static int ionvideo_driver_probe(struct platform_device *pdev) { int ret = 0, i; - ret = class_register(&ionvideo_class); - if (ret < 0) - return ret; if (n_devs <= 0) n_devs = 1; @@ -1468,8 +1287,7 @@ static int ionvideo_driver_probe(struct platform_device *pdev) static int ionvideo_drv_remove(struct platform_device *pdev) { - ionvideo_release(); - class_unregister(&ionvideo_class); + ionvideo_v4l2_release(); return 0; } @@ -1492,17 +1310,49 @@ static struct platform_driver ionvideo_drv = { static int __init ionvideo_init(void) { + int ret = -1; + struct device *devp; + + ret = class_register(&ionvideo_class); + if (ret < 0) + return ret; + + ret = register_chrdev(IONVIDEO_MAJOR, "ionvideo", &ionvideo_fops); + if (ret < 0) { + pr_err("Can't allocate major for ionvideo device\n"); + goto error1; + } + + devp = device_create(&ionvideo_class, + NULL, + MKDEV(IONVIDEO_MAJOR, 0), + NULL, + IONVIDEO_DEVICE_NAME); + if (IS_ERR(devp)) { + pr_err("failed to create ionvideo device node\n"); + ret = PTR_ERR(devp); + return ret; + } + if (platform_driver_register(&ionvideo_drv)) { pr_err("Failed to register ionvideo driver\n"); return -ENODEV; } - return 0; + +error1: + unregister_chrdev(IONVIDEO_MAJOR, "ionvideo"); + class_unregister(&ionvideo_class); + return ret; + } static void __exit ionvideo_exit(void) { platform_driver_unregister(&ionvideo_drv); + device_destroy(&ionvideo_class, MKDEV(IONVIDEO_MAJOR, 0)); + unregister_chrdev(IONVIDEO_MAJOR, IONVIDEO_DEVICE_NAME); + class_unregister(&ionvideo_class); } MODULE_DESCRIPTION("Video Technology Magazine Ion Video Capture Board"); diff --git a/drivers/amlogic/media/video_processor/ionvideo/ionvideo.h b/drivers/amlogic/media/video_processor/ionvideo/ionvideo.h index a5a4a6a..14bb5f9 100644 --- a/drivers/amlogic/media/video_processor/ionvideo/ionvideo.h +++ b/drivers/amlogic/media/video_processor/ionvideo/ionvideo.h @@ -35,7 +35,6 @@ #include #include #include -#include #include /* #include */ @@ -48,7 +47,6 @@ #include #include -#include "videobuf2-ion.h" /* Wake up at about 30 fps */ #define WAKE_NUMERATOR 30 @@ -57,6 +55,8 @@ #define MAX_WIDTH 4096 #define MAX_HEIGHT 4096 +#define IONVIDEO_POOL_SIZE 16 + #define IONVID_INFO(fmt, args...) pr_info("ionvid: info: "fmt"", ## args) #define IONVID_DBG(fmt, args...) pr_debug("ionvid: dbg: "fmt"", ## args) #define IONVID_ERR(fmt, args...) pr_err("ionvid: err: "fmt"", ## args) @@ -74,6 +74,92 @@ do { \ #define PPMGR2_CANVAS_INDEX_SRC (PPMGR2_CANVAS_INDEX + 3) +struct v4l2q_s { + int rp; + int wp; + int size; + int pre_rp; + int pre_wp; + struct v4l2_buffer **pool; +}; + +static inline void v4l2q_lookup_start(struct v4l2q_s *q) +{ + q->pre_rp = q->rp; + q->pre_wp = q->wp; +} +static inline void v4l2q_lookup_end(struct v4l2q_s *q) +{ + q->rp = q->pre_rp; + q->wp = q->pre_wp; +} + +static inline void v4l2q_init(struct v4l2q_s *q, u32 size, + struct v4l2_buffer **pool) +{ + q->rp = q->wp = 0; + q->size = size; + q->pool = pool; +} + +static inline bool v4l2q_empty(struct v4l2q_s *q) +{ + return q->rp == q->wp; +} + +static inline void v4l2q_push(struct v4l2q_s *q, struct v4l2_buffer *vf) +{ + int wp = q->wp; + + /*ToDo*/ + smp_mb(); + + q->pool[wp] = vf; + + /*ToDo*/ + smp_wmb(); + + q->wp = (wp == (q->size - 1)) ? 0 : (wp + 1); +} + +static inline struct v4l2_buffer *v4l2q_pop(struct v4l2q_s *q) +{ + struct v4l2_buffer *vf; + int rp; + + if (v4l2q_empty(q)) + return NULL; + + rp = q->rp; + + /*ToDo*/ + smp_rmb(); + + vf = q->pool[rp]; + + /*ToDo*/ + smp_mb(); + + q->rp = (rp == (q->size - 1)) ? 0 : (rp + 1); + + return vf; +} + +static inline struct v4l2_buffer *v4l2q_peek(struct v4l2q_s *q) +{ + return (v4l2q_empty(q)) ? NULL : q->pool[q->rp]; +} + +static inline int v4l2q_level(struct v4l2q_s *q) +{ + int level = q->wp - q->rp; + + if (level < 0) + level += q->size; + + return level; +} + /* ------------------------------------------------------------------ * Basic structures * ------------------------------------------------------------------ @@ -89,7 +175,6 @@ struct ionvideo_fmt { /* buffer for one video frame */ struct ionvideo_buffer { /* common v4l buffer stuff -- must be first */ - struct vb2_buffer vb; struct list_head list; const struct ionvideo_fmt *fmt; u64 pts; @@ -131,6 +216,35 @@ struct ppmgr2_device { #define ION_VF_RECEIVER_NAME_SIZE 32 +#define ION_ACTIVE 0 +#define ION_INACTIVE_REQ 1 +#define ION_INACTIVE 2 + +struct ion_buffer { + struct kref ref; + union { + struct rb_node node; + struct list_head list; + }; + struct ion_device *dev; + struct ion_heap *heap; + unsigned long flags; + unsigned long private_flags; + size_t size; + void *priv_virt; + struct mutex lock; + int kmap_cnt; + void *vaddr; + int dmap_cnt; + struct sg_table *sg_table; + struct page **pages; + struct list_head vmas; + /* used to track orphaned buffers */ + int handle_count; + char task_comm[TASK_COMM_LEN]; + pid_t pid; +}; + struct ionvideo_dev { struct list_head ionvideo_devlist; struct v4l2_device v4l2_dev; @@ -154,7 +268,6 @@ struct ionvideo_dev { const struct ionvideo_fmt *fmt; unsigned int width, height; unsigned int c_width, c_height; - struct vb2_queue vb_vidq; unsigned int field_count; unsigned int pixelsize; @@ -179,6 +292,16 @@ struct ionvideo_dev { bool mapped; bool thread_stopped; int vf_wait_cnt; + int active_state; + struct completion inactive_done; + + struct v4l2q_s input_queue; + struct v4l2q_s output_queue; + struct v4l2_buffer *ionvideo_input_queue[IONVIDEO_POOL_SIZE + 1]; + struct v4l2_buffer *ionvideo_output_queue[IONVIDEO_POOL_SIZE + 1]; + struct mutex mutex_input; + struct mutex mutex_output; + struct v4l2_buffer ionvideo_input[IONVIDEO_POOL_SIZE + 1]; }; unsigned int get_ionvideo_debug(void); @@ -196,4 +319,8 @@ void ppmgr2_set_mirror(struct ppmgr2_device *ppd, int mirror); void ppmgr2_set_paint_mode(struct ppmgr2_device *ppd, int paint_mode); int v4l_to_ge2d_format(int v4l2_format); +#define IONVIDEO_IOC_MAGIC 'I' +#define IONVIDEO_IOCTL_ALLOC_ID _IOW(IONVIDEO_IOC_MAGIC, 0x00, int) +#define IONVIDEO_IOCTL_FREE_ID _IOW(IONVIDEO_IOC_MAGIC, 0x01, int) + #endif diff --git a/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c b/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c deleted file mode 100644 index 2039af4..0000000 --- a/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/*#include */ -#include -#include "ion_priv.h" -#include "videobuf2-ion.h" - -struct vb2_ion_buf { - void *vaddr; - struct page **pages; - struct vm_area_struct *vma; - int write; - unsigned long size; - unsigned int n_pages; - atomic_t refcount; - struct vb2_vmarea_handler handler; - struct dma_buf *dbuf; -}; - -static void vb2_ion_put(void *buf_priv); - -#ifdef IONVIDEO_DEBUG -static void *vb2_ion_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags) -{ - struct vb2_ion_buf *buf; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL | gfp_flags); - if (!buf) - return NULL; - - buf->size = size; - buf->vaddr = vmalloc_user(buf->size); - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_ion_put; - buf->handler.arg = buf; - - if (!buf->vaddr) { - pr_debug("ion of size %ld failed\n", buf->size); - kfree(buf); - return NULL; - } - - atomic_inc(&buf->refcount); - return buf; -} -#endif - -static void vb2_ion_put(void *buf_priv) -{ - struct vb2_ion_buf *buf = buf_priv; - - if (atomic_dec_and_test(&buf->refcount)) { - vfree(buf->vaddr); - kfree(buf); - } -} - -#ifdef IONVIDEO_DEBUG -static void *vb2_ion_get_userptr(void *alloc_ctx, unsigned long vaddr, - unsigned long size, int write) -{ - struct vb2_ion_buf *buf; - unsigned long first, last; - int n_pages, offset; - struct vm_area_struct *vma; - dma_addr_t physp; - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return NULL; - - buf->write = write; - offset = vaddr & ~PAGE_MASK; - buf->size = size; - - vma = find_vma(current->mm, vaddr); - if (vma && (vma->vm_flags & VM_PFNMAP) && (vma->vm_pgoff)) { -#ifdef IONVIDEO_DEBUG - if (vb2_get_contig_userptr(vaddr, size, &vma, &physp)) - goto fail_pages_array_alloc; -#endif - buf->vma = vma; - buf->vaddr = ioremap_nocache(physp, size); - if (!buf->vaddr) - goto fail_pages_array_alloc; - } else { - first = vaddr >> PAGE_SHIFT; - last = (vaddr + size - 1) >> PAGE_SHIFT; - buf->n_pages = last - first + 1; - buf->pages = kcalloc(buf->n_pages, sizeof(struct page *), - GFP_KERNEL); - if (!buf->pages) - goto fail_pages_array_alloc; - - /* current->mm->mmap_sem is taken by videobuf2 core */ -#ifdef IONVIDEO_DEBUG - n_pages = get_user_pages(current, current->mm, - vaddr & PAGE_MASK, buf->n_pages, - write, 1, /* force */ - buf->pages, NULL); -#endif - if (n_pages != buf->n_pages) - goto fail_get_user_pages; - - buf->vaddr = vm_map_ram(buf->pages, buf->n_pages, -1, - PAGE_KERNEL); - if (!buf->vaddr) - goto fail_get_user_pages; - } - - buf->vaddr += offset; - return buf; - -fail_get_user_pages: - pr_debug("get_user_pages requested/got: %d/%d]\n", n_pages, - buf->n_pages); - while (--n_pages >= 0) - put_page(buf->pages[n_pages]); - kfree(buf->pages); - -fail_pages_array_alloc: kfree(buf); - - return NULL; -} -#endif - -static void vb2_ion_put_userptr(void *buf_priv) -{ - struct vb2_ion_buf *buf = buf_priv; - unsigned long vaddr = (unsigned long)buf->vaddr & PAGE_MASK; - unsigned int i; - - if (buf->pages) { - if (vaddr) - vm_unmap_ram((void *)vaddr, buf->n_pages); - for (i = 0; i < buf->n_pages; ++i) { - if (buf->write) - set_page_dirty_lock(buf->pages[i]); - put_page(buf->pages[i]); - } - kfree(buf->pages); - } else { -#ifdef IONVIDEO_DEBUG - if (buf->vma) - vb2_put_vma(buf->vma); -#endif - iounmap(buf->vaddr); - } - kfree(buf); -} - -static void *vb2_ion_vaddr(void *buf_priv) -{ - struct vb2_ion_buf *buf = buf_priv; - - if (!buf->vaddr) { - pr_err("Address of an unallocated plane requested"); - pr_err("or cannot map user pointer\n"); - return NULL; - } - - return buf->vaddr; -} - -static unsigned int vb2_ion_num_users(void *buf_priv) -{ - struct vb2_ion_buf *buf = buf_priv; - - return atomic_read(&buf->refcount); -} - -static int vb2_ion_mmap(void *buf_priv, struct vm_area_struct *vma) -{ - struct vb2_ion_buf *buf = buf_priv; - int ret; - - pr_info("11vb2_ion_mmap\n"); - if (!buf) { - pr_err("No memory to map\n"); - return -EINVAL; - } - - ret = remap_vmalloc_range(vma, buf->vaddr, 0); - if (ret) { - pr_err("Remapping ion memory, error: %d\n", ret); - return ret; - } - - /* - * Make sure that vm_areas for 2 buffers won't be merged together - */ - vma->vm_flags |= VM_DONTEXPAND; - - /* - * Use common vm_area operations to track buffer refcount. - */ - vma->vm_private_data = &buf->handler; - vma->vm_ops = &vb2_common_vm_ops; - - vma->vm_ops->open(vma); - pr_info("22vb2_ion_mmap\n"); - return 0; -} - -/*********************************************/ -/* callbacks for DMABUF buffers */ -/*********************************************/ - -static int vb2_ion_map_dmabuf(void *mem_priv) -{ - /* struct vb2_ion_buf *buf = mem_priv; */ - /* */ - /* struct ion_buffer *buffer = buf->dbuf->priv; */ - /* int mtype = MT_MEMORY_NONCACHED; */ - /* */ - /* if (buffer->flags & ION_FLAG_CACHED) */ - /* mtype = MT_MEMORY; */ -#if 0 - buf->vaddr = __arm_ioremap(buffer->priv_phys, buffer->size, mtype); - - return buf->vaddr ? 0 : -EFAULT; -#else - return 0; -#endif -} - -static void vb2_ion_unmap_dmabuf(void *mem_priv) -{ - /* struct vb2_ion_buf *buf = mem_priv; */ - -#if 0 - __arm_iounmap(buf->vaddr); - - buf->vaddr = NULL; -#endif -} - -static void vb2_ion_detach_dmabuf(void *mem_priv) -{ - struct vb2_ion_buf *buf = mem_priv; - - if (buf->vaddr) - dma_buf_vunmap(buf->dbuf, buf->vaddr); - - kfree(buf); -} - -#ifdef IONVIDEO_DEBUG -static void *vb2_ion_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, - unsigned long size, int write) -{ - struct vb2_ion_buf *buf; - - if (dbuf->size < size) - return ERR_PTR(-EFAULT); - - buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) - return ERR_PTR(-ENOMEM); - - buf->dbuf = dbuf; - buf->write = write; - buf->size = size; - - return buf; -} -#endif - -static void *vb2_ion_cookie(void *buf_priv) -{ - struct vb2_ion_buf *buf = buf_priv; - - struct ion_buffer *buffer = buf->dbuf->priv; -#if 0 - return (void *)buffer->priv_phys; -#endif - struct sg_table *table = buffer->priv_virt; - struct page *page = sg_page(table->sgl); - - ion_phys_addr_t paddr = PFN_PHYS(page_to_pfn(page)); - - return (void *)paddr; -} - -const struct vb2_mem_ops vb2_ion_memops = { -#ifdef IONVIDEO_DEBUG - .alloc = vb2_ion_alloc, -#endif - .put = vb2_ion_put, -#ifdef IONVIDEO_DEBUG - .get_userptr = vb2_ion_get_userptr, -#endif - .put_userptr = vb2_ion_put_userptr, - .map_dmabuf = vb2_ion_map_dmabuf, - .unmap_dmabuf = vb2_ion_unmap_dmabuf, -#ifdef IONVIDEO_DEBUG - .attach_dmabuf = vb2_ion_attach_dmabuf, -#endif - .detach_dmabuf = vb2_ion_detach_dmabuf, - .vaddr = vb2_ion_vaddr, - .mmap = vb2_ion_mmap, - .num_users = vb2_ion_num_users, - .cookie = vb2_ion_cookie, -}; -EXPORT_SYMBOL_GPL(vb2_ion_memops); - -MODULE_DESCRIPTION("ion memory handling routines for videobuf2"); -MODULE_AUTHOR("Shuai Cao "); -MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h b/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h deleted file mode 100644 index b152557..0000000 --- a/drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef _MEDIA_VIDEOBUF2_ION_H -#define _MEDIA_VIDEOBUF2_ION_H - -#include - -extern const struct vb2_mem_ops vb2_ion_memops; - -#endif -- 2.7.4