From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- .../gfxdrivers/davinci/kernel-module/c64x/c64x.c | 507 +++++++++++++++++++++ 1 file changed, 507 insertions(+) create mode 100755 Source/DirectFB/gfxdrivers/davinci/kernel-module/c64x/c64x.c (limited to 'Source/DirectFB/gfxdrivers/davinci/kernel-module/c64x/c64x.c') diff --git a/Source/DirectFB/gfxdrivers/davinci/kernel-module/c64x/c64x.c b/Source/DirectFB/gfxdrivers/davinci/kernel-module/c64x/c64x.c new file mode 100755 index 0000000..bbbbfe9 --- /dev/null +++ b/Source/DirectFB/gfxdrivers/davinci/kernel-module/c64x/c64x.c @@ -0,0 +1,507 @@ +/* + TI Davinci driver - C64X+ DSP Kernel Module + + (c) Copyright 2007 Telio AG + + Written by Olaf Dreesen . + + All rights reserved. + + This module is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. + + 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 + General Public License for more details. + + You should have received a copy of the GNU 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#define C64X_IRQ + +MODULE_LICENSE("GPL v2"); +//MODULE_LICENSE("Propietary"); +MODULE_AUTHOR("Olaf Dreesen "); +MODULE_DESCRIPTION("A little c64+ handling module."); + +#define C_MOD_MAJOR 400 +#define C_MOD_NUM_DEV 1 +#define C_MOD_NAME "c64x" +#define F_NAME "c64x_drv.bin" + +#define CODE_BASE 0x00800000 + +/* DDR2: + * + * transfer buffer + */ +#define R_BASE DAVINCI_C64X_MEM +#define R_LEN 0x02000000 + +/* L2RAM: + * + * 0x00800000 - 0x0080FFFF C64x+ + * 0x11800000 - 0x1180FFFF ARM + */ +#define D_BASE 0x11800000 +#define D_LEN 0x00010000 + +/* L1DRAM: + * + * 0x00F04000 - 0x00F0FFFF C64x+ + * 0x11F04000 - 0x11F0FFFF ARM + * + * Queue controls @ 0x00F04000 (4096 Bytes) + */ +#define Q_BASE 0x11F04000 +#define Q_LEN 0x00001000 + +#define HQueueDSP (l1dram[0x00>>2]) +#define HQueueARM (l1dram[0x04>>2]) +#define LQueueDSP (l1dram[0x08>>2]) +#define LQueueARM (l1dram[0x0C>>2]) +#define DSPidle (l1dram[0x10>>2]) + +/* IO Register needed: + * + * 0x01C40008 DSPBOOTADDR DSP Boot Address + * 0x01C40010 INTGEN Interrupt Generator + * 0x01C40038 CHP_SHRTSW DSP Power + * 0x01C4169C MDCFG39 DSP Module config + * 0x01C41A9C MDCTL39 DSP Module control + */ +#define IO_BASE 0x01c40000 +#define IO_LEN 0x00010000 + +#define DSPBOOTADDR (mmr[0x0008>>2]) +#define INTGEN (mmr[0x0010>>2]) +#define CHP_SHRTSW (mmr[0x0038>>2]) +#define MDCFG39 (mmr[0x169C>>2]) +#define MDCTL39 (mmr[0x1A9C>>2]) + +MODULE_FIRMWARE(F_NAME); + +static dev_t dev_major; +static struct cdev*dev_cdev; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) +static struct class*dev_class; +#else +static struct class_simple*dev_class; +#endif + +static volatile unsigned int*mmr=0; +static unsigned char*l2ram=0; +static volatile unsigned int*l1dram=0; +static volatile void*dram=0; +static volatile c64xTaskControl*c64xctl=0; +static volatile c64xTask*queue_l=0; + +#ifdef C64X_IRQ +static int dev_irq=46; +static DECLARE_WAIT_QUEUE_HEAD( wait_irq ); + +/* IRQ */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) +static irqreturn_t dev_irq_handler(int irq,void*dev_id) { +#else +static irqreturn_t dev_irq_handler(int irq,void*dev_id,struct pt_regs*regs) { +#endif + wake_up_all( &wait_irq ); + return IRQ_HANDLED; +} +#endif + +static u32 opencnt=0; + +/* char-dev */ +static int dev_open(struct inode*inode,struct file*filp) { + if (opencnt++==0) { + DSPidle=0; + MDCTL39=0x00000103; /* Go! Go, go Go! */ + while(DSPidle==0); + } + return 0; +} +static int dev_release(struct inode*inode,struct file*filp) { + if (--opencnt==0) { + MDCTL39=0x00000000; /* local reset */ + } + return 0; +} + +static ssize_t dev_write(struct file*filp,const char __user*buffer,size_t len,loff_t*off) { + long ret=0; + unsigned long offset=*off; + if (offset=D_LEN) { len=D_LEN-offset; } +// printk(KERN_INFO "c64x+ : read got offset %08lx %08lx\n",offset,(long)len); + ret=len; + *off+=len; + } + return ret; +} +static ssize_t dev_read(struct file*filp,char __user*buffer,size_t len,loff_t*off) { + long ret=0; + unsigned long offset=*off; + if (offset=D_LEN) { len=D_LEN-offset; } +// printk(KERN_INFO "c64x+ : read got offset %08lx %08lx\n",offset,(long)len); + ret=len; + ret-=copy_to_user(buffer,(l2ram+offset),len); + *off+=len; + } + return ret; +} + +static int dev_mmap(struct file * file, struct vm_area_struct * vma) { + size_t size=vma->vm_end-vma->vm_start; + if (vma->vm_pgoff) { + if (size!=R_LEN) return -EINVAL; +#if defined(pgprot_writecombine) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); +#else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); +#endif + if (remap_pfn_range(vma, + vma->vm_start, + R_BASE>>PAGE_SHIFT, + size, + vma->vm_page_prot)) + return -EAGAIN; + } + else { + if (size!=Q_LEN) return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (remap_pfn_range(vma, + vma->vm_start, + Q_BASE>>PAGE_SHIFT, + size, + vma->vm_page_prot)) + return -EAGAIN; + } + return 0; +} + +static void +c64x_dump( const char *condition ) +{ + static const char *state_names[] = { "DONE", "ERROR", "TODO", "RUNNING" }; + + uint32_t ql_dsp = c64xctl->QL_dsp; + uint32_t ql_arm = c64xctl->QL_arm; + uint32_t tl_dsp = queue_l[ql_dsp & C64X_QUEUE_MASK].c64x_function; + uint32_t tl_arm = queue_l[ql_arm & C64X_QUEUE_MASK].c64x_function; + int dl; + + dl = ql_arm - ql_dsp; + if (dl < 0) + dl += C64X_QUEUE_LENGTH; + + printk( "C64X+ Queue: %s\n" + " [DSP %d / %d (%s), ARM %d / %d (%s)] <- %d pending\n", + condition, + ql_dsp, (tl_dsp >> 2) & 0x3fff, state_names[tl_dsp & 3], + ql_arm, (tl_arm >> 2) & 0x3fff, state_names[tl_arm & 3], + dl ); +} + +static int +c64x_wait_low( void ) +{ + int ret; + int num = 0; + /* Keep reference values for comparison. */ + u32 idle = c64xctl->idlecounter; + u32 dsp = c64xctl->QL_dsp; + + /* Wait for equal pointers... */ + while (dsp != c64xctl->QL_arm) { + /* ...each time for a 1/50 second... */ + ret = wait_event_interruptible_timeout( wait_irq, c64xctl->QL_dsp == c64xctl->QL_arm, HZ/50 ); + if (ret < 0) + return ret; + + /* ...if after that 1/50 second still the same command is running... */ + if (!ret && c64xctl->QL_dsp == dsp) { + /* ...and almost one second elapsed in total, or the DSP felt idle... */ + if (++num > 42 || c64xctl->idlecounter != idle) { + /* ...timeout! */ + printk( KERN_ERR "c64x+ : timeout waiting for idle queue\n" ); + c64x_dump( "TIMEOUT!!!" ); + return -ETIMEDOUT; + } + } + else { + /* Different command running, reset total elapsed time. */ + num = 0; + } + + /* Update reference values. */ + idle = c64xctl->idlecounter; + dsp = c64xctl->QL_dsp; + } + + return 0; +} + +static int dev_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) { + switch (cmd) { + case C64X_IOCTL_RESET: + MDCTL39=0x00000000; /* local reset */ + mdelay(10); + DSPidle=0; + MDCTL39=0x00000103; + break; + case C64X_IOCTL_WAIT_LOW: + return c64x_wait_low(); + default: + printk(KERN_INFO "c64x+ : unknown ioctl : cmd=%08x\n",cmd); + return -EAGAIN; + break; + } + return 0; +} +static struct file_operations dev_file_ops={ + .owner = THIS_MODULE, + .open = dev_open, + .release = dev_release, + .read = dev_read, + .write = dev_write, + .mmap = dev_mmap, + .ioctl = dev_ioctl, +}; + +/* INIT */ +static __initdata struct device dev_device = { + .bus_id = "c64x0", +}; +static int __init dev_init(void) { + int ret=-EIO; + u8 *at; + const struct firmware*fw = NULL; + + printk(KERN_INFO "c64x+ : module load\n"); + + if ((dram=ioremap(R_BASE,R_LEN))==0) { + printk(KERN_ERR "c64x+ : module couldn't get memory\n"); + goto err0; + } + printk(KERN_INFO "c64x+ : module got memory @ %p\n",dram); + queue_l = dram + 0x01e00000; + + /* get the 'device' memory */ + if ((mmr=ioremap(IO_BASE,IO_LEN))==0) { + printk(KERN_ERR "c64x+ : module couldn't get IO-MMR\n"); + goto err0; + } + printk(KERN_INFO "c64x+ : DSP bootaddr: %08x\n",DSPBOOTADDR); + printk(KERN_INFO "c64x+ : got mmr %p %08x %08x\n",mmr,MDCTL39,MDCFG39); + + printk(KERN_INFO "c64x+ : switch state: %08x\n",CHP_SHRTSW); + + MDCTL39=0x00000000; /* local reset */ + mdelay(10); + DSPBOOTADDR=CODE_BASE; /* set DSP base address */ + +// printk(KERN_INFO "c64x+ : check0: %p %08x %08x\n",mmr,MDCTL39,MDCFG39); + + /* get the 'device' memory */ + if ((l1dram=ioremap(Q_BASE,Q_LEN))==0) { + printk(KERN_ERR "c64x+ : module couldn't get L1 dsp-memory\n"); + goto err1; + } + printk(KERN_INFO "c64x+ : module got L1D @ %p\n",l1dram); + c64xctl = (volatile void*)l1dram; + + if ((l2ram=ioremap(D_BASE,D_LEN))==0) { + printk(KERN_ERR "c64x+ : module couldn't get L2 dsp-memory\n"); + goto err2; + } + printk(KERN_INFO "c64x+ : module got L2 @ %p\n",l2ram); + + /* request firmware */ + device_initialize(&dev_device); + ret=device_add(&dev_device); + if (ret) { + printk(KERN_ERR "c64x+ : device_add failed\n"); + goto err3; + } + printk(KERN_INFO "c64x+ : module requesting firmware '%s'\n",F_NAME); + ret=request_firmware(&fw,F_NAME,&dev_device); + printk(KERN_INFO "c64x+ : module got fw %p\n",fw); + if (ret) { + printk(KERN_ERR "c64x+ : no firmware upload (timeout or file not found?)\n"); + device_del(&dev_device); + goto err3; + } + printk(KERN_INFO "c64x+ : firmware upload %p %zd\n",fw->data,fw->size); + if (fw->size>32767) { + printk(KERN_ERR "c64x+ : firmware too big! 32767 is maximum (for now)\n"); + release_firmware(fw); + device_del(&dev_device); + goto err3; + } + if (memcmp(fw->data+8,"C64x+DV",8)) { + printk(KERN_ERR "c64x+ : firmware signature missing\n"); + release_firmware(fw); + device_del(&dev_device); + goto err3; + } + at = fw->data + fw->size; + while ((ulong)--at > (ulong)fw->data) { + if (*at == '@') + break; + } + if (at == fw->data) { + printk(KERN_ERR "c64x+ : firmware tag missing\n"); + release_firmware(fw); + device_del(&dev_device); + goto err3; + } + printk(KERN_NOTICE "c64x+ : got firmware of length %d at %p with tag '%*s' of length %d at %p+1\n", + fw->size, fw->data, + (int)((ulong)(fw->data + fw->size) - (ulong)at - 1), at + 1, + (int)((ulong)(fw->data + fw->size) - (ulong)at - 1), at ); + /* move firmware into the hardware buffer here. */ + memcpy(l2ram,fw->data,fw->size); + release_firmware(fw); + device_del(&dev_device); + +#if 0 + /* release DSP */ + printk(KERN_INFO "c64x+ : check1: %p %08x %08x\n",mmr,MDCTL39,MDCFG39); + MDCTL39=0x00000103; /* Hopefully run... */ + printk(KERN_INFO "c64x+ : check2: %p %08x %08x\n",mmr,MDCTL39,MDCFG39); + printk(KERN_INFO "c64x+ : check3: %08x\n",DSPBOOTADDR); +#endif + + /* register char-dev */ + dev_major=MKDEV(C_MOD_MAJOR,0); + ret=register_chrdev_region(dev_major,C_MOD_NUM_DEV,C_MOD_NAME); + if (ret) { + printk(KERN_ERR "c64x+ : can't get chrdev %d\n",C_MOD_MAJOR); + goto err3; + } + + /* allocate cdev */ + dev_cdev=cdev_alloc(); + dev_cdev->ops=&dev_file_ops; + /* cdev_init(&dev_data.cdev,&dev_file_ops); */ + ret=cdev_add(dev_cdev,dev_major,1); + if (ret) { + printk(KERN_ERR "c64x+ : can't allocate cdev\n"); + goto err4; + } + +#ifdef C64X_IRQ + /* allocate interrupt slot */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21) + ret=request_irq(dev_irq,dev_irq_handler,IRQF_DISABLED,C_MOD_NAME,NULL); +#else + ret=request_irq(dev_irq,dev_irq_handler,SA_INTERRUPT ,C_MOD_NAME,NULL); +#endif + if (ret) { + printk(KERN_ERR "c64x+ : can't get IRQ %d\n",dev_irq); + goto err5; + } +#endif + + /* tell sysfs/udev */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + dev_class=class_create(THIS_MODULE,C_MOD_NAME); +#else + dev_class=class_simple_create(THIS_MODULE,C_MOD_NAME); +#endif + if (IS_ERR(dev_class)) { + ret=PTR_ERR(dev_class); + printk(KERN_ERR "c64x+ : can't allocate class\n"); + goto err6; + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + class_device_create(dev_class,NULL,dev_major,NULL,C_MOD_NAME"%d",0); +#else + class_simple_device_add(dev_class,dev_major,NULL,C_MOD_NAME"%d",0); +#endif + + printk(KERN_INFO "c64x+ : module load finished\n"); + return 0; + /* error out */ +err6: +#ifdef C64X_IRQ + free_irq(dev_irq,0); +err5: +#endif + cdev_del(dev_cdev); +err4: + unregister_chrdev_region(dev_major,1); +err3: + iounmap(l2ram); +err2: + iounmap((void*)l1dram); +err1: + iounmap((void*)mmr); +err0: + if (dram) + iounmap((void*)dram); + return ret; +} +module_init(dev_init); + +/* EXIT */ +static void __exit dev_exit(void) { + /* Put the DSP into Reset */ + MDCTL39=0x00000000; + /* release the DSP memory */ + iounmap((void*)mmr); + iounmap((void*)l1dram); + iounmap(l2ram); + /* release all the other resources */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) + class_device_destroy(dev_class,dev_major); + class_destroy(dev_class); +#else + class_simple_device_remove(dev_major); + class_simple_destroy(dev_class); +#endif +#ifdef C64X_IRQ + free_irq(dev_irq,0); +#endif + cdev_del(dev_cdev); + unregister_chrdev_region(dev_major,C_MOD_NUM_DEV); +} +module_exit(dev_exit); + -- cgit