📄 kllad.c
字号:
/*Copyright (C) 2003 Sigma Designs, Inc.This library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 2.1 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*/#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/version.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/interrupt.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#include <linux/devfs_fs_kernel.h>#endif#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#define ALLOW_OS_CODE 1#ifdef WITH_PROC#ifdef WITH_MONITORING#include "kllad_proc.h"#endif#endif#define DIRECT_MAJOR 126unsigned long max_dmapool_memory_size = 4*1024*1024;unsigned long max_dmabuffer_log2_size = 17;/* Major number */static int major = DIRECT_MAJOR;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)MODULE_PARM(max_dmapool_memory_size, "i");MODULE_PARM(max_dmabuffer_log2_size, "i");MODULE_PARM(major, "i");#elsemodule_param(max_dmapool_memory_size, ulong, S_IRUGO|S_IWUSR);module_param(max_dmabuffer_log2_size, ulong, S_IRUGO|S_IWUSR);module_param(major, int, S_IRUGO|S_IRUSR);#endifMODULE_PARM_DESC(max_dmapool_memory_size, "Sets the maximum amount of memory shared by the all dmapools");MODULE_PARM_DESC(max_dmabuffer_log2_size, "Sets the dmapool buffers maximum size (ex: set 15 for 32kB)");MODULE_PARM_DESC(major, "Sets the major number");/* the main chip ids */#define EM86XX_CHIPID_MAMBO 1000#define EM86XX_CHIPID_MAMBOLIGHT 2000#define EM86XX_CHIPID_TANGO 3000#define EM86XX_CHIPID_TANGOLIGHT 4000#define EM86XX_CHIPID_TANGO15 4500#define EM86XX_CHIPID_TANGO2 5000#define EM86XX_CHIPID_TANGO3 10000#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#include <asm/tango2/hardware.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)#include <asm/tango2/rmdefs.h>#include <asm/tango2/tango2_gbus.h>#endif#include <linux/mm.h>#ifndef XLAT_G2P // Subject to redefinition in kernel#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#if defined(CONFIG_TANGO2_USE_TLB_REMAP_DRAM1) || defined(CONFIG_TANGOX_USE_TLB_REMAP_DRAM1) // In Tango 2, we need to remap addresses greater than 0x20000000. For this, the kernel is currently // - subject to change - setting the TLB so that @ > 0x20000000 is remapped to em86xx_tlb_dram1_map_base. // Therefore for the kernel point of view GBUS address is equal to PHYSICAL address.#define XLAT_G2P(g) (g)#else// In Tango 2, we need to remap addresses greater than 0x20000000. For this, the kernel is currently // - subject to change - setting the remap register so that @ > 0x20000000 is remapped to // 0x08000000. Therefore @ becomes @ - 0x20000000 + 0x08000000" (== 0x18000000) when @ > 0x20000000.#define XLAT_G2P(g) (((g) >= 0x20000000) ? ((g) - 0x18000000) : (g)) #endif#else#define XLAT_G2P(g) (g)#endif#endif#define REG_BASE_CPU REG_BASE_cpu_block//#include "../../../emhwlib_hal/include/emhwlib_registers.h"#define REG_BASE_HOST 0x20000#define PCI_devcfg_reg0 0xfee8#define PCI_devcfg_reg1 0xfeec#define PCI_devcfg_reg2 0xfef0#define PCI_devcfg_reg3 0xfef4#define SOFTIRQMASK_VALID 0xf010#define IRQ_SOFTINT (IRQ_CONTROLLER_IRQ_BASE+0) // Software interrupt#define IRQ_TIMER1 (IRQ_CONTROLLER_IRQ_BASE+6) // Timer 1#define IRQ_MBUS_W1 (IRQ_CONTROLLER_IRQ_BASE+10) // Host interface MBUS W1 channel#define IRQ_MBUS_R1 (IRQ_CONTROLLER_IRQ_BASE+12) // Host interface MBUS R1 channel#define IRQ_GRAPHICACCEL (IRQ_CONTROLLER_IRQ_BASE+23) // Graphic accelerator#define IRQ_VSYNC0 (IRQ_CONTROLLER_IRQ_BASE+24) // Vsync 0#define IRQ_VSYNC1 (IRQ_CONTROLLER_IRQ_BASE+25) // Vsync 1#define IRQ_VSYNC2 (IRQ_CONTROLLER_IRQ_BASE+26) // Vsync 2#define IRQ_VSYNC3 (IRQ_CONTROLLER_IRQ_BASE+27) // Vsync 3#if 0unsigned long loop_cnt = 5000;MODULE_PARM(loop_cnt, "i");MODULE_PARM_DESC(loop_cnt, "Sets the loop counter for vsync workaround");#endif/* buffer size for large data transfer transition into kernel */#define GBUS_BUF_SIZE (32 * 1024)static unsigned char gbus_buf[GBUS_BUF_SIZE] __attribute__ ((__aligned__(PAGE_SIZE)));#else /* (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) */#include <asm/hardware.h>#undef REG_BASE_cpu_block /* avoid redefinition */#define REG_BASE_cpu_block REG_BASE_CPU#endif /* (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)#ifndef __user#define __user#endif#endifstatic struct semaphore gbus_buf_sem;static spinlock_t open_lock;struct llad;struct gbus;#ifndef pGBus#define pGBus ((struct gbus *) 1)#endif#ifndef pLLAD#define pLLAD ((struct llad *) 1)#endif#include "kernelcalls.h"#include "../../include/kdmapool.h"// Update the value in emhwlib/include/emhwlib_resources.h as well#define UCLINUX_LLAD_IRQHANDLER_HANDSHAKE (REG_BASE_CPU + 0x006C)#define IRQHANDLER_ENTRY (REG_BASE_CPU + 0x0070) #define FIQHANDLER_ENTRY (REG_BASE_CPU + 0x0074) #define UNDEFHANDLER_ENTRY (REG_BASE_CPU + 0x0078) #define JUMPTABLE_ADDRESS (REG_BASE_CPU + 0x007c)#define UCLINUX_UNDEF_VECTOR (REG_BASE_CPU + 0x0048)#define UCLINUX_IRQ_VECTOR (REG_BASE_CPU + 0x005c)MODULE_DESCRIPTION("llad kernel module for standalone configuration");MODULE_AUTHOR("Mambo standalone team");MODULE_LICENSE("LGPL");#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)static inline int ctu(void __user *x, void *y, unsigned long z) { if (!access_ok(VERIFY_WRITE, x, z)) return -EFAULT; memcpy(x,y,z); return 0; }static inline int cfu(void *x, void __user *y, unsigned long z) { if (!access_ok(VERIFY_READ, y, z)) return -EFAULT; memcpy(x,y,z); return 0;}#elsestatic inline int ctu(void __user *x, void *y, unsigned long z) { int rc; if ((rc=copy_to_user(x,y,z))!=0) printk("copy_to_user %p %p %ld failed\n",x,y,z); return rc;}static inline int cfu(void *x, void __user *y, unsigned long z) { int rc; if ((rc=copy_from_user(x,y,z))!=0) printk("copy_from_user %p %p %ld failed\n",x,y,z); return rc;}#endifunsigned long long kc_longlongdiv(unsigned long long a, unsigned long long b);// For long long division// Otherwise We can not link _udivdi3 from libgcc.a due to a pic and non-pic problem.EXPORT_SYMBOL(kc_longlongdiv);unsigned long long kc_longlongdiv(unsigned long long a, unsigned long long b){ unsigned long long remainder = 0, quotient = 0; unsigned long r32,d,b_low; int i; unsigned char nbits = sizeof(unsigned long long)*8; if ( ((b >> 32 ) == 0) && ( (a >> 32 ) == 0) ) /* Simplest Case, 32 bits division */ return (unsigned long long)( (unsigned long) a / (unsigned long) b ); if ( (b >> 28) == 0){ /* Divisor is less than 28bit length */ b_low = (unsigned long)b; d = a >> 32; quotient = (d / b_low); r32 = d % b_low; for (i = 0; i < 8; i++) { d = (r32 << 4) | ((a >> (7-i)*4) & 0xf); quotient = (quotient << 4) | (d / b_low); r32 = d % b_low; } return quotient; } /* Skip first zeros */ quotient = ( (unsigned long long) 1 << ( nbits-1 ) ); while( quotient && ((a & quotient) == 0) ){ nbits--; quotient = quotient >> 1; } /* Compute, simple 2-radix */ quotient = 0; for ( i = (nbits-1) ; i >=0 ; i--){ remainder = remainder << 1 | (( a >> i ) & 1); quotient = quotient << 1 ; if ( remainder >= b ){ remainder = remainder - b; quotient |= 1 ; } } return quotient;}/** US_TO_JIFFIES abstraction * Microseconds are converted in jiffies. * 1 jiffie = 1000000/HZ us, where HZ = number of PC real timer interrupts per second. * If u < 1000000/HZ => 0 jiffies * Conversion is done using 64bit mult&div => maximum timeout is 71 min. * Usually HZ=100 => 1 jiffie = 10 ms. For HZ=512 => 1 jiffie = 1953.125 us */EXPORT_SYMBOL(US_TO_JIFFIES);unsigned long US_TO_JIFFIES(unsigned long u){ return (unsigned long)( kc_longlongdiv((unsigned long long)u * (unsigned long long)HZ, (unsigned long long)1000000) ); }//static unsigned long JIFFIES_TO_US(unsigned long j){ return j*(unsigned long)1000000/HZ; };EXPORT_SYMBOL(JIFFIES_TO_US);unsigned long JIFFIES_TO_US(unsigned long j){ return (unsigned long)( kc_longlongdiv((unsigned long long)j * (unsigned long long)1000000, (unsigned long long)HZ) ); }/******************* USEFUL FUNCTION TO ACCESS MAMBO REGISTER *********************/void llad_get_config(struct llad *pllad, char *config, unsigned long size);struct llad *llad_open(char *dev);void llad_close(struct llad *pllad);struct gbus *gbus_open(struct llad *pllad);void gbus_close(struct gbus *PGBUS);EXPORT_SYMBOL(llad_open);struct llad *llad_open(char *dev){ if (*dev == '0') return pLLAD; else return (struct llad *) NULL;}EXPORT_SYMBOL(llad_close);void llad_close(struct llad *pllad){}EXPORT_SYMBOL(gbus_open);struct gbus *gbus_open(struct llad *pllad){ if (pllad != NULL) return pGBus; return NULL;}EXPORT_SYMBOL(gbus_close);void gbus_close(struct gbus *PGBUS){}#if (EM86XX_CHIP!=EM86XX_CHIPID_TANGO2) #define RMuint32 unsigned longstatic inline void gbus_write_uint32(struct gbus *h, unsigned long byte_address, unsigned long data){ *((volatile unsigned long *) byte_address) = data;}static inline unsigned long gbus_read_uint32(struct gbus *h, unsigned long byte_address){ return *((volatile unsigned long *) byte_address);}#define gbus_save_flags_clf(x) \ { \ unsigned long tmp; \ __asm__( \ "mrs %0, cpsr\n" \ "orr %1, %0, #64\n" \ "msr cpsr_c, %1\n" \ : "=r" (x), "=r" (tmp) \ : \ : "memory"); \ }/* * Restore the saved value back to CPSR register. */#define gbus_restore_flags(x) \ __asm__( \ "msr cpsr_c, %0\n" \ : \ : "r" (x))#else#define RMPanic(x)#include "../../../init_4ke/helpers_4ke_mipsel.h"#define RMuint8 unsigned char#define RMuint16 unsigned short#define RMmin(x,y) (((x) < (y)) ? (x) : (y))/* gbus_read_uint* and gbus_write_uint* functions are defined in Linux * header file include/linux/config.h for TANGO2 */static inline void gbus_read_data8 (struct gbus *h, RMuint32 byte_address, RMuint8 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { *(data+i) = gbus_read_uint8(h, byte_address + i); }}static inline void gbus_read_data16(struct gbus *h, RMuint32 byte_address, RMuint16 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { *(data+i) = gbus_read_uint16(h, byte_address + 2*i); }}static inline void gbus_read_data32(struct gbus *h, RMuint32 byte_address, RMuint32 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { *(data+i) = gbus_read_uint32(h, byte_address + 4*i); }}static inline void gbus_write_data8 (struct gbus *h, RMuint32 byte_address, const RMuint8 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { gbus_write_uint8(h, byte_address + i, *(data+i)); }}static inline void gbus_write_data16(struct gbus *h, RMuint32 byte_address, const RMuint16 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { gbus_write_uint16(h, byte_address + 2*i, *(data+i)); }}static inline void gbus_write_data32(struct gbus *h, RMuint32 byte_address, const RMuint32 *data, RMuint32 count){ RMuint32 i; for (i=0 ; i<count ; i++) { gbus_write_uint32(h, byte_address + 4*i, *(data+i)); }}#endif/* struct llad; *//* #define pGBus ((struct gbus *) 1) *//* #define pLLAD ((struct llad *) 1) *//* struct llad *llad_open(char *dev); *//* void llad_close(struct llad *pllad); *//* void llad_get_config(struct llad *pllad, char *config, unsigned long size); *//* struct gbus *gbus_open(struct llad *pllad); *//* void gbus_close(struct gbus *PGBUS); *//* EXPORT_SYMBOL(llad_open); *//* struct llad *llad_open(char *dev) *//* { *//* if (*dev == '0') *//* return pLLAD; *//* else *//* return (struct llad *) NULL; *//* } *//* EXPORT_SYMBOL(llad_close); *//* void llad_close(struct llad *pllad) *//* { *//* } *//* EXPORT_SYMBOL(gbus_open); */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -