diff options
author | Lea Li <lea.li@marvell.com> | 2010-04-19 18:16:47 +0800 |
---|---|---|
committer | Lea Li <lea.li@marvell.com> | 2010-04-19 18:16:47 +0800 |
commit | d22406f55aa68562b23cc64d3249255f608eccd7 (patch) | |
tree | 1e58f82539ce661b81ebaa10dc8cd9eed1a5a44e |
initial commit
Signed-off-by: Lea Li <lea.li@marvell.com>
-rwxr-xr-x | vmeta_lib.c | 452 | ||||
-rwxr-xr-x | vmeta_lib.h | 144 |
2 files changed, 596 insertions, 0 deletions
diff --git a/vmeta_lib.c b/vmeta_lib.c new file mode 100755 index 0000000..9d83f30 --- /dev/null +++ b/vmeta_lib.c @@ -0,0 +1,452 @@ +/* + * vmeta_lib.c + * + * + * Copyright (C) 2009 Marvell International Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdarg.h> +#include <string.h> + +#include "vmeta_lib.h" +#include "bmm_lib.h" +#include "sys/poll.h" + + +#define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) +#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) + +// global variable +vdec_os_driver_cb_t *vdec_iface = NULL; +UNSG32 globalDbgLevel = VDEC_DEBUG_NONE; +struct timeval vdec_timer; + +//Add for hal mmap +UNSG8 vdec_os_api_rd8(UNSG32 addr) +{ + return *((volatile UNSG8*)addr); +} + +UNSG16 vdec_os_api_rd16(UNSG32 addr) +{ + return *((volatile UNSG16*)addr); +} + +UNSG32 vdec_os_api_rd32(UNSG32 addr) +{ + return *((volatile UNSG32*)addr); +} + +void vdec_os_api_wr8(UNSG32 addr, UNSG8 data) +{ + *((volatile UNSG8*)addr) = data; +} + +void vdec_os_api_wr16(UNSG32 addr, UNSG16 data) +{ + *((volatile UNSG16*)addr) = data; +} + +void vdec_os_api_wr32(UNSG32 addr, UNSG32 data) +{ + *((volatile UNSG32*)addr) = data; +} + +UNSG32 vdec_os_api_get_regbase_addr(void) +{ + vdec_os_driver_cb_t *vdec_iface = vdec_driver_get_cb(); + return vdec_iface->io_mem_virt_addr; +} +//End of hal mmap + +//Mem map to bmm_lib +UNSG32 vdec_os_api_get_pa(UNSG32 vaddr) +{ + return ((UNSG32)bmm_get_paddr((void *)vaddr)); +} + +UNSG32 vdec_os_api_get_va(UNSG32 paddr) +{ + return ((UNSG32)bmm_get_vaddr((void *)paddr)); +} + +void vdec_os_api_vfree(void *ptr) +{ + unsigned int offset = 0; + unsigned int *paddr = NULL; + + paddr = (unsigned int *)(ptr); + offset = *(paddr - 1); + paddr = (unsigned int *)((unsigned int)paddr - offset); + free((void *)paddr); +} + +void *vdec_os_api_vmalloc(UNSG32 size, UNSG32 align) +{ + unsigned int *ptr = NULL; + unsigned int tmp = 0; + + align = ALIGN(align, sizeof(int)); + size += align; + ptr = malloc(size); + if (!ptr) { + printf("\tno enough memory\n"); + return NULL; + } + + tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); + tmp = (unsigned int)(align - tmp); + ptr = (unsigned int *)((unsigned int)ptr + tmp); + *(ptr - 1) = tmp; + + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_vmalloc ptr: 0x%x\n", ptr); + return ptr; +} + +void vdec_os_api_dma_free(void *ptr) +{ + unsigned int offset = 0; + unsigned int *paddr = NULL; + + paddr = (unsigned int *)(ptr); + offset = *(paddr - 1); + paddr = (unsigned int *)((unsigned int)paddr - offset); + bmm_free((void *)paddr); +} + +void * vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) +{ + unsigned int *ptr = NULL; + unsigned int tmp = 0; + + if(size <= 0) + return NULL; + + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc -> size: 0x%x\n", size); + + align = ALIGN(align, sizeof(int)); + size += align; + ptr = bmm_malloc(size, BMM_ATTR_NONBUFFERABLE | BMM_ATTR_NONCACHEABLE); + if (!ptr) { + printf("\tno enough memory\n"); + return NULL; + } + + tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); + tmp = (unsigned int)(align - tmp); + ptr = (unsigned int *)((unsigned int)ptr + tmp); + *(ptr - 1) = tmp; + + *pPhysical = (unsigned long)bmm_get_paddr(ptr); + + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc ptr: 0x%x\n", ptr); + //memset(ptr, 0, size); + + return ptr; +} + +UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction) +{ + switch (direction) { + case DMA_FROM_DEVICE: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_FROM_DEVICE); + break; + case DMA_TO_DEVICE: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_TO_DEVICE); + break; + case DMA_BIDIRECTIONAL: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_BIDIRECTIONAL); + break; + } + return 0; +} + +// enable vmeta interrupt +void vdec_os_api_irq_enable(void) +{ + if(vdec_iface == NULL) + return; + + ioctl(vdec_iface->uiofd, UIO_VPRO_IRQ_ENABLE); +} + +// disable vmeta interrupt +void vdec_os_api_irq_disable(void) +{ + if(vdec_iface == NULL) + return; + + ioctl(vdec_iface->uiofd, UIO_VPRO_IRQ_DISABLE); +} + +SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout) +{ + vdec_timer.tv_sec = 0; + vdec_timer.tv_usec = timeout * 1000; + + return 0; +} + +SIGN32 vdec_os_api_sync_event() +{ + SIGN32 ret = VDEC_OS_DRIVER_OK; + fd_set rd_fds, tmp_fds; + struct timeval timeout; + + if(vdec_iface == NULL) + return -VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL; + + FD_ZERO(&rd_fds); + FD_SET(vdec_iface->uiofd, &rd_fds); + + timeout.tv_sec = vdec_timer.tv_sec; + timeout.tv_usec = vdec_timer.tv_usec; + + while(1) { + int ret = 0; + + tmp_fds = rd_fds; + + // enable interrupt + vdec_os_api_irq_enable(); + + ret = select(vdec_iface->uiofd + 1, &tmp_fds, NULL, NULL, &timeout); + if(FD_ISSET(vdec_iface->uiofd, &tmp_fds)) { + int irq_num; + read(vdec_iface->uiofd, &irq_num, sizeof(int)); + // Or handle userspace ISR here + break; + } + + // timeout + ret = -VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL; + + break; + } + + return ret; +} +//End of mem mmap + +UNSG32 get_mem_size(char *msg) +{ + int ret; + UNSG32 result; + FILE *file = fopen(msg, "r"); + + if(!file) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_mem_size -> fopen failed\n"); + return -VDEC_OS_DRIVER_OPEN_FAIL; + } + + ret = fscanf(file, "0x%x", &result); + if(ret<0) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_mem_size -> fscanf failed\n"); + result = 0; + } + + fclose(file); + return result; +} + +UNSG32 get_mem_addr(char *msg) +{ + UNSG32 result; + int ret; + FILE *file = fopen(msg, "r"); + + if(!file) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_mem_addr -> fopen failed\n"); + return -VDEC_OS_DRIVER_OPEN_FAIL; + } + + ret = fscanf(file, "0x%x", &result); + if(ret<0) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_mem_addr -> fscanf failed\n"); + result = 0; + } + + fclose(file); + return result; +} + +// VMeta power on +void vdec_os_api_power_on(void) { + if(vdec_iface == NULL) + return; + + ioctl(vdec_iface->uiofd, UIO_VMETA_POWER_ON); + } + +// VMeta power off +void vdec_os_api_power_off(void) { + if(vdec_iface == NULL) + return; + + ioctl(vdec_iface->uiofd, UIO_VMETA_POWER_OFF); +} + +// check VMeta is ready to suspend +SIGN32 vdec_os_api_suspend_check(void) { + SIGN32 suspend_check; + + if(vdec_iface == NULL) + return 0; + + ioctl(vdec_iface->uiofd, UIO_VMETA_SUSPEND_CHECK, &suspend_check); + + return suspend_check; +} + +// VMeta is ready to suspend +void vdec_os_api_suspend_ready(void) { + if(vdec_iface == NULL) + return; + + ioctl(vdec_iface->uiofd, UIO_VMETA_SUSPEND_READY); +} + +// init vdec os driver +SIGN32 vdec_os_driver_init(void) +{ + int ret = 0; + + if(vdec_iface != NULL) { // already been initiated + vdec_iface->refcount++; + return ret; + } + + // Prepare the vdec os driver control interface + vdec_iface = (vdec_os_driver_cb_t*)malloc(sizeof(vdec_os_driver_cb_t)); + memset((void*)vdec_iface, 0, sizeof(vdec_os_driver_cb_t)); + if(vdec_iface == NULL) + return -VDEC_OS_DRIVER_INIT_FAIL; + + // initialize reference count + vdec_iface->refcount++; + + // Open the vdec uio driver + vdec_iface->uiofd = open(UIO_DEV, O_RDWR); + if(vdec_iface->uiofd < 0) { + ret = -VDEC_OS_DRIVER_OPEN_FAIL; + goto err_open_fail; + } + dbg_printf(VDEC_DEBUG_ALL, "vdec os driver open: %s\n", UIO_DEV); + + // Get the IO mem size of vPro's register + vdec_iface->io_mem_size = get_mem_size(UIO_IO_MEM_SIZE); + if(vdec_iface->io_mem_size <= 0) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + goto err_mmap_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec os driver io mem size: 0x%x\n", vdec_iface->io_mem_size); + + // Get the IO mem phy addr + vdec_iface->io_mem_phy_addr = get_mem_addr(UIO_IO_MEM_ADDR); + if(vdec_iface->io_mem_phy_addr <= 0) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + goto err_mmap_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec os driver io mem phy addr: 0x%x\n", vdec_iface->io_mem_phy_addr); + + // mmap the io mem area + vdec_iface->io_mem_virt_addr = (SIGN32)mmap(NULL, vdec_iface->io_mem_size, + PROT_READ|PROT_WRITE, MAP_SHARED, vdec_iface->uiofd, 0); + + if(vdec_iface->io_mem_virt_addr == -1) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + goto err_mmap_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec os driver io mem map to: 0x%x\n", vdec_iface->io_mem_virt_addr); + + return ret; + +err_mmap_fail: + if(vdec_iface->io_mem_virt_addr > 0) + munmap((void*)vdec_iface->io_mem_virt_addr, vdec_iface->io_mem_size); + close(vdec_iface->uiofd); +err_open_fail: + free((void*)vdec_iface); + vdec_iface = NULL; + + return ret; +} + +// clean vdec os driver +SIGN32 vdec_os_driver_clean(void) +{ + if(vdec_iface == NULL) + return -VDEC_OS_DRIVER_CLEAN_FAIL; + + // decrease the refcount + vdec_iface->refcount--; + + if(vdec_iface->refcount != 0) + return 0; + + // unmap memory area + if(vdec_iface->io_mem_virt_addr > 0) + munmap((void*)vdec_iface->io_mem_virt_addr, vdec_iface->io_mem_size); + + // close fd + if(vdec_iface->uiofd > 0) + close(vdec_iface->uiofd); + + // free vdec_iface + if(vdec_iface != NULL) { + free((void*)vdec_iface); + vdec_iface = NULL; + } + + return 0; +} + +/* display debug message */ +int dbg_printf(UNSG32 dbglevel, const char* format, ...) { + char dbgBuf[256] = {'\0'}; + va_list var; + + if(VDEC_DEBUG_NONE == globalDbgLevel) + return 0; + else { + va_start(var, format); + vsprintf(dbgBuf, format, var); + va_end(var); + + if(VDEC_DEBUG_ALL & globalDbgLevel) + printf(dbgBuf); + else if((VDEC_DEBUG_MEM & globalDbgLevel) && (dbglevel == VDEC_DEBUG_MEM)) + printf(dbgBuf); + else + return 0; + } + + return 0; +} + +/* vdec driver get cb */ +vdec_os_driver_cb_t *vdec_driver_get_cb(void) { + return vdec_iface; +} diff --git a/vmeta_lib.h b/vmeta_lib.h new file mode 100755 index 0000000..561e855 --- /dev/null +++ b/vmeta_lib.h @@ -0,0 +1,144 @@ +#ifndef VDEC_OS_DRIVER_H +#define VDEC_OS_DRIVER_H +#include <sys/poll.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define VDEC_DEBUG_ALL 0x1 +#define VDEC_DEBUG_MEM 0x2 +#define VDEC_DEBUG_NONE 0x80 + +#define UIO_DEV "/dev/uio0" +#define UIO_IO_MEM_SIZE "/sys/class/uio/uio0/maps/map0/size" +#define UIO_IO_MEM_ADDR "/sys/class/uio/uio0/maps/map0/addr" + +//--------------------------------------------------------------------------- +// Macros +//--------------------------------------------------------------------------- +#ifndef UNSG32 +#define UNSG32 unsigned int +#endif + +#ifndef SIGN32 +#define SIGN32 int +#endif + +#ifndef UNSG16 +#define UNSG16 unsigned short +#endif + +#ifndef SIGN16 +#define SIGN16 short +#endif + +#ifndef UNSG8 +#define UNSG8 unsigned char +#endif + +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +//--------------------------------------------------------------------------- +// Driver initialization API +//--------------------------------------------------------------------------- +SIGN32 vdec_os_driver_init(void); +SIGN32 vdec_os_driver_clean(void); + +//--------------------------------------------------------------------------- +// Memory operation API +//--------------------------------------------------------------------------- +void * vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 * pPhysical); + +void vdec_os_api_dma_free(void *ptr); +void *vdec_os_api_vmalloc(UNSG32 size, UNSG32 align); // always return VA and can't be translated to PA +void vdec_os_api_vfree(void *ptr); +UNSG32 vdec_os_api_get_va(UNSG32 paddr); +UNSG32 vdec_os_api_get_pa(UNSG32 vaddr); + +UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction); + +//--------------------------------------------------------------------------- +// Mem/IO R/W API +//--------------------------------------------------------------------------- +UNSG8 vdec_os_api_rd8(UNSG32 addr); +UNSG16 vdec_os_api_rd16(UNSG32 addr); +UNSG32 vdec_os_api_rd32(UNSG32 addr); +void vdec_os_api_wr8(UNSG32 addr, UNSG8 data); +void vdec_os_api_wr16(UNSG32 addr, UNSG16 data); +void vdec_os_api_wr32(UNSG32 addr, UNSG32 data); +UNSG32 vdec_os_api_get_regbase_addr(void); // return VA + +//--------------------------------------------------------------------------- +// Interrupt register API +//--------------------------------------------------------------------------- +SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout); +SIGN32 vdec_os_api_sync_event(); + +//--------------------------------------------------------------------------- +// Power Management API +//--------------------------------------------------------------------------- +void vdec_os_api_power_on(void); +void vdec_os_api_power_off(void); +SIGN32 vdec_os_api_suspend_check(void); +void vdec_os_api_suspend_ready(void); + +typedef enum _VPRO_CODEC_ERROR_CODE_ { + VDEC_OS_DRIVER_OK = 0, + VDEC_OS_DRIVER_INIT_FAIL, + VDEC_OS_DRIVER_OPEN_FAIL, + VDEC_OS_DRIVER_NO_SYS_MEM_FAIL, + VDEC_OS_DRIVER_MEM_POOL_INIT_FAIL, + VDEC_OS_DRIVER_MMAP_FAIL, + VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL, + VDEC_OS_DRIVER_IO_CONTROL_FAIL, + VDEC_OS_DRIVER_ALREADY_INIT_FAIL, + VDEC_OS_DRIVER_CLEAN_FAIL +}VPRO_DEC_ERROR_CODE; + +/************************* + * Vmeta ioctl Define * + *************************/ +#define IOP_MAGIC 'v' + +#define UIO_VPRO_IRQ_ENABLE _IO(IOP_MAGIC, 2) +#define UIO_VPRO_IRQ_DISABLE _IO(IOP_MAGIC, 3) +#define UIO_VPRO_XV_IN_QUEUE _IOW(IOP_MAGIC, 4, struct vpro_xv_frame) // used for vpro decoder to put a video frame in queue +#define UIO_VPRO_XV_DQUEUE _IOR(IOP_MAGIC, 5, struct vpro_xv_frame) // used for vpro decoder to free a video frame in queue +#define UIO_VPRO_XV_QUERY_VIDEO _IOR(IOP_MAGIC, 6, struct vpro_xv_frame) // used for vo xv interface to query a video frame that from vpro +#define UIO_VPRO_XV_FREE_VIDEO _IOW(IOP_MAGIC, 7, struct vpro_xv_frame) // used for vo xv interface to free a video frame +#define UIO_VPRO_XV_INIT_QUEUE _IO(IOP_MAGIC, 8) +#define UIO_VMETA_POWER_ON _IO(IOP_MAGIC, 9) +#define UIO_VMETA_POWER_OFF _IO(IOP_MAGIC, 10) +#define UIO_VMETA_SUSPEND_CHECK _IOR(IOP_MAGIC, 11, int) +#define UIO_VMETA_SUSPEND_READY _IO(IOP_MAGIC, 12) + +/* display debug message */ +int dbg_printf(UNSG32 dbglevel, const char* format, ...); + +//--------------------------------------------------------------------------- +// the control block of vdec os driver +//--------------------------------------------------------------------------- +typedef struct vdec_os_driver_cb_s +{ + int uiofd; // the uio file descriptor + UNSG32 io_mem_phy_addr; // the physical addr of io register base + SIGN32 io_mem_virt_addr; // the reg base addr that maped from kernel + UNSG32 io_mem_size; // the size of io mem area + int refcount; // reference count +} vdec_os_driver_cb_t; + +/* vdec driver get cb */ +vdec_os_driver_cb_t *vdec_driver_get_cb(void); + + +#ifdef __cplusplus +} +#endif +#endif |