From 7b5b08d99d5362e9c36fd7d42d6c06c2a848266c Mon Sep 17 00:00:00 2001 From: Kurt Mahan <kmahan@freescale.com> Date: Sun, 9 Dec 2007 02:21:19 -0700 Subject: [PATCH] Update EDMA. LTIBName: m5445x-edma-update Signed-off-by: Kurt Mahan <kmahan@freescale.com> --- drivers/spi/coldfire_edma.c | 261 +++++++++++++++++++++++--------------- include/asm-m68k/coldfire_edma.h | 9 +- include/asm-m68k/mcf5445x_edma.h | 28 +++- 3 files changed, 188 insertions(+), 110 deletions(-) --- a/drivers/spi/coldfire_edma.c +++ b/drivers/spi/coldfire_edma.c @@ -20,76 +20,91 @@ #include <linux/cdev.h> #include <linux/seq_file.h> #include <linux/proc_fs.h> +#ifdef CONFIG_M54455 #include <asm/mcf5445x_edma.h> #include <asm/mcf5445x_intc.h> +#endif /* CONFIG_M54455 */ #include <asm/coldfire_edma.h> - -/* callback handler data for each TCD */ +/* + * Callback handler data for each TCD + */ struct edma_isr_record { - edma_irq_handler irq_handler; /* interrupt handler */ - edma_error_handler error_handler; /* error interrupt handler */ - void* dev; /* device used for the channel */ - int allocated; /* busy flag */ - spinlock_t *lock; /* spin lock (if needs to be locked in interrupt) */ - const char* device_id; /* device id string, used in proc file system */ + edma_irq_handler irq_handler; /* interrupt handler */ + edma_error_handler error_handler; /* error interrupt handler */ + void *arg; /* argument to pass back */ + int allocated; /* busy flag */ + spinlock_t *lock; /* spin lock (optional) */ + const char *device_id; /* dev id string, used in procfs */ }; -/* device structure */ +/* + * Device structure + */ struct coldfire_edma_dev { - struct cdev cdev; /* character device */ - struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; /* channel handlers */ + struct cdev cdev; /* character device */ + struct edma_isr_record dma_interrupt_handlers[EDMA_CHANNELS]; }; /* allocated major device number */ static int coldfire_dma_major; + /* device driver structure */ -static struct coldfire_edma_dev* devp = NULL; +static struct coldfire_edma_dev *devp = NULL; /* device driver file operations */ struct file_operations coldfire_edma_fops = { .owner = THIS_MODULE, }; -/* eDMA channel interrupt handler */ +/** + * dmaisr - eDMA channel interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ static int dmaisr(int irq, void *dev_id) { int channel = irq - EDMA_INT_CONTROLLER_BASE - EDMA_INT_CHANNEL_BASE; int result = IRQ_HANDLED; - if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) { - spin_lock(devp->dma_interrupt_handlers[channel].lock); - } + if ((devp != NULL) && + (devp->dma_interrupt_handlers[channel].irq_handler)) { + /* call user irq handler */ + if (devp->dma_interrupt_handlers[channel].lock) + spin_lock(devp->dma_interrupt_handlers[channel].lock); + + result = devp->dma_interrupt_handlers[channel].irq_handler( + channel, devp->dma_interrupt_handlers[channel].arg); - if (devp!=NULL && devp->dma_interrupt_handlers[channel].irq_handler) { - result = devp->dma_interrupt_handlers[channel].irq_handler(channel, - devp->dma_interrupt_handlers[channel].dev); + if (devp->dma_interrupt_handlers[channel].lock) + spin_unlock(devp->dma_interrupt_handlers[channel].lock); } else { + /* no irq handler so just ack it */ confirm_edma_interrupt_handled(channel); - printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", channel); - } - - if (devp!=NULL && devp->dma_interrupt_handlers[channel].lock) { - spin_unlock(devp->dma_interrupt_handlers[channel].lock); + printk(EDMA_DRIVER_NAME ": No handler for DMA channel %d\n", + channel); } return result; } -/* eDMA error interrupt handler */ +/** + * dma_error_isr - eDMA error interrupt handler + * @irq: interrupt number + * @dev_id: argument + */ static int dma_error_isr(int irq, void* dev_id) { u16 err; int i; err = MCF_EDMA_ERR; - for (i=0;i<EDMA_CHANNELS;i++) { + for (i=0; i<EDMA_CHANNELS; i++) { if (err & (1<<i)) { - if (devp!=NULL && devp->dma_interrupt_handlers[i].error_handler) { - devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].dev); - } else { + if (devp!=NULL && devp->dma_interrupt_handlers[i].error_handler) + devp->dma_interrupt_handlers[i].error_handler(i, devp->dma_interrupt_handlers[i].arg); + else printk(KERN_WARNING EDMA_DRIVER_NAME ": DMA error on channel %d\n", i); - } } } @@ -97,11 +112,26 @@ static int dma_error_isr(int irq, void* return IRQ_HANDLED; } -/* sets channel parameters */ +/** + * set_edma_params - Set transfer control descriptor (TCD) + * @channel: channel number + * @source: source address + * @dest: destination address + * @attr: attributes + * @soff: source offset + * @nbytes: number of bytes to be transfered in minor loop + * @slast: last source address adjustment + * @citer: major loop count + * @biter: beginning minor loop count + * @doff: destination offset + * @dlast_sga: last destination address adjustment + * @major_int: generate interrupt after each major loop + * @disable_req: disable DMA request after major loop + */ void set_edma_params(int channel, u32 source, u32 dest, - u32 attr, u32 soff, u32 nbytes, u32 slast, - u32 citer, u32 biter, u32 doff, u32 dlast_sga, - int major_int, int disable_req) + u32 attr, u32 soff, u32 nbytes, u32 slast, + u32 citer, u32 biter, u32 doff, u32 dlast_sga, + int major_int, int disable_req) { if (channel<0 || channel>EDMA_CHANNELS) @@ -117,45 +147,56 @@ void set_edma_params(int channel, u32 so MCF_EDMA_TCD_BITER(channel)=MCF_EDMA_TCD_BITER_BITER(biter); MCF_EDMA_TCD_DOFF(channel) = MCF_EDMA_TCD_DOFF_DOFF(doff); MCF_EDMA_TCD_DLAST_SGA(channel) = MCF_EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga); + /* interrupt at the end of major loop */ - if (major_int) { + if (major_int) MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_INT_MAJOR; - } else { + else MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_INT_MAJOR; - } + /* disable request at the end of major loop of transfer or not*/ - if (disable_req) { + if (disable_req) MCF_EDMA_TCD_CSR(channel) |= MCF_EDMA_TCD_CSR_D_REQ; - } else { + else MCF_EDMA_TCD_CSR(channel) &= ~MCF_EDMA_TCD_CSR_D_REQ; - } - } EXPORT_SYMBOL(set_edma_params); -/* init eDMA controller */ +/** + * init_edma - Initialize the eDMA controller + */ void init_edma(void) { MCF_EDMA_CR = 0; } EXPORT_SYMBOL(init_edma); -/* request eDMA channel */ +/** + * request_edma_channel - Request an eDMA channel + * @channel: channel number + * @handler: dma handler + * @error_handler: dma error handler + * @arg: argument to pass back + * @lock: optional spinlock to hold over interrupt + * @device_id: device id + * + * Returns 0 if success or a negative value if failure + */ int request_edma_channel(int channel, - edma_irq_handler handler, - edma_error_handler error_handler, - void* dev, - spinlock_t *lock, - const char* device_id ) + edma_irq_handler handler, + edma_error_handler error_handler, + void *arg, + spinlock_t *lock, + const char *device_id ) { if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { - if (devp->dma_interrupt_handlers[channel].allocated) { + if (devp->dma_interrupt_handlers[channel].allocated) return -EBUSY; - } + devp->dma_interrupt_handlers[channel].allocated = 1; devp->dma_interrupt_handlers[channel].irq_handler = handler; devp->dma_interrupt_handlers[channel].error_handler = error_handler; - devp->dma_interrupt_handlers[channel].dev = dev; + devp->dma_interrupt_handlers[channel].arg = arg; devp->dma_interrupt_handlers[channel].lock = lock; devp->dma_interrupt_handlers[channel].device_id = device_id; return 0; @@ -164,16 +205,22 @@ int request_edma_channel(int channel, } EXPORT_SYMBOL(request_edma_channel); -/* free eDMA channel */ -int free_edma_channel(int channel, void* dev) +/** + * free_edma_channel - Free the edma channel + * @channel: channel number + * @arg: argument created with + * + * Returns 0 if success or a negative value if failure + */ +int free_edma_channel(int channel, void *arg) { if (devp!=NULL && channel>=0 && channel<=EDMA_CHANNELS) { if (devp->dma_interrupt_handlers[channel].allocated) { - if (devp->dma_interrupt_handlers[channel].dev != dev) { + if (devp->dma_interrupt_handlers[channel].arg != arg) return -EBUSY; - } + devp->dma_interrupt_handlers[channel].allocated = 0; - devp->dma_interrupt_handlers[channel].dev = NULL; + devp->dma_interrupt_handlers[channel].arg = NULL; devp->dma_interrupt_handlers[channel].irq_handler = NULL; devp->dma_interrupt_handlers[channel].error_handler = NULL; devp->dma_interrupt_handlers[channel].lock = NULL; @@ -184,7 +231,9 @@ int free_edma_channel(int channel, void* } EXPORT_SYMBOL(free_edma_channel); -/* clean-up device driver allocated resources */ +/** + * coldfire_edma_cleanup - cleanup driver allocated resources + */ static void coldfire_edma_cleanup(void) { dev_t devno; @@ -192,13 +241,10 @@ static void coldfire_edma_cleanup(void) /* free interrupts/memory */ if (devp) { - for (i=0;i<EDMA_CHANNELS;i++) - { - MCF_INTC0_SIMR = EDMA_INT_CHANNEL_BASE+i; - free_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i, devp); - } - MCF_INTC0_SIMR = EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS; - free_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+EDMA_CHANNELS, devp); + for (i=0; i<EDMA_CHANNELS; i++) + free_irq(EDMA_INT_BASE+i, devp); + + free_irq(EDMA_INT_BASE+EDMA_INT_ERR, devp); cdev_del(&devp->cdev); kfree(devp); } @@ -209,30 +255,42 @@ static void coldfire_edma_cleanup(void) } #ifdef CONFIG_PROC_FS -/* proc file system support */ +/* + * proc file system support + */ #define FREE_CHANNEL "free" #define DEVICE_UNKNOWN "device unknown" +/** + * proc_edma_show - print out proc info + * @m: seq_file + * @v: + */ static int proc_edma_show(struct seq_file *m, void *v) { int i; - if (devp==NULL) return 0; + if (devp == NULL) + return 0; for (i = 0 ; i < EDMA_CHANNELS ; i++) { if (devp->dma_interrupt_handlers[i].allocated) { if (devp->dma_interrupt_handlers[i].device_id) - seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id); + seq_printf(m, "%2d: %s\n", i, devp->dma_interrupt_handlers[i].device_id); else seq_printf(m, "%2d: %s\n", i, DEVICE_UNKNOWN); - } else { + } else seq_printf(m, "%2d: %s\n", i, FREE_CHANNEL); - } } return 0; } +/** + * proc_edma_open - open the proc file + * @inode: inode ptr + * @file: file ptr + */ static int proc_edma_open(struct inode *inode, struct file *file) { return single_open(file, proc_edma_show, NULL); @@ -245,6 +303,9 @@ static const struct file_operations proc .release = single_release, }; +/** + * proc_edma_init - initialize proc filesystem + */ static int __init proc_edma_init(void) { struct proc_dir_entry *e; @@ -258,7 +319,9 @@ static int __init proc_edma_init(void) #endif -/* initializes device driver */ +/** + * coldfire_edma_init - eDMA module init + */ static int __init coldfire_edma_init(void) { dev_t dev; @@ -267,8 +330,9 @@ static int __init coldfire_edma_init(voi /* allocate free major number */ result = alloc_chrdev_region(&dev, DMA_DEV_MINOR, 1, EDMA_DRIVER_NAME); - if (result<0) { - printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", result); + if (result < 0) { + printk(KERN_WARNING EDMA_DRIVER_NAME": can't get major %d\n", + result); return result; } coldfire_dma_major = MAJOR(dev); @@ -280,71 +344,68 @@ static int __init coldfire_edma_init(voi goto fail; } - /* init handlers (no handlers for beggining) */ - for (i=0;i<EDMA_CHANNELS;i++) { + /* init handlers (no handlers for beginning) */ + for (i = 0; i < EDMA_CHANNELS; i++) { devp->dma_interrupt_handlers[i].irq_handler = NULL; devp->dma_interrupt_handlers[i].error_handler = NULL; - devp->dma_interrupt_handlers[i].dev = NULL; + devp->dma_interrupt_handlers[i].arg = NULL; devp->dma_interrupt_handlers[i].allocated = 0; devp->dma_interrupt_handlers[i].lock = NULL; devp->dma_interrupt_handlers[i].device_id = NULL; } - /* register char device */ + /* register char device */ cdev_init(&devp->cdev, &coldfire_edma_fops); devp->cdev.owner = THIS_MODULE; devp->cdev.ops = &coldfire_edma_fops; result = cdev_add(&devp->cdev, dev, 1); if (result) { - printk(KERN_NOTICE EDMA_DRIVER_NAME": Error %d adding coldfire-dma device\n", result); + printk(KERN_NOTICE EDMA_DRIVER_NAME + ": Error %d adding coldfire-dma device\n", result); result = -ENODEV; goto fail; } /* request/enable irq for each eDMA channel */ - for (i=0;i<EDMA_CHANNELS;i++) - { - result = request_irq(EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i, - dmaisr, SA_INTERRUPT, EDMA_DRIVER_NAME, devp); + for (i = 0; i < EDMA_CHANNELS;i++) { + result = request_irq(EDMA_INT_BASE + i, + dmaisr, IRQF_DISABLED, + EDMA_DRIVER_NAME, devp); if (result) { - printk(KERN_WARNING EDMA_DRIVER_NAME": Cannot request irq %d\n", - EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+i); + printk(KERN_WARNING EDMA_DRIVER_NAME + ": Cannot request irq %d\n", + (EDMA_INT_BASE + EDMA_INT_ERR+i)); result = -EBUSY; goto fail; } - - MCF_INTC0_ICR(EDMA_INT_CHANNEL_BASE+i) = EDMA_IRQ_LEVEL; - MCF_INTC0_CIMR = EDMA_INT_CHANNEL_BASE+i; - } - /* request error interrupt */ - result = request_irq(EDMA_INT_CHANNEL_BASE + EDMA_INT_CONTROLLER_BASE + EDMA_CHANNELS, - dma_error_isr, SA_INTERRUPT, EDMA_DRIVER_NAME, devp); + /* request error interrupt */ + result = request_irq(EDMA_INT_BASE + EDMA_INT_ERR, + dma_error_isr, IRQF_DISABLED, + EDMA_DRIVER_NAME, devp); if (result) { - printk(KERN_WARNING EDMA_DRIVER_NAME": Cannot request irq %d\n", - EDMA_INT_CHANNEL_BASE+EDMA_INT_CONTROLLER_BASE+EDMA_CHANNELS); + printk(KERN_WARNING EDMA_DRIVER_NAME + ": Cannot request irq %d\n", + (EDMA_INT_BASE + EDMA_INT_ERR)); result = -EBUSY; goto fail; } - /* enable error interrupt in interrupt controller */ - MCF_INTC0_ICR(EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS) = EDMA_IRQ_LEVEL; - MCF_INTC0_CIMR = EDMA_INT_CHANNEL_BASE+EDMA_CHANNELS; - #ifdef CONFIG_PROC_FS proc_edma_init(); #endif printk(EDMA_DRIVER_NAME ": initialized successfully\n"); - return 0; fail: coldfire_edma_cleanup(); return result; - } +/** + * coldfire_edma_exit - eDMA module exit + */ static void __exit coldfire_edma_exit(void) { coldfire_edma_cleanup(); @@ -354,5 +415,5 @@ module_init(coldfire_edma_init); module_exit(coldfire_edma_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Yaroslav Vinogradov, Freescale Inc."); -MODULE_DESCRIPTION("eDMA library for Coldfire 5445x"); +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("eDMA library for Coldfire M5445x"); --- a/include/asm-m68k/coldfire_edma.h +++ b/include/asm-m68k/coldfire_edma.h @@ -20,11 +20,14 @@ #define EDMA_DRIVER_NAME "ColdFire-eDMA" #define DMA_DEV_MINOR 1 +#ifdef CONFIG_M54455 #define EDMA_INT_CHANNEL_BASE 8 #define EDMA_INT_CONTROLLER_BASE 64 +#define EDMA_INT_BASE (EDMA_INT_CHANNEL_BASE + \ + EDMA_INT_CONTROLLER_BASE) #define EDMA_CHANNELS 16 - -#define EDMA_IRQ_LEVEL 5 +#define EDMA_INT_ERR 16 /* edma error interrupt */ +#endif /* CONFIG_M54455 */ typedef irqreturn_t (*edma_irq_handler)(int, void *); typedef void (*edma_error_handler)(int, void *); @@ -38,7 +41,7 @@ typedef void (*edma_error_handler)(int, * nbytes - number of bytes to be transfered in minor loop * slast - last source address adjustment * citer - major loop count - * biter - beggining minor loop count + * biter - begining minor loop count * doff - destination offset * dlast_sga - last destination address adjustment * major_int - generate interrupt after each major loop --- a/include/asm-m68k/mcf5445x_edma.h +++ b/include/asm-m68k/mcf5445x_edma.h @@ -11,11 +11,27 @@ #ifndef __MCF5445X_EDMA_H__ #define __MCF5445X_EDMA_H__ -/********************************************************************* -* -* Enhanced DMA (EDMA) -* -*********************************************************************/ +/* + * Enhanced DMA (EDMA) + */ + +/* Channels */ +#define MCF_EDMA_CHAN_DREQ0 0 /* External DMA request 0 */ +#define MCF_EDMA_CHAN_DREQ1 1 /* External DMA request 1 */ +#define MCF_EDMA_CHAN_UART0_RX 2 /* UART0 Receive */ +#define MCF_EDMA_CHAN_UART0_TX 3 /* UART0 Transmit */ +#define MCF_EDMA_CHAN_UART1_RX 4 /* UART1 Receive */ +#define MCF_EDMA_CHAN_UART1_TX 5 /* UART1 Transmit */ +#define MCF_EDMA_CHAN_UART2_RX 6 /* UART2 Receive */ +#define MCF_EDMA_CHAN_UART2_TX 7 /* UART2 Transmit */ +#define MCF_EDMA_CHAN_TIMER0 8 /* Timer 0 / SSI0 Rx */ +#define MCF_EDMA_CHAN_TIMER1 9 /* Timer 1 / SSI1 Rx */ +#define MCF_EDMA_CHAN_TIMER2 10 /* Timer 2 / SSI0 Tx */ +#define MCF_EDMA_CHAN_TIMER3 11 /* Timer 3 / SSI1 Tx */ +#define MCF_EDMA_CHAN_DSPI_RX 12 /* DSPI Receive */ +#define MCF_EDMA_CHAN_DSPI_TX 13 /* DSPI Transmit */ +#define MCF_EDMA_CHAN_ATA_RX 14 /* ATA Receive */ +#define MCF_EDMA_CHAN_ATA_TX 15 /* ATA Transmit */ /* Register read/write macros */ #define MCF_EDMA_CR MCF_REG32(0xFC044000) @@ -1453,6 +1469,4 @@ #define MCF_EDMA_TCD15_CSR_LINKCH(x) (((x)&0x003F)<<8) #define MCF_EDMA_TCD15_CSR_BWC(x) (((x)&0x0003)<<14) -/********************************************************************/ - #endif /* __MCF5445X_EDMA_H__ */