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