Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ARM] 3444/1: i.MX: Scatter-gather DMA emulation for i.MX/MX1

Patch from Pavel Pisa

This patch contains simplified set of changes to add scatter-gather
emulation capability into MX1 DMA support. The result should
be still usable for next combination of DMA transfers
Statter-Gather/linear/2D/FIFO to linear/2D/FIFO and
linear/2D/FIFO to Statter-Gather/2D/FIFO
The patch corrects channel priority allocation to be compatible
with MX1 hardware implementation.
Previous code has not been adapted from its PXA original.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Acked-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Pavel Pisa and committed by
Russell King
999331af 7ba01f97

+546 -82
+453 -68
arch/arm/mach-imx/dma.c
··· 7 7 * it under the terms of the GNU General Public License version 2 as 8 8 * published by the Free Software Foundation. 9 9 * 10 - * 03/03/2004 Sascha Hauer <sascha@saschahauer.de> 10 + * 2004-03-03 Sascha Hauer <sascha@saschahauer.de> 11 11 * initial version heavily inspired by 12 12 * linux/arch/arm/mach-pxa/dma.c 13 + * 14 + * 2005-04-17 Pavel Pisa <pisa@cmp.felk.cvut.cz> 15 + * Changed to support scatter gather DMA 16 + * by taking Russell's code from RiscPC 17 + * 13 18 */ 19 + 20 + #undef DEBUG 14 21 15 22 #include <linux/module.h> 16 23 #include <linux/init.h> ··· 29 22 #include <asm/irq.h> 30 23 #include <asm/hardware.h> 31 24 #include <asm/dma.h> 25 + #include <asm/arch/imx-dma.h> 32 26 33 - static struct dma_channel { 34 - char *name; 35 - void (*irq_handler) (int, void *, struct pt_regs *); 36 - void (*err_handler) (int, void *, struct pt_regs *); 37 - void *data; 38 - } dma_channels[11]; 27 + struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; 39 28 40 - /* set err_handler to NULL to have the standard info-only error handler */ 41 - int 42 - imx_request_dma(char *name, imx_dma_prio prio, 43 - void (*irq_handler) (int, void *, struct pt_regs *), 44 - void (*err_handler) (int, void *, struct pt_regs *), void *data) 29 + /* 30 + * imx_dma_sg_next - prepare next chunk for scatter-gather DMA emulation 31 + * @dma_ch: i.MX DMA channel number 32 + * @lastcount: number of bytes transferred during last transfer 33 + * 34 + * Functions prepares DMA controller for next sg data chunk transfer. 35 + * The @lastcount argument informs function about number of bytes transferred 36 + * during last block. Zero value can be used for @lastcount to setup DMA 37 + * for the first chunk. 38 + */ 39 + static inline int imx_dma_sg_next(imx_dmach_t dma_ch, unsigned int lastcount) 45 40 { 46 - unsigned long flags; 47 - int i, found = 0; 41 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 42 + unsigned int nextcount; 43 + unsigned int nextaddr; 48 44 49 - /* basic sanity checks */ 50 - if (!name || !irq_handler) 51 - return -EINVAL; 45 + if (!imxdma->name) { 46 + printk(KERN_CRIT "%s: called for not allocated channel %d\n", 47 + __FUNCTION__, dma_ch); 48 + return 0; 49 + } 52 50 53 - local_irq_save(flags); 51 + imxdma->resbytes -= lastcount; 54 52 55 - /* try grabbing a DMA channel with the requested priority */ 56 - for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) { 57 - if (!dma_channels[i].name) { 58 - found = 1; 59 - break; 53 + if (!imxdma->sg) { 54 + pr_debug("imxdma%d: no sg data\n", dma_ch); 55 + return 0; 56 + } 57 + 58 + imxdma->sgbc += lastcount; 59 + if ((imxdma->sgbc >= imxdma->sg->length) || !imxdma->resbytes) { 60 + if ((imxdma->sgcount <= 1) || !imxdma->resbytes) { 61 + pr_debug("imxdma%d: sg transfer limit reached\n", 62 + dma_ch); 63 + imxdma->sgcount=0; 64 + imxdma->sg = NULL; 65 + return 0; 66 + } else { 67 + imxdma->sgcount--; 68 + imxdma->sg++; 69 + imxdma->sgbc = 0; 60 70 } 61 71 } 72 + nextcount = imxdma->sg->length - imxdma->sgbc; 73 + nextaddr = imxdma->sg->dma_address + imxdma->sgbc; 62 74 63 - if (!found) { 64 - /* requested prio group is full, try hier priorities */ 65 - for (i = prio - 1; i >= 0; i--) { 66 - if (!dma_channels[i].name) { 67 - found = 1; 68 - break; 69 - } 70 - } 71 - } 75 + if(imxdma->resbytes < nextcount) 76 + nextcount = imxdma->resbytes; 72 77 73 - if (found) { 74 - DIMR &= ~(1 << i); 75 - dma_channels[i].name = name; 76 - dma_channels[i].irq_handler = irq_handler; 77 - dma_channels[i].err_handler = err_handler; 78 - dma_channels[i].data = data; 79 - } else { 80 - printk(KERN_WARNING "No more available DMA channels for %s\n", 81 - name); 82 - i = -ENODEV; 83 - } 78 + if ((imxdma->dma_mode & DMA_MODE_MASK) == DMA_MODE_READ) 79 + DAR(dma_ch) = nextaddr; 80 + else 81 + SAR(dma_ch) = nextaddr; 84 82 85 - local_irq_restore(flags); 86 - return i; 83 + CNTR(dma_ch) = nextcount; 84 + pr_debug("imxdma%d: next sg chunk dst 0x%08x, src 0x%08x, size 0x%08x\n", 85 + dma_ch, DAR(dma_ch), SAR(dma_ch), CNTR(dma_ch)); 86 + 87 + return nextcount; 87 88 } 88 89 89 - void 90 - imx_free_dma(int dma_ch) 90 + /* 91 + * imx_dma_setup_sg_base - scatter-gather DMA emulation 92 + * @dma_ch: i.MX DMA channel number 93 + * @sg: pointer to the scatter-gather list/vector 94 + * @sgcount: scatter-gather list hungs count 95 + * 96 + * Functions sets up i.MX DMA state for emulated scatter-gather transfer 97 + * and sets up channel registers to be ready for the first chunk 98 + */ 99 + static int 100 + imx_dma_setup_sg_base(imx_dmach_t dma_ch, 101 + struct scatterlist *sg, unsigned int sgcount) 102 + { 103 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 104 + 105 + imxdma->sg = sg; 106 + imxdma->sgcount = sgcount; 107 + imxdma->sgbc = 0; 108 + return imx_dma_sg_next(dma_ch, 0); 109 + } 110 + 111 + /** 112 + * imx_dma_setup_single - setup i.MX DMA channel for linear memory to/from device transfer 113 + * @dma_ch: i.MX DMA channel number 114 + * @dma_address: the DMA/physical memory address of the linear data block 115 + * to transfer 116 + * @dma_length: length of the data block in bytes 117 + * @dev_addr: physical device port address 118 + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory 119 + * or %DMA_MODE_WRITE from memory to the device 120 + * 121 + * The function setups DMA channel source and destination addresses for transfer 122 + * specified by provided parameters. The scatter-gather emulation is disabled, 123 + * because linear data block 124 + * form the physical address range is transfered. 125 + * Return value: if incorrect parameters are provided -%EINVAL. 126 + * Zero indicates success. 127 + */ 128 + int 129 + imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, 130 + unsigned int dma_length, unsigned int dev_addr, 131 + dmamode_t dmamode) 132 + { 133 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 134 + 135 + imxdma->sg = NULL; 136 + imxdma->sgcount = 0; 137 + imxdma->dma_mode = dmamode; 138 + imxdma->resbytes = dma_length; 139 + 140 + if (!dma_address) { 141 + printk(KERN_ERR "imxdma%d: imx_dma_setup_single null address\n", 142 + dma_ch); 143 + return -EINVAL; 144 + } 145 + 146 + if (!dma_length) { 147 + printk(KERN_ERR "imxdma%d: imx_dma_setup_single zero length\n", 148 + dma_ch); 149 + return -EINVAL; 150 + } 151 + 152 + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { 153 + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for read\n", 154 + dma_ch, (unsigned int)dma_address, dma_length, 155 + dev_addr); 156 + SAR(dma_ch) = dev_addr; 157 + DAR(dma_ch) = (unsigned int)dma_address; 158 + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { 159 + pr_debug("imxdma%d: mx_dma_setup_single2dev dma_addressg=0x%08x dma_length=%d dev_addr=0x%08x for write\n", 160 + dma_ch, (unsigned int)dma_address, dma_length, 161 + dev_addr); 162 + SAR(dma_ch) = (unsigned int)dma_address; 163 + DAR(dma_ch) = dev_addr; 164 + } else { 165 + printk(KERN_ERR "imxdma%d: imx_dma_setup_single bad dmamode\n", 166 + dma_ch); 167 + return -EINVAL; 168 + } 169 + 170 + CNTR(dma_ch) = dma_length; 171 + 172 + return 0; 173 + } 174 + 175 + /** 176 + * imx_dma_setup_sg - setup i.MX DMA channel SG list to/from device transfer 177 + * @dma_ch: i.MX DMA channel number 178 + * @sg: pointer to the scatter-gather list/vector 179 + * @sgcount: scatter-gather list hungs count 180 + * @dma_length: total length of the transfer request in bytes 181 + * @dev_addr: physical device port address 182 + * @dmamode: DMA transfer mode, %DMA_MODE_READ from the device to the memory 183 + * or %DMA_MODE_WRITE from memory to the device 184 + * 185 + * The function setups DMA channel state and registers to be ready for transfer 186 + * specified by provided parameters. The scatter-gather emulation is set up 187 + * according to the parameters. 188 + * 189 + * The full preparation of the transfer requires setup of more register 190 + * by the caller before imx_dma_enable() can be called. 191 + * 192 + * %BLR(dma_ch) holds transfer burst length in bytes, 0 means 64 bytes 193 + * 194 + * %RSSR(dma_ch) has to be set to the DMA request line source %DMA_REQ_xxx 195 + * 196 + * %CCR(dma_ch) has to specify transfer parameters, the next settings is typical 197 + * for linear or simple scatter-gather transfers if %DMA_MODE_READ is specified 198 + * 199 + * %CCR_DMOD_LINEAR | %CCR_DSIZ_32 | %CCR_SMOD_FIFO | %CCR_SSIZ_x 200 + * 201 + * The typical setup for %DMA_MODE_WRITE is specified by next options combination 202 + * 203 + * %CCR_SMOD_LINEAR | %CCR_SSIZ_32 | %CCR_DMOD_FIFO | %CCR_DSIZ_x 204 + * 205 + * Be carefull there and do not mistakenly mix source and target device 206 + * port sizes constants, they are really different: 207 + * %CCR_SSIZ_8, %CCR_SSIZ_16, %CCR_SSIZ_32, 208 + * %CCR_DSIZ_8, %CCR_DSIZ_16, %CCR_DSIZ_32 209 + * 210 + * Return value: if incorrect parameters are provided -%EINVAL. 211 + * Zero indicates success. 212 + */ 213 + int 214 + imx_dma_setup_sg(imx_dmach_t dma_ch, 215 + struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, 216 + unsigned int dev_addr, dmamode_t dmamode) 217 + { 218 + int res; 219 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 220 + 221 + imxdma->sg = NULL; 222 + imxdma->sgcount = 0; 223 + imxdma->dma_mode = dmamode; 224 + imxdma->resbytes = dma_length; 225 + 226 + if (!sg || !sgcount) { 227 + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg epty sg list\n", 228 + dma_ch); 229 + return -EINVAL; 230 + } 231 + 232 + if (!sg->length) { 233 + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg zero length\n", 234 + dma_ch); 235 + return -EINVAL; 236 + } 237 + 238 + if ((dmamode & DMA_MODE_MASK) == DMA_MODE_READ) { 239 + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for read\n", 240 + dma_ch, sg, sgcount, dma_length, dev_addr); 241 + SAR(dma_ch) = dev_addr; 242 + } else if ((dmamode & DMA_MODE_MASK) == DMA_MODE_WRITE) { 243 + pr_debug("imxdma%d: mx_dma_setup_sg2dev sg=%p sgcount=%d total length=%d dev_addr=0x%08x for write\n", 244 + dma_ch, sg, sgcount, dma_length, dev_addr); 245 + DAR(dma_ch) = dev_addr; 246 + } else { 247 + printk(KERN_ERR "imxdma%d: imx_dma_setup_sg bad dmamode\n", 248 + dma_ch); 249 + return -EINVAL; 250 + } 251 + 252 + res = imx_dma_setup_sg_base(dma_ch, sg, sgcount); 253 + if (res <= 0) { 254 + printk(KERN_ERR "imxdma%d: no sg chunk ready\n", dma_ch); 255 + return -EINVAL; 256 + } 257 + 258 + return 0; 259 + } 260 + 261 + /** 262 + * imx_dma_setup_handlers - setup i.MX DMA channel end and error notification handlers 263 + * @dma_ch: i.MX DMA channel number 264 + * @irq_handler: the pointer to the function called if the transfer 265 + * ends successfully 266 + * @err_handler: the pointer to the function called if the premature 267 + * end caused by error occurs 268 + * @data: user specified value to be passed to the handlers 269 + */ 270 + int 271 + imx_dma_setup_handlers(imx_dmach_t dma_ch, 272 + void (*irq_handler) (int, void *, struct pt_regs *), 273 + void (*err_handler) (int, void *, struct pt_regs *), 274 + void *data) 275 + { 276 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 277 + unsigned long flags; 278 + 279 + if (!imxdma->name) { 280 + printk(KERN_CRIT "%s: called for not allocated channel %d\n", 281 + __FUNCTION__, dma_ch); 282 + return -ENODEV; 283 + } 284 + 285 + local_irq_save(flags); 286 + DISR = (1 << dma_ch); 287 + imxdma->irq_handler = irq_handler; 288 + imxdma->err_handler = err_handler; 289 + imxdma->data = data; 290 + local_irq_restore(flags); 291 + return 0; 292 + } 293 + 294 + /** 295 + * imx_dma_enable - function to start i.MX DMA channel operation 296 + * @dma_ch: i.MX DMA channel number 297 + * 298 + * The channel has to be allocated by driver through imx_dma_request() 299 + * or imx_dma_request_by_prio() function. 300 + * The transfer parameters has to be set to the channel registers through 301 + * call of the imx_dma_setup_single() or imx_dma_setup_sg() function 302 + * and registers %BLR(dma_ch), %RSSR(dma_ch) and %CCR(dma_ch) has to 303 + * be set prior this function call by the channel user. 304 + */ 305 + void imx_dma_enable(imx_dmach_t dma_ch) 306 + { 307 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 308 + unsigned long flags; 309 + 310 + pr_debug("imxdma%d: imx_dma_enable\n", dma_ch); 311 + 312 + if (!imxdma->name) { 313 + printk(KERN_CRIT "%s: called for not allocated channel %d\n", 314 + __FUNCTION__, dma_ch); 315 + return; 316 + } 317 + 318 + local_irq_save(flags); 319 + DISR = (1 << dma_ch); 320 + DIMR &= ~(1 << dma_ch); 321 + CCR(dma_ch) |= CCR_CEN; 322 + local_irq_restore(flags); 323 + } 324 + 325 + /** 326 + * imx_dma_disable - stop, finish i.MX DMA channel operatin 327 + * @dma_ch: i.MX DMA channel number 328 + */ 329 + void imx_dma_disable(imx_dmach_t dma_ch) 91 330 { 92 331 unsigned long flags; 93 332 94 - if (!dma_channels[dma_ch].name) { 333 + pr_debug("imxdma%d: imx_dma_disable\n", dma_ch); 334 + 335 + local_irq_save(flags); 336 + DIMR |= (1 << dma_ch); 337 + CCR(dma_ch) &= ~CCR_CEN; 338 + DISR = (1 << dma_ch); 339 + local_irq_restore(flags); 340 + } 341 + 342 + /** 343 + * imx_dma_request - request/allocate specified channel number 344 + * @dma_ch: i.MX DMA channel number 345 + * @name: the driver/caller own non-%NULL identification 346 + */ 347 + int imx_dma_request(imx_dmach_t dma_ch, const char *name) 348 + { 349 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 350 + unsigned long flags; 351 + 352 + /* basic sanity checks */ 353 + if (!name) 354 + return -EINVAL; 355 + 356 + if (dma_ch >= IMX_DMA_CHANNELS) { 357 + printk(KERN_CRIT "%s: called for non-existed channel %d\n", 358 + __FUNCTION__, dma_ch); 359 + return -EINVAL; 360 + } 361 + 362 + local_irq_save(flags); 363 + if (imxdma->name) { 364 + local_irq_restore(flags); 365 + return -ENODEV; 366 + } 367 + 368 + imxdma->name = name; 369 + imxdma->irq_handler = NULL; 370 + imxdma->err_handler = NULL; 371 + imxdma->data = NULL; 372 + imxdma->sg = NULL; 373 + local_irq_restore(flags); 374 + return 0; 375 + } 376 + 377 + /** 378 + * imx_dma_free - release previously acquired channel 379 + * @dma_ch: i.MX DMA channel number 380 + */ 381 + void imx_dma_free(imx_dmach_t dma_ch) 382 + { 383 + unsigned long flags; 384 + struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch]; 385 + 386 + if (!imxdma->name) { 95 387 printk(KERN_CRIT 96 388 "%s: trying to free channel %d which is already freed\n", 97 389 __FUNCTION__, dma_ch); ··· 398 92 } 399 93 400 94 local_irq_save(flags); 401 - DIMR &= ~(1 << dma_ch); 402 - dma_channels[dma_ch].name = NULL; 95 + /* Disable interrupts */ 96 + DIMR |= (1 << dma_ch); 97 + CCR(dma_ch) &= ~CCR_CEN; 98 + imxdma->name = NULL; 403 99 local_irq_restore(flags); 404 100 } 405 101 406 - static irqreturn_t 407 - dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) 102 + /** 103 + * imx_dma_request_by_prio - find and request some of free channels best suiting requested priority 104 + * @dma_ch: i.MX DMA channel number 105 + * @name: the driver/caller own non-%NULL identification 106 + * @prio: one of the hardware distinguished priority level: 107 + * %DMA_PRIO_HIGH, %DMA_PRIO_MEDIUM, %DMA_PRIO_LOW 108 + * 109 + * This function tries to find free channel in the specified priority group 110 + * if the priority cannot be achieved it tries to look for free channel 111 + * in the higher and then even lower priority groups. 112 + * 113 + * Return value: If there is no free channel to allocate, -%ENODEV is returned. 114 + * Zero value indicates successful channel allocation. 115 + */ 116 + int 117 + imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name, 118 + imx_dma_prio prio) 119 + { 120 + int i; 121 + int best; 122 + 123 + switch (prio) { 124 + case (DMA_PRIO_HIGH): 125 + best = 8; 126 + break; 127 + case (DMA_PRIO_MEDIUM): 128 + best = 4; 129 + break; 130 + case (DMA_PRIO_LOW): 131 + default: 132 + best = 0; 133 + break; 134 + } 135 + 136 + for (i = best; i < IMX_DMA_CHANNELS; i++) { 137 + if (!imx_dma_request(i, name)) { 138 + *pdma_ch = i; 139 + return 0; 140 + } 141 + } 142 + 143 + for (i = best - 1; i >= 0; i--) { 144 + if (!imx_dma_request(i, name)) { 145 + *pdma_ch = i; 146 + return 0; 147 + } 148 + } 149 + 150 + printk(KERN_ERR "%s: no free DMA channel found\n", __FUNCTION__); 151 + 152 + return -ENODEV; 153 + } 154 + 155 + static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs) 408 156 { 409 157 int i, disr = DISR; 410 - struct dma_channel *channel; 158 + struct imx_dma_channel *channel; 411 159 unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR; 412 160 413 161 DISR = disr; 414 - for (i = 0; i < 11; i++) { 415 - channel = &dma_channels[i]; 162 + for (i = 0; i < IMX_DMA_CHANNELS; i++) { 163 + channel = &imx_dma_channels[i]; 416 164 417 - if ( (err_mask & 1<<i) && channel->name && channel->err_handler) { 165 + if ((err_mask & 1 << i) && channel->name 166 + && channel->err_handler) { 418 167 channel->err_handler(i, channel->data, regs); 419 168 continue; 420 169 } 170 + 171 + imx_dma_channels[i].sg = NULL; 421 172 422 173 if (DBTOSR & (1 << i)) { 423 174 printk(KERN_WARNING ··· 504 141 return IRQ_HANDLED; 505 142 } 506 143 507 - static irqreturn_t 508 - dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) 144 + static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) 509 145 { 510 146 int i, disr = DISR; 511 147 148 + pr_debug("imxdma: dma_irq_handler called, disr=0x%08x\n", 149 + disr); 150 + 512 151 DISR = disr; 513 - for (i = 0; i < 11; i++) { 152 + for (i = 0; i < IMX_DMA_CHANNELS; i++) { 514 153 if (disr & (1 << i)) { 515 - struct dma_channel *channel = &dma_channels[i]; 516 - if (channel->name && channel->irq_handler) { 517 - channel->irq_handler(i, channel->data, regs); 154 + struct imx_dma_channel *channel = &imx_dma_channels[i]; 155 + if (channel->name) { 156 + if (imx_dma_sg_next(i, CNTR(i))) { 157 + CCR(i) &= ~CCR_CEN; 158 + mb(); 159 + CCR(i) |= CCR_CEN; 160 + } else { 161 + if (channel->irq_handler) 162 + channel->irq_handler(i, 163 + channel->data, regs); 164 + } 518 165 } else { 519 166 /* 520 167 * IRQ for an unregistered DMA channel: ··· 538 165 return IRQ_HANDLED; 539 166 } 540 167 541 - static int __init 542 - imx_dma_init(void) 168 + static int __init imx_dma_init(void) 543 169 { 544 170 int ret; 171 + int i; 545 172 546 173 /* reset DMA module */ 547 174 DCR = DCR_DRST; ··· 562 189 DCR = DCR_DEN; 563 190 564 191 /* clear all interrupts */ 565 - DISR = 0x3ff; 192 + DISR = (1 << IMX_DMA_CHANNELS) - 1; 566 193 567 194 /* enable interrupts */ 568 - DIMR = 0; 195 + DIMR = (1 << IMX_DMA_CHANNELS) - 1; 196 + 197 + for (i = 0; i < IMX_DMA_CHANNELS; i++) { 198 + imx_dma_channels[i].sg = NULL; 199 + imx_dma_channels[i].dma_num = i; 200 + } 569 201 570 202 return ret; 571 203 } 572 204 573 205 arch_initcall(imx_dma_init); 574 206 575 - EXPORT_SYMBOL(imx_request_dma); 576 - EXPORT_SYMBOL(imx_free_dma); 207 + EXPORT_SYMBOL(imx_dma_setup_single); 208 + EXPORT_SYMBOL(imx_dma_setup_sg); 209 + EXPORT_SYMBOL(imx_dma_setup_handlers); 210 + EXPORT_SYMBOL(imx_dma_enable); 211 + EXPORT_SYMBOL(imx_dma_disable); 212 + EXPORT_SYMBOL(imx_dma_request); 213 + EXPORT_SYMBOL(imx_dma_free); 214 + EXPORT_SYMBOL(imx_dma_request_by_prio); 215 + EXPORT_SYMBOL(imx_dma_channels);
+3 -14
include/asm-arm/arch-imx/dma.h
··· 17 17 * along with this program; if not, write to the Free Software 18 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 19 */ 20 + 20 21 #ifndef __ASM_ARCH_DMA_H 21 22 #define __ASM_ARCH_DMA_H 22 23 23 - /* 24 - * DMA registration 25 - */ 26 - 27 24 typedef enum { 28 25 DMA_PRIO_HIGH = 0, 29 - DMA_PRIO_MEDIUM = 3, 30 - DMA_PRIO_LOW = 6 26 + DMA_PRIO_MEDIUM = 1, 27 + DMA_PRIO_LOW = 2 31 28 } imx_dma_prio; 32 - 33 - int imx_request_dma(char *name, imx_dma_prio prio, 34 - void (*irq_handler) (int, void *, struct pt_regs *), 35 - void (*err_handler) (int, void *, struct pt_regs *), 36 - void *data); 37 - 38 - void imx_free_dma(int dma_ch); 39 - 40 29 41 30 #define DMA_REQ_UART3_T 2 42 31 #define DMA_REQ_UART3_R 3
+90
include/asm-arm/arch-imx/imx-dma.h
··· 1 + /* 2 + * linux/include/asm-arm/imxads/dma.h 3 + * 4 + * Copyright (C) 1997,1998 Russell King 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (at your option) any later version. 10 + * 11 + * This program is distributed in the hope that it will be useful, 12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 + * GNU General Public License for more details. 15 + * 16 + * You should have received a copy of the GNU General Public License 17 + * along with this program; if not, write to the Free Software 18 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 + */ 20 + 21 + #include <asm/dma.h> 22 + 23 + #ifndef __ASM_ARCH_IMX_DMA_H 24 + #define __ASM_ARCH_IMX_DMA_H 25 + 26 + #define IMX_DMA_CHANNELS 11 27 + 28 + /* 29 + * struct imx_dma_channel - i.MX specific DMA extension 30 + * @name: name specified by DMA client 31 + * @irq_handler: client callback for end of transfer 32 + * @err_handler: client callback for error condition 33 + * @data: clients context data for callbacks 34 + * @dma_mode: direction of the transfer %DMA_MODE_READ or %DMA_MODE_WRITE 35 + * @sg: pointer to the actual read/written chunk for scatter-gather emulation 36 + * @sgbc: counter of processed bytes in the actual read/written chunk 37 + * @resbytes: total residual number of bytes to transfer 38 + * (it can be lower or same as sum of SG mapped chunk sizes) 39 + * @sgcount: number of chunks to be read/written 40 + * 41 + * Structure is used for IMX DMA processing. It would be probably good 42 + * @struct dma_struct in the future for external interfacing and use 43 + * @struct imx_dma_channel only as extension to it. 44 + */ 45 + 46 + struct imx_dma_channel { 47 + const char *name; 48 + void (*irq_handler) (int, void *, struct pt_regs *); 49 + void (*err_handler) (int, void *, struct pt_regs *); 50 + void *data; 51 + dmamode_t dma_mode; 52 + struct scatterlist *sg; 53 + unsigned int sgbc; 54 + unsigned int sgcount; 55 + unsigned int resbytes; 56 + int dma_num; 57 + }; 58 + 59 + extern struct imx_dma_channel imx_dma_channels[IMX_DMA_CHANNELS]; 60 + 61 + 62 + /* The type to distinguish channel numbers parameter from ordinal int type */ 63 + typedef int imx_dmach_t; 64 + 65 + int 66 + imx_dma_setup_single(imx_dmach_t dma_ch, dma_addr_t dma_address, 67 + unsigned int dma_length, unsigned int dev_addr, dmamode_t dmamode); 68 + 69 + int 70 + imx_dma_setup_sg(imx_dmach_t dma_ch, 71 + struct scatterlist *sg, unsigned int sgcount, unsigned int dma_length, 72 + unsigned int dev_addr, dmamode_t dmamode); 73 + 74 + int 75 + imx_dma_setup_handlers(imx_dmach_t dma_ch, 76 + void (*irq_handler) (int, void *, struct pt_regs *), 77 + void (*err_handler) (int, void *, struct pt_regs *), void *data); 78 + 79 + void imx_dma_enable(imx_dmach_t dma_ch); 80 + 81 + void imx_dma_disable(imx_dmach_t dma_ch); 82 + 83 + int imx_dma_request(imx_dmach_t dma_ch, const char *name); 84 + 85 + void imx_dma_free(imx_dmach_t dma_ch); 86 + 87 + int imx_dma_request_by_prio(imx_dmach_t *pdma_ch, const char *name, imx_dma_prio prio); 88 + 89 + 90 + #endif /* _ASM_ARCH_IMX_DMA_H */