1/* 2 * arch/arm/mach-sa1100/dma.c 3 * 4 * Support functions for the SA11x0 internal DMA channels. 5 * 6 * Copyright (C) 2000, 2001 by Nicolas Pitre 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11 */ 12 13#include <linux/module.h> 14#include <linux/interrupt.h> 15#include <linux/init.h> 16#include <linux/spinlock.h> 17#include <linux/errno.h> 18 19#include <asm/system.h> 20#include <asm/irq.h> 21#include <asm/hardware.h> 22#include <asm/dma.h> 23 24 25#undef DEBUG 26#ifdef DEBUG 27#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg ) 28#else 29#define DPRINTK( x... ) 30#endif 31 32 33typedef struct { 34 const char *device_id; /* device name */ 35 u_long device; /* this channel device, 0 if unused*/ 36 dma_callback_t callback; /* to call when DMA completes */ 37 void *data; /* ... with private data ptr */ 38} sa1100_dma_t; 39 40static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS]; 41 42static spinlock_t dma_list_lock; 43 44 45static irqreturn_t dma_irq_handler(int irq, void *dev_id) 46{ 47 dma_regs_t *dma_regs = dev_id; 48 sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7); 49 int status = dma_regs->RdDCSR; 50 51 if (status & (DCSR_ERROR)) { 52 printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id); 53 dma_regs->ClrDCSR = DCSR_ERROR; 54 } 55 56 dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB); 57 if (dma->callback) { 58 if (status & DCSR_DONEA) 59 dma->callback(dma->data); 60 if (status & DCSR_DONEB) 61 dma->callback(dma->data); 62 } 63 return IRQ_HANDLED; 64} 65 66 67/** 68 * sa1100_request_dma - allocate one of the SA11x0's DMA chanels 69 * @device: The SA11x0 peripheral targeted by this request 70 * @device_id: An ascii name for the claiming device 71 * @callback: Function to be called when the DMA completes 72 * @data: A cookie passed back to the callback function 73 * @dma_regs: Pointer to the location of the allocated channel's identifier 74 * 75 * This function will search for a free DMA channel and returns the 76 * address of the hardware registers for that channel as the channel 77 * identifier. This identifier is written to the location pointed by 78 * @dma_regs. The list of possible values for @device are listed into 79 * linux/include/asm-arm/arch-sa1100/dma.h as a dma_device_t enum. 80 * 81 * Note that reading from a port and writing to the same port are 82 * actually considered as two different streams requiring separate 83 * DMA registrations. 84 * 85 * The @callback function is called from interrupt context when one 86 * of the two possible DMA buffers in flight has terminated. That 87 * function has to be small and efficient while posponing more complex 88 * processing to a lower priority execution context. 89 * 90 * If no channels are available, or if the desired @device is already in 91 * use by another DMA channel, then an error code is returned. This 92 * function must be called before any other DMA calls. 93 **/ 94 95int sa1100_request_dma (dma_device_t device, const char *device_id, 96 dma_callback_t callback, void *data, 97 dma_regs_t **dma_regs) 98{ 99 sa1100_dma_t *dma = NULL; 100 dma_regs_t *regs; 101 int i, err; 102 103 *dma_regs = NULL; 104 105 err = 0; 106 spin_lock(&dma_list_lock); 107 for (i = 0; i < SA1100_DMA_CHANNELS; i++) { 108 if (dma_chan[i].device == device) { 109 err = -EBUSY; 110 break; 111 } else if (!dma_chan[i].device && !dma) { 112 dma = &dma_chan[i]; 113 } 114 } 115 if (!err) { 116 if (dma) 117 dma->device = device; 118 else 119 err = -ENOSR; 120 } 121 spin_unlock(&dma_list_lock); 122 if (err) 123 return err; 124 125 i = dma - dma_chan; 126 regs = (dma_regs_t *)&DDAR(i); 127 err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED, 128 device_id, regs); 129 if (err) { 130 printk(KERN_ERR 131 "%s: unable to request IRQ %d for %s\n", 132 __FUNCTION__, IRQ_DMA0 + i, device_id); 133 dma->device = 0; 134 return err; 135 } 136 137 *dma_regs = regs; 138 dma->device_id = device_id; 139 dma->callback = callback; 140 dma->data = data; 141 142 regs->ClrDCSR = 143 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | 144 DCSR_IE | DCSR_ERROR | DCSR_RUN); 145 regs->DDAR = device; 146 147 return 0; 148} 149 150 151/** 152 * sa1100_free_dma - free a SA11x0 DMA channel 153 * @regs: identifier for the channel to free 154 * 155 * This clears all activities on a given DMA channel and releases it 156 * for future requests. The @regs identifier is provided by a 157 * successful call to sa1100_request_dma(). 158 **/ 159 160void sa1100_free_dma(dma_regs_t *regs) 161{ 162 int i; 163 164 for (i = 0; i < SA1100_DMA_CHANNELS; i++) 165 if (regs == (dma_regs_t *)&DDAR(i)) 166 break; 167 if (i >= SA1100_DMA_CHANNELS) { 168 printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__); 169 return; 170 } 171 172 if (!dma_chan[i].device) { 173 printk(KERN_ERR "%s: Trying to free free DMA\n", __FUNCTION__); 174 return; 175 } 176 177 regs->ClrDCSR = 178 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | 179 DCSR_IE | DCSR_ERROR | DCSR_RUN); 180 free_irq(IRQ_DMA0 + i, regs); 181 dma_chan[i].device = 0; 182} 183 184 185/** 186 * sa1100_start_dma - submit a data buffer for DMA 187 * @regs: identifier for the channel to use 188 * @dma_ptr: buffer physical (or bus) start address 189 * @size: buffer size 190 * 191 * This function hands the given data buffer to the hardware for DMA 192 * access. If another buffer is already in flight then this buffer 193 * will be queued so the DMA engine will switch to it automatically 194 * when the previous one is done. The DMA engine is actually toggling 195 * between two buffers so at most 2 successful calls can be made before 196 * one of them terminates and the callback function is called. 197 * 198 * The @regs identifier is provided by a successful call to 199 * sa1100_request_dma(). 200 * 201 * The @size must not be larger than %MAX_DMA_SIZE. If a given buffer 202 * is larger than that then it's the caller's responsibility to split 203 * it into smaller chunks and submit them separately. If this is the 204 * case then a @size of %CUT_DMA_SIZE is recommended to avoid ending 205 * up with too small chunks. The callback function can be used to chain 206 * submissions of buffer chunks. 207 * 208 * Error return values: 209 * %-EOVERFLOW: Given buffer size is too big. 210 * %-EBUSY: Both DMA buffers are already in use. 211 * %-EAGAIN: Both buffers were busy but one of them just completed 212 * but the interrupt handler has to execute first. 213 * 214 * This function returs 0 on success. 215 **/ 216 217int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size) 218{ 219 unsigned long flags; 220 u_long status; 221 int ret; 222 223 if (dma_ptr & 3) 224 printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n", 225 (unsigned long)dma_ptr); 226 227 if (size > MAX_DMA_SIZE) 228 return -EOVERFLOW; 229 230 local_irq_save(flags); 231 status = regs->RdDCSR; 232 233 /* If both DMA buffers are started, there's nothing else we can do. */ 234 if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) { 235 DPRINTK("start: st %#x busy\n", status); 236 ret = -EBUSY; 237 goto out; 238 } 239 240 if (((status & DCSR_BIU) && (status & DCSR_STRTB)) || 241 (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) { 242 if (status & DCSR_DONEA) { 243 /* give a chance for the interrupt to be processed */ 244 ret = -EAGAIN; 245 goto out; 246 } 247 regs->DBSA = dma_ptr; 248 regs->DBTA = size; 249 regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN; 250 DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size); 251 } else { 252 if (status & DCSR_DONEB) { 253 /* give a chance for the interrupt to be processed */ 254 ret = -EAGAIN; 255 goto out; 256 } 257 regs->DBSB = dma_ptr; 258 regs->DBTB = size; 259 regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN; 260 DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size); 261 } 262 ret = 0; 263 264out: 265 local_irq_restore(flags); 266 return ret; 267} 268 269 270/** 271 * sa1100_get_dma_pos - return current DMA position 272 * @regs: identifier for the channel to use 273 * 274 * This function returns the current physical (or bus) address for the 275 * given DMA channel. If the channel is running i.e. not in a stopped 276 * state then the caller must disable interrupts prior calling this 277 * function and process the returned value before re-enabling them to 278 * prevent races with the completion interrupt handler and the callback 279 * function. The validation of the returned value is the caller's 280 * responsibility as well -- the hardware seems to return out of range 281 * values when the DMA engine completes a buffer. 282 * 283 * The @regs identifier is provided by a successful call to 284 * sa1100_request_dma(). 285 **/ 286 287dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs) 288{ 289 int status; 290 291 /* 292 * We must determine whether buffer A or B is active. 293 * Two possibilities: either we are in the middle of 294 * a buffer, or the DMA controller just switched to the 295 * next toggle but the interrupt hasn't been serviced yet. 296 * The former case is straight forward. In the later case, 297 * we'll do like if DMA is just at the end of the previous 298 * toggle since all registers haven't been reset yet. 299 * This goes around the edge case and since we're always 300 * a little behind anyways it shouldn't make a big difference. 301 * If DMA has been stopped prior calling this then the 302 * position is exact. 303 */ 304 status = regs->RdDCSR; 305 if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) || 306 ( (status & DCSR_BIU) && !(status & DCSR_STRTB))) 307 return regs->DBSA; 308 else 309 return regs->DBSB; 310} 311 312 313/** 314 * sa1100_reset_dma - reset a DMA channel 315 * @regs: identifier for the channel to use 316 * 317 * This function resets and reconfigure the given DMA channel. This is 318 * particularly useful after a sleep/wakeup event. 319 * 320 * The @regs identifier is provided by a successful call to 321 * sa1100_request_dma(). 322 **/ 323 324void sa1100_reset_dma(dma_regs_t *regs) 325{ 326 int i; 327 328 for (i = 0; i < SA1100_DMA_CHANNELS; i++) 329 if (regs == (dma_regs_t *)&DDAR(i)) 330 break; 331 if (i >= SA1100_DMA_CHANNELS) { 332 printk(KERN_ERR "%s: bad DMA identifier\n", __FUNCTION__); 333 return; 334 } 335 336 regs->ClrDCSR = 337 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB | 338 DCSR_IE | DCSR_ERROR | DCSR_RUN); 339 regs->DDAR = dma_chan[i].device; 340} 341 342 343EXPORT_SYMBOL(sa1100_request_dma); 344EXPORT_SYMBOL(sa1100_free_dma); 345EXPORT_SYMBOL(sa1100_start_dma); 346EXPORT_SYMBOL(sa1100_get_dma_pos); 347EXPORT_SYMBOL(sa1100_reset_dma); 348