/* * 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 #include #include #include #include #include #include #include #include #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_NONCACHED); 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; } void * vdec_os_api_dma_alloc_writecombine(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_WRITECOMBINE); 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; } void * vdec_os_api_dma_alloc_cached(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_DEFAULT); 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; }