[coldfire]: 2.6.31 support (WiP)
[openwrt.git] / target / linux / coldfire / files-2.6.31 / arch / m68k / coldfire / m547x / dma.c
1 /*
2 * arch/m68k/coldfire/m547x/dma.c
3 *
4 * Coldfire M547x/M548x DMA
5 *
6 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Kurt Mahan <kmahan@freescale.com>
8 * Shrek Wu b16972@freescale.com
9 *
10 * This code is based on patches from the Freescale M547x_8x BSP
11 * release mcf547x_8x-20070107-ltib.iso
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 */
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
29 #include <linux/mm.h>
30 #include <linux/init.h>
31 #include <linux/interrupt.h>
32 #include <asm/io.h>
33 #include <asm/irq.h>
34 #include <asm/dma.h>
35 #include <asm/coldfire.h>
36 #include <asm/m5485sram.h>
37 #include <asm/mcfsim.h>
38 #include <asm/MCD_dma.h>
39
40 /*
41 * This global keeps track of which initiators have been
42 * used of the available assignments. Initiators 0-15 are
43 * hardwired. Initiators 16-31 are multiplexed and controlled
44 * via the Initiatior Mux Control Registe (IMCR). The
45 * assigned requestor is stored with the associated initiator
46 * number.
47 */
48 static int used_reqs[32] = {
49 DMA_ALWAYS, DMA_DSPI_RX, DMA_DSPI_TX, DMA_DREQ0,
50 DMA_PSC0_RX, DMA_PSC0_TX, DMA_USBEP0, DMA_USBEP1,
51 DMA_USBEP2, DMA_USBEP3, DMA_PCI_TX, DMA_PCI_RX,
52 DMA_PSC1_RX, DMA_PSC1_TX, DMA_I2C_RX, DMA_I2C_TX,
53 0, 0, 0, 0,
54 0, 0, 0, 0,
55 0, 0, 0, 0,
56 0, 0, 0, 0
57 };
58
59 /*
60 * This global keeps track of which channels have been assigned
61 * to tasks. This methology assumes that no single initiator
62 * will be tied to more than one task/channel
63 */
64 static char used_channel[16] = {
65 -1, -1, -1, -1, -1, -1, -1, -1,
66 -1, -1, -1, -1, -1, -1, -1, -1
67 };
68
69 unsigned int connected_channel[16] = {
70 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0
72 };
73
74 /**
75 * dma_set_initiator - enable initiator
76 * @initiator: initiator identifier
77 *
78 * Returns 0 of successful, non-zero otherwise
79 *
80 * Attempt to enable the provided Initiator in the Initiator
81 * Mux Control Register.
82 */
83 int dma_set_initiator(int initiator)
84 {
85 switch (initiator) {
86 case DMA_ALWAYS:
87 case DMA_DSPI_RX:
88 case DMA_DSPI_TX:
89 case DMA_DREQ0:
90 case DMA_PSC0_RX:
91 case DMA_PSC0_TX:
92 case DMA_USBEP0:
93 case DMA_USBEP1:
94 case DMA_USBEP2:
95 case DMA_USBEP3:
96 case DMA_PCI_TX:
97 case DMA_PCI_RX:
98 case DMA_PSC1_RX:
99 case DMA_PSC1_TX:
100 case DMA_I2C_RX:
101 case DMA_I2C_TX:
102 /*
103 * These initiators are always active
104 */
105 break;
106
107 case DMA_FEC0_RX:
108 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC16(3))
109 | MCF_DMA_IMCR_SRC16_FEC0RX;
110 used_reqs[16] = DMA_FEC0_RX;
111 break;
112
113 case DMA_FEC0_TX:
114 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC17(3))
115 | MCF_DMA_IMCR_SRC17_FEC0TX;
116 used_reqs[17] = DMA_FEC0_TX;
117 break;
118
119 case DMA_FEC1_RX:
120 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC20(3))
121 | MCF_DMA_IMCR_SRC20_FEC1RX;
122 used_reqs[20] = DMA_FEC1_RX;
123 break;
124
125 case DMA_FEC1_TX:
126 if (used_reqs[21] == 0) {
127 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC21(3))
128 | MCF_DMA_IMCR_SRC21_FEC1TX;
129 used_reqs[21] = DMA_FEC1_TX;
130 } else if (used_reqs[25] == 0) {
131 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC25(3))
132 | MCF_DMA_IMCR_SRC25_FEC1TX;
133 used_reqs[25] = DMA_FEC1_TX;
134 } else if (used_reqs[31] == 0) {
135 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3))
136 | MCF_DMA_IMCR_SRC31_FEC1TX;
137 used_reqs[31] = DMA_FEC1_TX;
138 } else /* No empty slots */
139 return 1;
140 break;
141
142 case DMA_DREQ1:
143 if (used_reqs[29] == 0) {
144 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3))
145 | MCF_DMA_IMCR_SRC29_DREQ1;
146 used_reqs[29] = DMA_DREQ1;
147 } else if (used_reqs[21] == 0) {
148 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC21(3))
149 | MCF_DMA_IMCR_SRC21_DREQ1;
150 used_reqs[21] = DMA_DREQ1;
151 } else /* No empty slots */
152 return 1;
153 break;
154
155 case DMA_CTM0:
156 if (used_reqs[24] == 0) {
157 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC24(3))
158 | MCF_DMA_IMCR_SRC24_CTM0;
159 used_reqs[24] = DMA_CTM0;
160 } else /* No empty slots */
161 return 1;
162 break;
163
164 case DMA_CTM1:
165 if (used_reqs[25] == 0) {
166 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC25(3))
167 | MCF_DMA_IMCR_SRC25_CTM1;
168 used_reqs[25] = DMA_CTM1;
169 } else /* No empty slots */
170 return 1;
171 break;
172
173 case DMA_CTM2:
174 if (used_reqs[26] == 0) {
175 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC26(3))
176 | MCF_DMA_IMCR_SRC26_CTM2;
177 used_reqs[26] = DMA_CTM2;
178 } else /* No empty slots */
179 return 1;
180 break;
181
182 case DMA_CTM3:
183 if (used_reqs[27] == 0) {
184 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC27(3))
185 | MCF_DMA_IMCR_SRC27_CTM3;
186 used_reqs[27] = DMA_CTM3;
187 } else /* No empty slots */
188 return 1;
189 break;
190
191 case DMA_CTM4:
192 if (used_reqs[28] == 0) {
193 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3))
194 | MCF_DMA_IMCR_SRC28_CTM4;
195 used_reqs[28] = DMA_CTM4;
196 } else /* No empty slots */
197 return 1;
198 break;
199
200 case DMA_CTM5:
201 if (used_reqs[29] == 0) {
202 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3))
203 | MCF_DMA_IMCR_SRC29_CTM5;
204 used_reqs[29] = DMA_CTM5;
205 } else /* No empty slots */
206 return 1;
207 break;
208
209 case DMA_CTM6:
210 if (used_reqs[30] == 0) {
211 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC30(3))
212 | MCF_DMA_IMCR_SRC30_CTM6;
213 used_reqs[30] = DMA_CTM6;
214 } else /* No empty slots */
215 return 1;
216 break;
217
218 case DMA_CTM7:
219 if (used_reqs[31] == 0) {
220 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3))
221 | MCF_DMA_IMCR_SRC31_CTM7;
222 used_reqs[31] = DMA_CTM7;
223 } else /* No empty slots */
224 return 1;
225 break;
226
227 case DMA_USBEP4:
228 if (used_reqs[26] == 0) {
229 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC26(3))
230 | MCF_DMA_IMCR_SRC26_USBEP4;
231 used_reqs[26] = DMA_USBEP4;
232 } else /* No empty slots */
233 return 1;
234 break;
235
236 case DMA_USBEP5:
237 if (used_reqs[27] == 0) {
238 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC27(3))
239 | MCF_DMA_IMCR_SRC27_USBEP5;
240 used_reqs[27] = DMA_USBEP5;
241 } else /* No empty slots */
242 return 1;
243 break;
244
245 case DMA_USBEP6:
246 if (used_reqs[28] == 0) {
247 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3))
248 | MCF_DMA_IMCR_SRC28_USBEP6;
249 used_reqs[28] = DMA_USBEP6;
250 } else /* No empty slots */
251 return 1;
252 break;
253
254 case DMA_PSC2_RX:
255 if (used_reqs[28] == 0) {
256 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC28(3))
257 | MCF_DMA_IMCR_SRC28_PSC2RX;
258 used_reqs[28] = DMA_PSC2_RX;
259 } else /* No empty slots */
260 return 1;
261 break;
262
263 case DMA_PSC2_TX:
264 if (used_reqs[29] == 0) {
265 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC29(3))
266 | MCF_DMA_IMCR_SRC29_PSC2TX;
267 used_reqs[29] = DMA_PSC2_TX;
268 } else /* No empty slots */
269 return 1;
270 break;
271
272 case DMA_PSC3_RX:
273 if (used_reqs[30] == 0) {
274 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC30(3))
275 | MCF_DMA_IMCR_SRC30_PSC3RX;
276 used_reqs[30] = DMA_PSC3_RX;
277 } else /* No empty slots */
278 return 1;
279 break;
280
281 case DMA_PSC3_TX:
282 if (used_reqs[31] == 0) {
283 MCF_DMA_IMCR = (MCF_DMA_IMCR & ~MCF_DMA_IMCR_SRC31(3))
284 | MCF_DMA_IMCR_SRC31_PSC3TX;
285 used_reqs[31] = DMA_PSC3_TX;
286 } else /* No empty slots */
287 return 1;
288 break;
289
290 default:
291 return 1;
292 }
293 return 0;
294 }
295
296 /**
297 * dma_get_initiator - get the initiator for the given requestor
298 * @requestor: initiator identifier
299 *
300 * Returns initiator number (0-31) if assigned or just 0
301 */
302 unsigned int dma_get_initiator(int requestor)
303 {
304 u32 i;
305
306 for (i = 0; i < sizeof(used_reqs); ++i) {
307 if (used_reqs[i] == requestor)
308 return i;
309 }
310 return 0;
311 }
312
313 /**
314 * dma_remove_initiator - remove the given initiator from active list
315 * @requestor: requestor to remove
316 */
317 void dma_remove_initiator(int requestor)
318 {
319 u32 i;
320
321 for (i = 0; i < sizeof(used_reqs); ++i) {
322 if (used_reqs[i] == requestor) {
323 used_reqs[i] = -1;
324 break;
325 }
326 }
327 }
328
329 /**
330 * dma_set_channel_fec: find available channel for fec and mark
331 * @requestor: initiator/requestor identifier
332 *
333 * Returns first avaialble channel (0-5) or -1 if all occupied
334 */
335 int dma_set_channel_fec(int requestor)
336 {
337 u32 i, t;
338
339 #ifdef CONFIG_FEC_548x_ENABLE_FEC2
340 t = 4;
341 #else
342 t = 2;
343 #endif
344
345 for (i = 0; i < t ; ++i) {
346 if (used_channel[i] == -1) {
347 used_channel[i] = requestor;
348 return i;
349 }
350 }
351 /* All channels taken */
352 return -1;
353 }
354
355 /**
356 * dma_set_channel - find an available channel and mark as used
357 * @requestor: initiator/requestor identifier
358 *
359 * Returns first available channel (6-15) or -1 if all occupied
360 */
361 int dma_set_channel(int requestor)
362 {
363 u32 i;
364 #ifdef CONFIG_NET_FEC2
365 i = 4;
366 #else
367 i = 2;
368 #endif
369
370 for (; i < 16; ++i)
371 if (used_channel[i] == -1) {
372 used_channel[i] = requestor;
373 return i;
374 }
375
376 /* All channels taken */
377 return -1;
378 }
379
380 /**
381 * dma_get_channel - get the channel being initiated by the requestor
382 * @requestor: initiator/requestor identifier
383 *
384 * Returns Initiator for requestor or -1 if not found
385 */
386 int dma_get_channel(int requestor)
387 {
388 u32 i;
389
390 for (i = 0; i < sizeof(used_channel); ++i) {
391 if (used_channel[i] == requestor)
392 return i;
393 }
394 return -1;
395 }
396
397 /**
398 * dma_connect - connect a channel with reference on data
399 * @channel: channel number
400 * @address: reference address of data
401 *
402 * Returns 0 if success or -1 if invalid channel
403 */
404 int dma_connect(int channel, int address)
405 {
406 if ((channel < 16) && (channel >= 0)) {
407 connected_channel[channel] = address;
408 return 0;
409 }
410 return -1;
411 }
412
413 /**
414 * dma_disconnect - disconnect a channel
415 * @channel: channel number
416 *
417 * Returns 0 if success or -1 if invalid channel
418 */
419 int dma_disconnect(int channel)
420 {
421 if ((channel < 16) && (channel >= 0)) {
422 connected_channel[channel] = 0;
423 return 0;
424 }
425 return -1;
426 }
427
428 /**
429 * dma_remove_channel - remove channel from the active list
430 * @requestor: initiator/requestor identifier
431 */
432 void dma_remove_channel(int requestor)
433 {
434 u32 i;
435
436 for (i = 0; i < sizeof(used_channel); ++i) {
437 if (used_channel[i] == requestor) {
438 used_channel[i] = -1;
439 break;
440 }
441 }
442 }
443
444 /**
445 * dma_interrupt_handler - dma interrupt handler
446 * @irq: interrupt number
447 * @dev_id: data
448 *
449 * Returns IRQ_HANDLED
450 */
451 irqreturn_t dma_interrupt_handler(int irq, void *dev_id)
452 {
453 u32 i, interrupts;
454
455 /*
456 * Determine which interrupt(s) triggered by AND'ing the
457 * pending interrupts with those that aren't masked.
458 */
459 interrupts = MCF_DMA_DIPR;
460 MCF_DMA_DIPR = interrupts;
461
462 for (i = 0; i < 16; ++i, interrupts >>= 1) {
463 if (interrupts & 0x1)
464 if (connected_channel[i] != 0)
465 ((void (*)(void)) (connected_channel[i])) ();
466 }
467
468 return IRQ_HANDLED;
469 }
470
471 /**
472 * dma_remove_channel_by_number - clear dma channel
473 * @channel: channel number to clear
474 */
475 void dma_remove_channel_by_number(int channel)
476 {
477 if ((channel < sizeof(used_channel)) && (channel >= 0))
478 used_channel[channel] = -1;
479 }
480
481 /**
482 * dma_init - initialize the dma subsystem
483 *
484 * Returns 0 if success non-zero if failure
485 *
486 * Handles the DMA initialization during device setup.
487 */
488 int __devinit dma_init()
489 {
490 int result;
491 char *dma_version_str;
492
493 MCD_getVersion(&dma_version_str);
494 printk(KERN_INFO "m547x_8x DMA: Initialize %s\n", dma_version_str);
495
496 /* attempt to setup dma interrupt handler */
497 if (request_irq(64 + ISC_DMA, dma_interrupt_handler, IRQF_DISABLED,
498 "MCD-DMA", NULL)) {
499 printk(KERN_ERR "MCD-DMA: Cannot allocate the DMA IRQ(48)\n");
500 return 1;
501 }
502
503 MCF_DMA_DIMR = 0;
504 MCF_DMA_DIPR = 0xFFFFFFFF;
505
506 MCF_ICR(ISC_DMA) = ILP_DMA;
507
508 result = MCD_initDma((dmaRegs *) (MCF_MBAR + 0x8000),
509 (void *) SYS_SRAM_DMA_START, MCD_RELOC_TASKS);
510 if (result != MCD_OK) {
511 printk(KERN_ERR "MCD-DMA: Cannot perform DMA initialization\n");
512 free_irq(64 + ISC_DMA, NULL);
513 return 1;
514 }
515
516 return 0;
517 }
518 device_initcall(dma_init);
This page took 0.103946 seconds and 5 git commands to generate.