mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 04:10:18 +09:00
ionvideo: initial add the driver
PD#138714: initial add the driver 1.Add amlogic ionvideo driver; 2.device tree support of ionvideo for p212/q200/skt/p400/p401; 3.related Makefiles/Kconfig/Headfiles update; Change-Id: I2c0013a8ab256f73618b7f583c3b275fa3aaeebb Signed-off-by: Guosong Zhou <guosong.zhou@amlogic.com>
This commit is contained in:
12
MAINTAINERS
12
MAINTAINERS
@@ -13768,4 +13768,16 @@ M: Rongjun Chen <rongjun.chen@amlogic.com>
|
||||
F: drivers/amlogic/bluetooth/
|
||||
F: drivers/amlogic/wifi/
|
||||
|
||||
AMLOGIC IONVIDEO DRIVER
|
||||
M: Guosong Zhou <guosong.zhou@amlogic.com>
|
||||
F: arch/arm64/boot/dts/amlogic/gxl_p212_1g.dts
|
||||
F: arch/arm64/boot/dts/amlogic/gxl_p212_2g.dts
|
||||
F: arch/arm64/boot/dts/amlogic/gxm_q200_2g.dts
|
||||
F: arch/arm64/boot/dts/amlogic/gxl_p400_2g.dts
|
||||
F: arch/arm64/boot/dts/amlogic/gxm_p401_2g.dts
|
||||
F: arch/arm64/boot/dts/amlogic/gxm_skt.dts
|
||||
F: arch/arm64/configs/meson64_defconfig
|
||||
F: drivers/amlogic/media/video_processor/Kconfig
|
||||
F: drivers/amlogic/media/video_processor/Makefile
|
||||
F: drivers/amlogic/media/video_processor/ionvideo/*
|
||||
|
||||
|
||||
@@ -1022,6 +1022,12 @@
|
||||
hw-version = <2>;
|
||||
};
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -1020,6 +1020,12 @@
|
||||
hw-version = <2>;
|
||||
};
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -677,6 +677,12 @@
|
||||
};
|
||||
/* END OF AUDIO board specific */
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -79,6 +79,12 @@
|
||||
size = <0x0 0x2000000>;
|
||||
};
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -1043,6 +1043,12 @@
|
||||
hw-version = <2>;
|
||||
};
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -810,6 +810,12 @@
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
ionvideo {
|
||||
compatible = "amlogic, ionvideo";
|
||||
dev_name = "ionvideo";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
amlvideo {
|
||||
compatible = "amlogic, amlvideo";
|
||||
dev_name = "amlvideo";
|
||||
|
||||
@@ -226,6 +226,8 @@ CONFIG_AMLOGIC_V4L_VIDEO=y
|
||||
CONFIG_AMLOGIC_V4L_VIDEO2=y
|
||||
CONFIG_AMLOGIC_POST_PROCESS_MANAGER=y
|
||||
CONFIG_AMLOGIC_POST_PROCESS_MANAGER_PPSCALER=y
|
||||
CONFIG_AMLOGIC_VIDEOBUF2_ION=y
|
||||
CONFIG_AMLOGIC_IONVIDEO=y
|
||||
CONFIG_AMLOGIC_MMC=y
|
||||
CONFIG_AMLOGIC_NAND=y
|
||||
CONFIG_AMLOGIC_VRTC=y
|
||||
|
||||
@@ -15,6 +15,7 @@ if AMLOGIC_VIDEO_PROCESSOR
|
||||
|
||||
source "drivers/amlogic/media/video_processor/video_dev/Kconfig"
|
||||
source "drivers/amlogic/media/video_processor/ppmgr/Kconfig"
|
||||
source "drivers/amlogic/media/video_processor/ionvideo/Kconfig"
|
||||
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_AMLOGIC_V4L_VIDEO2) += video_dev/
|
||||
obj-$(CONFIG_AMLOGIC_POST_PROCESS_MANAGER) += ppmgr/
|
||||
obj-$(CONFIG_AMLOGIC_IONVIDEO) += ionvideo/
|
||||
|
||||
31
drivers/amlogic/media/video_processor/ionvideo/Kconfig
Normal file
31
drivers/amlogic/media/video_processor/ionvideo/Kconfig
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# Amlogic ionvideo device configuation
|
||||
#
|
||||
|
||||
menu "Amlogic ion video support"
|
||||
|
||||
config AMLOGIC_VIDEOBUF2_ION
|
||||
tristate "videobuf2-ion video device support"
|
||||
depends on VIDEO_DEV
|
||||
depends on VIDEO_V4L2
|
||||
depends on VIDEOBUF2_CORE
|
||||
depends on VIDEOBUF2_MEMOPS
|
||||
depends on DMA_SHARED_BUFFER
|
||||
default n
|
||||
|
||||
---help---
|
||||
capture ion video to user
|
||||
select to enable capture ion video to user
|
||||
enabled by default
|
||||
good luck
|
||||
|
||||
|
||||
config AMLOGIC_IONVIDEO
|
||||
tristate "Amlogic ion video device support"
|
||||
depends on AMLOGIC_VIDEOBUF2_ION
|
||||
default n
|
||||
|
||||
---help---
|
||||
capture ion video to user
|
||||
|
||||
endmenu
|
||||
5
drivers/amlogic/media/video_processor/ionvideo/Makefile
Normal file
5
drivers/amlogic/media/video_processor/ionvideo/Makefile
Normal file
@@ -0,0 +1,5 @@
|
||||
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
|
||||
279
drivers/amlogic/media/video_processor/ionvideo/ion_priv.h
Normal file
279
drivers/amlogic/media/video_processor/ionvideo/ion_priv.h
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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 <ion.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mm_types.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/shrinker.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
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 */
|
||||
1514
drivers/amlogic/media/video_processor/ionvideo/ionvideo.c
Normal file
1514
drivers/amlogic/media/video_processor/ionvideo/ionvideo.c
Normal file
File diff suppressed because it is too large
Load Diff
199
drivers/amlogic/media/video_processor/ionvideo/ionvideo.h
Normal file
199
drivers/amlogic/media/video_processor/ionvideo/ionvideo.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* drivers/amlogic/media/video_processor/ionvideo/ionvideo.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 _IONVIDEO_H
|
||||
#define _IONVIDEO_H
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-fh.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
|
||||
#include <linux/mm.h>
|
||||
/* #include <mach/mod_gate.h> */
|
||||
|
||||
#include <linux/amlogic/media/vfm/vframe.h>
|
||||
#include <linux/amlogic/media/vfm/vframe_provider.h>
|
||||
#include <linux/amlogic/media/vfm/vframe_receiver.h>
|
||||
#include <linux/amlogic/media/ge2d/ge2d.h>
|
||||
#include <linux/amlogic/media/canvas/canvas.h>
|
||||
|
||||
#include <linux/amlogic/media/frame_sync/timestamp.h>
|
||||
#include <linux/amlogic/media/frame_sync/tsync.h>
|
||||
#include "videobuf2-ion.h"
|
||||
|
||||
/* Wake up at about 30 fps */
|
||||
#define WAKE_NUMERATOR 30
|
||||
#define WAKE_DENOMINATOR 1001
|
||||
|
||||
#define MAX_WIDTH 4096
|
||||
#define MAX_HEIGHT 4096
|
||||
|
||||
#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)
|
||||
|
||||
#define DUR2PTS(x) ((x) - ((x) >> 4))
|
||||
|
||||
#define dprintk(dev, level, fmt, arg...) \
|
||||
v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
|
||||
|
||||
#define ppmgr2_printk(level, fmt, arg...) \
|
||||
do { \
|
||||
if (get_ionvideo_debug() >= level) \
|
||||
pr_debug("ppmgr2-dev: " fmt, ## arg); \
|
||||
} while (0)
|
||||
|
||||
#define PPMGR2_CANVAS_INDEX_SRC (PPMGR2_CANVAS_INDEX + 3)
|
||||
|
||||
/* ------------------------------------------------------------------
|
||||
* Basic structures
|
||||
* ------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
struct ionvideo_fmt {
|
||||
char *name;
|
||||
u32 fourcc; /* v4l2 format id */
|
||||
u8 depth;
|
||||
bool is_yuv;
|
||||
};
|
||||
|
||||
/* 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;
|
||||
u32 duration;
|
||||
};
|
||||
|
||||
struct ionvideo_dmaqueue {
|
||||
struct list_head active;
|
||||
|
||||
/* thread for generating video stream*/
|
||||
struct task_struct *kthread;
|
||||
wait_queue_head_t wq;
|
||||
/* Counters to control fps rate */
|
||||
int vb_ready;
|
||||
struct ionvideo_dev *pdev;
|
||||
};
|
||||
|
||||
struct ppmgr2_device {
|
||||
int dst_width;
|
||||
int dst_height;
|
||||
int dst_buffer_width;
|
||||
int dst_buffer_height;
|
||||
int ge2d_fmt;
|
||||
int canvas_id[PPMGR2_MAX_CANVAS];
|
||||
void *phy_addr[PPMGR2_MAX_CANVAS];
|
||||
int phy_size;
|
||||
|
||||
struct ge2d_context_s *context;
|
||||
struct config_para_ex_s ge2d_config;
|
||||
|
||||
int angle;
|
||||
int mirror;
|
||||
int paint_mode;
|
||||
int interlaced_num;
|
||||
int bottom_first;
|
||||
|
||||
struct mutex *ge2d_canvas_mutex;
|
||||
};
|
||||
|
||||
#define ION_VF_RECEIVER_NAME_SIZE 32
|
||||
|
||||
struct ionvideo_dev {
|
||||
struct list_head ionvideo_devlist;
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct video_device vdev;
|
||||
int fd_num;
|
||||
int ionvideo_v4l_num;
|
||||
|
||||
spinlock_t slock;
|
||||
struct mutex mutex;
|
||||
|
||||
struct ionvideo_dmaqueue vidq;
|
||||
|
||||
/* Several counters */
|
||||
unsigned int ms;
|
||||
unsigned long jiffies;
|
||||
|
||||
/* Input Number */
|
||||
int input;
|
||||
|
||||
/* video capture */
|
||||
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;
|
||||
|
||||
struct ppmgr2_device ppmgr2_dev;
|
||||
struct vframe_receiver_s video_vf_receiver;
|
||||
u64 pts;
|
||||
u8 receiver_register;
|
||||
u8 is_video_started;
|
||||
u32 skip;
|
||||
int once_record;
|
||||
u8 is_omx_video_started;
|
||||
int is_actived;
|
||||
u64 last_pts_us64;
|
||||
unsigned int freerun_mode;
|
||||
unsigned int skip_frames;
|
||||
|
||||
wait_queue_head_t wq;
|
||||
|
||||
char vf_receiver_name[ION_VF_RECEIVER_NAME_SIZE];
|
||||
int inst;
|
||||
bool mapped;
|
||||
bool thread_stopped;
|
||||
int vf_wait_cnt;
|
||||
};
|
||||
|
||||
unsigned int get_ionvideo_debug(void);
|
||||
|
||||
int ppmgr2_init(struct ppmgr2_device *ppd);
|
||||
int ppmgr2_canvas_config(struct ppmgr2_device *ppd, int index);
|
||||
int ppmgr2_process(struct vframe_s *vf, struct ppmgr2_device *ppd, int index);
|
||||
int ppmgr2_top_process(struct vframe_s *vf, struct ppmgr2_device *ppd,
|
||||
int index);
|
||||
int ppmgr2_bottom_process(struct vframe_s *vf, struct ppmgr2_device *ppd,
|
||||
int index);
|
||||
void ppmgr2_release(struct ppmgr2_device *ppd);
|
||||
void ppmgr2_set_angle(struct ppmgr2_device *ppd, int angle);
|
||||
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);
|
||||
|
||||
#endif
|
||||
68
drivers/amlogic/media/video_processor/ionvideo/map.h
Normal file
68
drivers/amlogic/media/video_processor/ionvideo/map.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* drivers/amlogic/media/video_processor/ionvideo/map.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 __ASM_MACH_MAP_H
|
||||
#define __ASM_MACH_MAP_H
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
struct map_desc {
|
||||
unsigned long virtual;
|
||||
unsigned long pfn;
|
||||
unsigned long length;
|
||||
unsigned int type;
|
||||
};
|
||||
|
||||
/* types 0-3 are defined in asm/io.h */
|
||||
#define MT_UNCACHED 4
|
||||
#define MT_CACHECLEAN 5
|
||||
#define MT_MINICLEAN 6
|
||||
#define MT_LOW_VECTORS 7
|
||||
#define MT_HIGH_VECTORS 8
|
||||
#define MT_MEMORY 9
|
||||
#define MT_ROM 10
|
||||
#define MT_MEMORY_NONCACHED 11
|
||||
#define MT_MEMORY_DTCM 12
|
||||
#define MT_MEMORY_ITCM 13
|
||||
#define MT_MEMORY_SO 14
|
||||
#define MT_MEMORY_DMA_READY 15
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
extern void iotable_init(struct map_desc *io_desc, int nr);
|
||||
extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
|
||||
void *caller);
|
||||
|
||||
#ifdef CONFIG_DEBUG_LL
|
||||
extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr);
|
||||
extern void debug_ll_io_init(void);
|
||||
#else
|
||||
static inline void debug_ll_io_init(void) {}
|
||||
#endif
|
||||
|
||||
struct mem_type;
|
||||
extern const struct mem_type *get_mem_type(unsigned int type);
|
||||
/*
|
||||
* external interface to remap single page with appropriate type
|
||||
*/
|
||||
extern int ioremap_page(unsigned long virt, unsigned long phys,
|
||||
const struct mem_type *mtype);
|
||||
#else
|
||||
#define iotable_init(map, num) do { } while (0)
|
||||
#define vm_reserve_area_early(a, s, c) do { } while (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
568
drivers/amlogic/media/video_processor/ionvideo/ppmgr2.c
Normal file
568
drivers/amlogic/media/video_processor/ionvideo/ppmgr2.c
Normal file
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* drivers/amlogic/media/video_processor/ionvideo/ppmgr2.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 "ionvideo.h"
|
||||
|
||||
static inline void paint_mode_convert(int paint_mode, int *src_position,
|
||||
int *dst_paint_position,
|
||||
int *dst_plane_position)
|
||||
{
|
||||
|
||||
if (paint_mode == 0) { /* stretch full */
|
||||
dst_paint_position[0] = dst_plane_position[0];
|
||||
dst_paint_position[1] = dst_plane_position[1];
|
||||
dst_paint_position[2] = dst_plane_position[2];
|
||||
dst_paint_position[3] = dst_plane_position[3];
|
||||
} else if (paint_mode == 1) { /* keep size */
|
||||
dst_paint_position[0] =
|
||||
(dst_plane_position[2] - src_position[2]) >> 1;
|
||||
dst_paint_position[1] =
|
||||
(dst_plane_position[3] - src_position[3]) >> 1;
|
||||
dst_paint_position[2] = src_position[2];
|
||||
dst_paint_position[3] = src_position[3];
|
||||
} else if (paint_mode == 2) {
|
||||
int dw = 0, dh = 0;
|
||||
|
||||
if (src_position[2] * dst_plane_position[3] >=
|
||||
dst_plane_position[2]
|
||||
* src_position[3]) { /* crop full */
|
||||
dh = dst_plane_position[3];
|
||||
dw = dh * src_position[2] / src_position[3];
|
||||
} else {
|
||||
dw = dst_plane_position[2];
|
||||
dh = dw * src_position[3] / src_position[2];
|
||||
}
|
||||
dst_paint_position[0] = (dst_plane_position[2] - dw) >> 1;
|
||||
dst_paint_position[1] = (dst_plane_position[3] - dh) >> 1;
|
||||
dst_paint_position[2] = dw;
|
||||
dst_paint_position[3] = dh;
|
||||
} else if (paint_mode == 3) { /* keep ration black */
|
||||
int dw = 0, dh = 0;
|
||||
|
||||
if (src_position[2] * dst_plane_position[3] >=
|
||||
dst_plane_position[2] * src_position[3]) {
|
||||
dw = dst_plane_position[2];
|
||||
dh = dw * src_position[3] / src_position[2];
|
||||
} else {
|
||||
dh = dst_plane_position[3];
|
||||
dw = dh * src_position[2] / src_position[3];
|
||||
}
|
||||
dst_paint_position[0] = (dst_plane_position[2] - dw) >> 1;
|
||||
dst_paint_position[1] = (dst_plane_position[3] - dh) >> 1;
|
||||
dst_paint_position[2] = dw;
|
||||
dst_paint_position[3] = dh;
|
||||
} else if (paint_mode == 4) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static int get_input_format(struct vframe_s *vf)
|
||||
{
|
||||
int format = GE2D_FORMAT_M24_NV21;
|
||||
|
||||
if (vf->type & VIDTYPE_VIU_422) {
|
||||
if ((vf->type & 3) == VIDTYPE_INTERLACE_BOTTOM) {
|
||||
format = GE2D_FORMAT_S16_YUV422
|
||||
| (GE2D_FORMAT_S16_YUV422B & (3 << 3));
|
||||
} else if ((vf->type & 3) == VIDTYPE_INTERLACE_TOP) {
|
||||
format = GE2D_FORMAT_S16_YUV422
|
||||
| (GE2D_FORMAT_S16_YUV422T & (3 << 3));
|
||||
} else {
|
||||
format = GE2D_FORMAT_S16_YUV422;
|
||||
}
|
||||
} else if (vf->type & VIDTYPE_VIU_NV21) {
|
||||
if ((vf->type & 3) == VIDTYPE_INTERLACE_BOTTOM) {
|
||||
format = GE2D_FORMAT_M24_NV21
|
||||
| (GE2D_FORMAT_M24_NV21B & (3 << 3));
|
||||
} else if ((vf->type & 3) == VIDTYPE_INTERLACE_TOP) {
|
||||
format = GE2D_FORMAT_M24_NV21
|
||||
| (GE2D_FORMAT_M24_NV21T & (3 << 3));
|
||||
} else {
|
||||
format = GE2D_FORMAT_M24_NV21;
|
||||
}
|
||||
} else {
|
||||
if ((vf->type & 3) == VIDTYPE_INTERLACE_BOTTOM) {
|
||||
format = GE2D_FORMAT_M24_YUV420
|
||||
| (GE2D_FMT_M24_YUV420B & (3 << 3));
|
||||
} else if ((vf->type & 3) == VIDTYPE_INTERLACE_TOP) {
|
||||
format = GE2D_FORMAT_M24_YUV420
|
||||
| (GE2D_FORMAT_M24_YUV420T & (3 << 3));
|
||||
} else {
|
||||
format = GE2D_FORMAT_M24_YUV420;
|
||||
}
|
||||
}
|
||||
return format;
|
||||
}
|
||||
|
||||
static inline void ge2d_src_config(struct vframe_s *vf,
|
||||
struct config_para_ex_s *ge2d_config)
|
||||
{
|
||||
struct vframe_s src_vf = *vf;
|
||||
struct canvas_s src_cs0, src_cs1, src_cs2;
|
||||
|
||||
if (vf->canvas0Addr == (u32)-1) {
|
||||
canvas_config_config(PPMGR2_CANVAS_INDEX_SRC,
|
||||
&src_vf.canvas0_config[0]);
|
||||
canvas_config_config(PPMGR2_CANVAS_INDEX_SRC + 1,
|
||||
&src_vf.canvas0_config[1]);
|
||||
if (src_vf.plane_num == 2) {
|
||||
src_vf.canvas0Addr =
|
||||
(PPMGR2_CANVAS_INDEX_SRC)
|
||||
| ((PPMGR2_CANVAS_INDEX_SRC + 1) << 8)
|
||||
| ((PPMGR2_CANVAS_INDEX_SRC + 1) << 16);
|
||||
} else if (src_vf.plane_num == 3) {
|
||||
canvas_config_config(PPMGR2_CANVAS_INDEX_SRC + 2,
|
||||
&src_vf.canvas0_config[2]);
|
||||
|
||||
src_vf.canvas0Addr =
|
||||
(PPMGR2_CANVAS_INDEX_SRC)
|
||||
| ((PPMGR2_CANVAS_INDEX_SRC + 1) << 8)
|
||||
| ((PPMGR2_CANVAS_INDEX_SRC + 2) << 16);
|
||||
}
|
||||
|
||||
ge2d_config->src_planes[0].addr =
|
||||
src_vf.canvas0_config[0].phy_addr;
|
||||
ge2d_config->src_planes[0].w =
|
||||
src_vf.canvas0_config[0].width;
|
||||
ge2d_config->src_planes[0].h =
|
||||
src_vf.canvas0_config[0].height;
|
||||
ge2d_config->src_planes[1].addr =
|
||||
src_vf.canvas0_config[1].phy_addr;
|
||||
ge2d_config->src_planes[1].w =
|
||||
src_vf.canvas0_config[1].width;
|
||||
ge2d_config->src_planes[1].h =
|
||||
src_vf.canvas0_config[1].height << 1;
|
||||
|
||||
if (src_vf.plane_num == 3) {
|
||||
ge2d_config->src_planes[2].addr =
|
||||
src_vf.canvas0_config[2].phy_addr;
|
||||
ge2d_config->src_planes[2].w =
|
||||
src_vf.canvas0_config[2].width;
|
||||
ge2d_config->src_planes[2].h =
|
||||
src_vf.canvas0_config[2].height << 1;
|
||||
}
|
||||
} else {
|
||||
canvas_read(src_vf.canvas0Addr & 0xff, &src_cs0);
|
||||
canvas_read(src_vf.canvas0Addr >> 8 & 0xff, &src_cs1);
|
||||
canvas_read(src_vf.canvas0Addr >> 16 & 0xff, &src_cs2);
|
||||
ge2d_config->src_planes[0].addr = src_cs0.addr;
|
||||
ge2d_config->src_planes[0].w = src_cs0.width;
|
||||
ge2d_config->src_planes[0].h = src_cs0.height;
|
||||
ge2d_config->src_planes[1].addr = src_cs1.addr;
|
||||
ge2d_config->src_planes[1].w = src_cs1.width;
|
||||
ge2d_config->src_planes[1].h = src_cs1.height;
|
||||
ge2d_config->src_planes[2].addr = src_cs2.addr;
|
||||
ge2d_config->src_planes[2].w = src_cs2.width;
|
||||
ge2d_config->src_planes[2].h = src_cs2.height;
|
||||
}
|
||||
/* data operating. */
|
||||
ge2d_config->alu_const_color = 0; /* 0x000000ff; */
|
||||
ge2d_config->bitmask_en = 0;
|
||||
ge2d_config->src1_gb_alpha = 0; /* 0xff; */
|
||||
|
||||
ge2d_config->src_key.key_enable = 0;
|
||||
ge2d_config->src_key.key_mask = 0;
|
||||
ge2d_config->src_key.key_mode = 0;
|
||||
ge2d_config->src_para.canvas_index = src_vf.canvas0Addr;
|
||||
ge2d_config->src_para.mem_type = CANVAS_TYPE_INVALID;
|
||||
ge2d_config->src_para.format = get_input_format(&src_vf);
|
||||
ge2d_config->src_para.fill_color_en = 0;
|
||||
ge2d_config->src_para.fill_mode = 0;
|
||||
ge2d_config->src_para.x_rev = 0;
|
||||
ge2d_config->src_para.y_rev = 0;
|
||||
ge2d_config->src_para.color = 0xffffffff;
|
||||
ge2d_config->src_para.top = 0;
|
||||
ge2d_config->src_para.left = 0;
|
||||
ge2d_config->src_para.width = src_vf.width;
|
||||
if (vf->type & VIDTYPE_INTERLACE)
|
||||
ge2d_config->src_para.height = src_vf.height >> 1;
|
||||
else
|
||||
ge2d_config->src_para.height = src_vf.height;
|
||||
|
||||
ge2d_config->src2_para.mem_type = CANVAS_TYPE_INVALID;
|
||||
/* ppmgr2_printk(2, "vf_width is %d , vf_height is %d type:%p\n",
|
||||
* vf->width, vf->height, (void *)vf->type);
|
||||
*/
|
||||
}
|
||||
|
||||
static int ge2d_paint_dst(struct ge2d_context_s *context,
|
||||
struct config_para_ex_s *ge2d_config,
|
||||
int dst_canvas_id, int dst_pixel_format,
|
||||
int *src_position, int *dst_paint_position,
|
||||
int *dst_plane_position)
|
||||
{
|
||||
struct canvas_s dst_cd;
|
||||
|
||||
ge2d_config->dst_para.mem_type = CANVAS_TYPE_INVALID;
|
||||
ge2d_config->dst_para.fill_color_en = 0;
|
||||
ge2d_config->dst_para.fill_mode = 0;
|
||||
ge2d_config->dst_para.color = 0;
|
||||
ge2d_config->dst_para.top = dst_plane_position[0];
|
||||
ge2d_config->dst_para.left = dst_plane_position[1];
|
||||
ge2d_config->dst_para.width = dst_plane_position[2];
|
||||
ge2d_config->dst_para.height = dst_plane_position[3];
|
||||
|
||||
if (dst_pixel_format == GE2D_FORMAT_S8_Y) {
|
||||
canvas_read(dst_canvas_id & 0xff, &dst_cd);
|
||||
ge2d_config->dst_planes[0].addr = dst_cd.addr;
|
||||
ge2d_config->dst_planes[0].w = dst_cd.width;
|
||||
ge2d_config->dst_planes[0].h = dst_cd.height;
|
||||
ge2d_config->dst_para.canvas_index = dst_canvas_id & 0xff;
|
||||
ge2d_config->dst_para.format = dst_pixel_format
|
||||
| GE2D_LITTLE_ENDIAN;
|
||||
|
||||
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
|
||||
ppmgr2_printk(1, "Ge2d configing error.\n");
|
||||
return -1;
|
||||
}
|
||||
stretchblt_noalpha(context, src_position[0], src_position[1],
|
||||
src_position[2], src_position[3],
|
||||
dst_paint_position[0],
|
||||
dst_paint_position[1],
|
||||
dst_paint_position[2],
|
||||
dst_paint_position[3]);
|
||||
canvas_read(dst_canvas_id >> 8 & 0xff, &dst_cd);
|
||||
ge2d_config->dst_planes[0].addr = dst_cd.addr;
|
||||
ge2d_config->dst_planes[0].w = dst_cd.width;
|
||||
ge2d_config->dst_planes[0].h = dst_cd.height;
|
||||
ge2d_config->dst_para.canvas_index = dst_canvas_id >> 8 & 0xff;
|
||||
ge2d_config->dst_para.format = GE2D_FORMAT_S8_CB
|
||||
| GE2D_LITTLE_ENDIAN;
|
||||
ge2d_config->dst_para.width = dst_paint_position[2] >> 1;
|
||||
ge2d_config->dst_para.height = dst_paint_position[3] >> 1;
|
||||
|
||||
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
|
||||
ppmgr2_printk(1, "Ge2d configing error.\n");
|
||||
return -1;
|
||||
}
|
||||
stretchblt_noalpha(context, src_position[0], src_position[1],
|
||||
src_position[2], src_position[3],
|
||||
dst_paint_position[0],
|
||||
dst_paint_position[1],
|
||||
dst_paint_position[2],
|
||||
dst_paint_position[3]);
|
||||
|
||||
canvas_read(dst_canvas_id >> 16 & 0xff, &dst_cd);
|
||||
ge2d_config->dst_planes[0].addr = dst_cd.addr;
|
||||
ge2d_config->dst_planes[0].w = dst_cd.width;
|
||||
ge2d_config->dst_planes[0].h = dst_cd.height;
|
||||
ge2d_config->dst_para.canvas_index = dst_canvas_id >> 16 & 0xff;
|
||||
ge2d_config->dst_para.format = GE2D_FORMAT_S8_CR
|
||||
| GE2D_LITTLE_ENDIAN;
|
||||
|
||||
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
|
||||
ppmgr2_printk(1, "Ge2d configing error.\n");
|
||||
return -1;
|
||||
}
|
||||
stretchblt_noalpha(context, src_position[0], src_position[1],
|
||||
src_position[2], src_position[3],
|
||||
dst_paint_position[0],
|
||||
dst_paint_position[1],
|
||||
dst_paint_position[2],
|
||||
dst_paint_position[3]);
|
||||
} else {
|
||||
canvas_read(dst_canvas_id & 0xff, &dst_cd);
|
||||
ge2d_config->dst_planes[0].addr = dst_cd.addr;
|
||||
ge2d_config->dst_planes[0].w = dst_cd.width;
|
||||
ge2d_config->dst_planes[0].h = dst_cd.height;
|
||||
ge2d_config->dst_para.format = dst_pixel_format
|
||||
| GE2D_LITTLE_ENDIAN;
|
||||
ge2d_config->dst_para.canvas_index = dst_canvas_id;
|
||||
|
||||
if ((dst_paint_position[2] > dst_cd.width)
|
||||
|| (dst_paint_position[3] > dst_cd.height)) {
|
||||
ppmgr2_printk(0, "error: id %d,width %d,height %d, ",
|
||||
dst_canvas_id,
|
||||
dst_cd.width,
|
||||
dst_cd.height);
|
||||
ppmgr2_printk(0, "dst_width %d,dst_height %d\n",
|
||||
dst_paint_position[2],
|
||||
dst_paint_position[3]);
|
||||
ppmgr2_printk(1, "error case : dst addr:%p\n",
|
||||
(void *)dst_cd.addr);
|
||||
return -1;
|
||||
}
|
||||
if (ge2d_context_config_ex(context, ge2d_config) < 0) {
|
||||
ppmgr2_printk(1, "Ge2d configing error.\n");
|
||||
return -1;
|
||||
}
|
||||
stretchblt_noalpha(context, src_position[0], src_position[1],
|
||||
src_position[2], src_position[3],
|
||||
dst_paint_position[0],
|
||||
dst_paint_position[1],
|
||||
dst_paint_position[2],
|
||||
dst_paint_position[3]);
|
||||
}
|
||||
/* ppmgr2_printk(2, "dst addr:%p w:%d h:%d canvas_id:%p format:%p\n",
|
||||
* (void *)dst_cd.addr, dst_cd.width, dst_cd.height,
|
||||
* (void *)dst_canvas_id,
|
||||
* (void *)ge2d_config->dst_para.format);
|
||||
*/
|
||||
ppmgr2_printk(2, "dst plane w:%d h:%d paint w:%d h:%d\n",
|
||||
dst_plane_position[2], dst_plane_position[3],
|
||||
dst_paint_position[2], dst_paint_position[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ge2d_mirror_config(int dst_mirror,
|
||||
struct config_para_ex_s *ge2d_config)
|
||||
{
|
||||
if (dst_mirror == 1) {
|
||||
ge2d_config->dst_para.x_rev = 1;
|
||||
ge2d_config->dst_para.y_rev = 0;
|
||||
} else if (dst_mirror == 2) {
|
||||
ge2d_config->dst_para.x_rev = 0;
|
||||
ge2d_config->dst_para.y_rev = 1;
|
||||
} else {
|
||||
ge2d_config->dst_para.x_rev = 0;
|
||||
ge2d_config->dst_para.y_rev = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ge2d_angle_config(int dst_angle,
|
||||
struct config_para_ex_s *ge2d_config)
|
||||
{
|
||||
if (dst_angle == 1) {
|
||||
ge2d_config->dst_xy_swap = 1;
|
||||
ge2d_config->dst_para.x_rev ^= 1;
|
||||
} else if (dst_angle == 2) {
|
||||
ge2d_config->dst_para.x_rev ^= 1;
|
||||
ge2d_config->dst_para.y_rev ^= 1;
|
||||
} else if (dst_angle == 3) {
|
||||
ge2d_config->dst_xy_swap = 1;
|
||||
ge2d_config->dst_para.y_rev ^= 1;
|
||||
} else {
|
||||
ge2d_config->dst_xy_swap = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* use ppmgr2 need to init struct ge2d_context_s,
|
||||
* pixel_format, canvas_width, canvas_height,
|
||||
* phy_addr, buffer_size, canvas_number.
|
||||
*/
|
||||
int ppmgr2_init(struct ppmgr2_device *ppd)
|
||||
{
|
||||
int i = 0;
|
||||
/* switch_mod_gate_by_name("ge2d", 1); */
|
||||
ppd->context = create_ge2d_work_queue();
|
||||
if (!ppd->context) {
|
||||
ppmgr2_printk(1, "create ge2d work queue error!\n");
|
||||
return -1;
|
||||
}
|
||||
ppmgr2_printk(2, "ppmgr2_init!\n");
|
||||
ppd->paint_mode = 0;
|
||||
ppd->angle = 0;
|
||||
ppd->mirror = 0;
|
||||
ppd->ge2d_fmt = 0;
|
||||
ppd->dst_width = 0;
|
||||
ppd->dst_height = 0;
|
||||
for (i = 0; i < PPMGR2_MAX_CANVAS; i++) {
|
||||
ppd->phy_addr[i] = NULL;
|
||||
ppd->canvas_id[i] = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ppmgr2_canvas_config(struct ppmgr2_device *ppd, int index)
|
||||
{
|
||||
int canvas_width = ppd->dst_buffer_width;
|
||||
int canvas_height = ppd->dst_buffer_height;
|
||||
void *phy_addr;
|
||||
|
||||
if (!ppd->phy_addr) {
|
||||
ppmgr2_printk(1, "NULL physical address!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
phy_addr = ppd->phy_addr[index];
|
||||
|
||||
if (index >= PPMGR2_MAX_CANVAS) {
|
||||
ppmgr2_printk(0, "canvas index too large! %d>=%d\n", index,
|
||||
PPMGR2_MAX_CANVAS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ppd->ge2d_fmt == GE2D_FORMAT_M24_NV21 || ppd->ge2d_fmt
|
||||
== GE2D_FORMAT_M24_NV12) {
|
||||
canvas_config(PPMGR2_CANVAS_INDEX, (ulong)phy_addr,
|
||||
canvas_width, canvas_height, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config(
|
||||
PPMGR2_CANVAS_INDEX + 1,
|
||||
(ulong)(phy_addr + (canvas_width * canvas_height)),
|
||||
canvas_width, canvas_height >> 1, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
ppd->canvas_id[index] = (PPMGR2_CANVAS_INDEX)
|
||||
| ((PPMGR2_CANVAS_INDEX + 1) << 8);
|
||||
} else if (ppd->ge2d_fmt == GE2D_FORMAT_S8_Y) {
|
||||
canvas_config(PPMGR2_CANVAS_INDEX, (ulong)phy_addr,
|
||||
canvas_width, canvas_height, CANVAS_ADDR_NOWRAP,
|
||||
CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config(
|
||||
PPMGR2_CANVAS_INDEX + 1,
|
||||
(ulong)(phy_addr + canvas_width * canvas_height),
|
||||
canvas_width >> 1, canvas_height >> 1,
|
||||
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
|
||||
canvas_config(
|
||||
PPMGR2_CANVAS_INDEX + 2,
|
||||
(ulong)(phy_addr + (canvas_width * canvas_height * 5
|
||||
>> 2)),
|
||||
canvas_width >> 1, canvas_height >> 1,
|
||||
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
|
||||
ppd->canvas_id[index] = (PPMGR2_CANVAS_INDEX)
|
||||
| ((PPMGR2_CANVAS_INDEX + 1) << 8)
|
||||
| ((PPMGR2_CANVAS_INDEX + 2) << 16);
|
||||
} else {
|
||||
int bpp = 0;
|
||||
|
||||
if (ppd->ge2d_fmt == GE2D_FORMAT_S32_ABGR) {
|
||||
bpp = 4;
|
||||
} else if (ppd->ge2d_fmt == GE2D_FORMAT_S24_BGR
|
||||
|| ppd->ge2d_fmt == GE2D_FORMAT_S24_RGB) {
|
||||
bpp = 3;
|
||||
} else if (ppd->ge2d_fmt == GE2D_FORMAT_S16_RGB_565) {
|
||||
bpp = 2;
|
||||
} else {
|
||||
ppmgr2_printk(1, "Not support format!\n");
|
||||
return -1;
|
||||
}
|
||||
canvas_config(PPMGR2_CANVAS_INDEX, (ulong)phy_addr,
|
||||
canvas_width * bpp, canvas_height,
|
||||
CANVAS_ADDR_NOWRAP, CANVAS_BLKMODE_LINEAR);
|
||||
ppd->canvas_id[index] = PPMGR2_CANVAS_INDEX;
|
||||
|
||||
}
|
||||
ppmgr2_printk(2, "canvas[%d] phy_addr:%p width:%d height:%d\n", index,
|
||||
phy_addr, canvas_width, canvas_height);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ppmgr2_set_angle(struct ppmgr2_device *ppd, int angle)
|
||||
{
|
||||
ppd->angle = angle;
|
||||
}
|
||||
|
||||
void ppmgr2_set_mirror(struct ppmgr2_device *ppd, int mirror)
|
||||
{
|
||||
ppd->mirror = mirror;
|
||||
}
|
||||
|
||||
void ppmgr2_set_paint_mode(struct ppmgr2_device *ppd, int paint_mode)
|
||||
{
|
||||
ppd->paint_mode = paint_mode;
|
||||
}
|
||||
|
||||
int ppmgr2_process(struct vframe_s *vf, struct ppmgr2_device *ppd, int index)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vframe_s *src_vf = vf;
|
||||
int src_position[4] = {0};
|
||||
int dst_paint_position[4] = {0}, dst_plane_position[4] = {0};
|
||||
int dst_pixel_format = ppd->ge2d_fmt;
|
||||
struct ge2d_context_s *context = ppd->context;
|
||||
struct config_para_ex_s *ge2d_config = &(ppd->ge2d_config);
|
||||
int angle = (ppd->angle + src_vf->orientation) % 4;
|
||||
int dst_canvas_id = 0;
|
||||
|
||||
if (src_vf->type & VIDTYPE_INTERLACE) {
|
||||
if ((ppd->bottom_first && src_vf->type & 0x2)
|
||||
|| (ppd->bottom_first == 0
|
||||
&& (src_vf->type & 0x2) == 0)) {
|
||||
return -EAGAIN;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(ppd->ge2d_canvas_mutex);
|
||||
ppmgr2_canvas_config(ppd, index);
|
||||
dst_canvas_id = ppd->canvas_id[index];
|
||||
src_position[0] = 0;
|
||||
src_position[1] = 0;
|
||||
src_position[2] = src_vf->width;
|
||||
src_position[3] = src_vf->height;
|
||||
if (src_position[2] == 0 || src_position[3] == 0) {
|
||||
ppmgr2_printk(1, "Source frame error!\n");
|
||||
mutex_unlock(ppd->ge2d_canvas_mutex);
|
||||
return -1;
|
||||
}
|
||||
dst_plane_position[0] = 0;
|
||||
dst_plane_position[1] = 0;
|
||||
dst_plane_position[2] = ppd->dst_width;
|
||||
dst_plane_position[3] = ppd->dst_height;
|
||||
|
||||
ge2d_src_config(src_vf, ge2d_config);
|
||||
|
||||
ge2d_mirror_config(ppd->mirror, ge2d_config);
|
||||
ge2d_angle_config(angle, ge2d_config);
|
||||
paint_mode_convert(ppd->paint_mode, src_position, dst_paint_position,
|
||||
dst_plane_position);
|
||||
|
||||
if (src_vf->type & VIDTYPE_INTERLACE)
|
||||
src_position[3] = src_vf->height >> 1;
|
||||
|
||||
ret = ge2d_paint_dst(context, ge2d_config, dst_canvas_id,
|
||||
dst_pixel_format, src_position,
|
||||
dst_paint_position, dst_plane_position);
|
||||
|
||||
mutex_unlock(ppd->ge2d_canvas_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ppmgr2_release(struct ppmgr2_device *ppd)
|
||||
{
|
||||
if (ppd->context)
|
||||
destroy_ge2d_work_queue(ppd->context);
|
||||
|
||||
/* switch_mod_gate_by_name("ge2d", 0); */
|
||||
ppmgr2_printk(2, "ppmgr2_release!\n");
|
||||
}
|
||||
|
||||
int v4l_to_ge2d_format(int v4l2_format)
|
||||
{
|
||||
int format = GE2D_FORMAT_M24_NV21;
|
||||
|
||||
switch (v4l2_format) {
|
||||
case V4L2_PIX_FMT_RGB32:
|
||||
format = GE2D_FORMAT_S32_ABGR;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
format = GE2D_FORMAT_S16_RGB_565;
|
||||
break;
|
||||
case V4L2_PIX_FMT_BGR24:
|
||||
format = GE2D_FORMAT_S24_RGB;
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB24:
|
||||
format = GE2D_FORMAT_S24_BGR;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
format = GE2D_FORMAT_M24_NV12;
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
format = GE2D_FORMAT_M24_NV21;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
case V4L2_PIX_FMT_YVU420:
|
||||
format = GE2D_FORMAT_S8_Y;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return format;
|
||||
}
|
||||
334
drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c
Normal file
334
drivers/amlogic/media/video_processor/ionvideo/videobuf2-ion.c
Normal file
@@ -0,0 +1,334 @@
|
||||
/*
|
||||
* 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 <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include <media/videobuf2-core.h>
|
||||
#include <media/videobuf2-memops.h>
|
||||
|
||||
/*#include <asm/mach/map.h>*/
|
||||
#include <ion.h>
|
||||
#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 <shuai.cao@amlogic.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 <media/videobuf2-core.h>
|
||||
|
||||
extern const struct vb2_mem_ops vb2_ion_memops;
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user