diff options
Diffstat (limited to 'target/linux/coldfire/patches/032-m5445x_edma_update.patch')
-rw-r--r-- | target/linux/coldfire/patches/032-m5445x_edma_update.patch | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/target/linux/coldfire/patches/032-m5445x_edma_update.patch b/target/linux/coldfire/patches/032-m5445x_edma_update.patch new file mode 100644 index 000000000..17f2becbd --- /dev/null +++ b/target/linux/coldfire/patches/032-m5445x_edma_update.patch @@ -0,0 +1,553 @@ +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__ */ |