2 * arch/m68k/coldfire/m547x/dma.c
4 * Coldfire M547x/M548x DMA
6 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Kurt Mahan <kmahan@freescale.com>
8 * Shrek Wu b16972@freescale.com
10 * This code is based on patches from the Freescale M547x_8x BSP
11 * release mcf547x_8x-20070107-ltib.iso
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.
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.
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.
27 #include <linux/kernel.h>
28 #include <linux/sched.h>
30 #include <linux/init.h>
31 #include <linux/interrupt.h>
35 #include <asm/coldfire.h>
36 #include <asm/m5485sram.h>
37 #include <asm/mcfsim.h>
38 #include <asm/MCD_dma.h>
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
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
,
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
64 static char used_channel
[16] = {
65 -1, -1, -1, -1, -1, -1, -1, -1,
66 -1, -1, -1, -1, -1, -1, -1, -1
69 unsigned int connected_channel
[16] = {
70 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0
75 * dma_set_initiator - enable initiator
76 * @initiator: initiator identifier
78 * Returns 0 of successful, non-zero otherwise
80 * Attempt to enable the provided Initiator in the Initiator
81 * Mux Control Register.
83 int dma_set_initiator(int initiator
)
103 * These initiators are always active
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
;
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
;
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
;
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
297 * dma_get_initiator - get the initiator for the given requestor
298 * @requestor: initiator identifier
300 * Returns initiator number (0-31) if assigned or just 0
302 unsigned int dma_get_initiator(int requestor
)
306 for (i
= 0; i
< sizeof(used_reqs
); ++i
) {
307 if (used_reqs
[i
] == requestor
)
314 * dma_remove_initiator - remove the given initiator from active list
315 * @requestor: requestor to remove
317 void dma_remove_initiator(int requestor
)
321 for (i
= 0; i
< sizeof(used_reqs
); ++i
) {
322 if (used_reqs
[i
] == requestor
) {
330 * dma_set_channel_fec: find available channel for fec and mark
331 * @requestor: initiator/requestor identifier
333 * Returns first avaialble channel (0-5) or -1 if all occupied
335 int dma_set_channel_fec(int requestor
)
339 #ifdef CONFIG_FEC_548x_ENABLE_FEC2
345 for (i
= 0; i
< t
; ++i
) {
346 if (used_channel
[i
] == -1) {
347 used_channel
[i
] = requestor
;
351 /* All channels taken */
356 * dma_set_channel - find an available channel and mark as used
357 * @requestor: initiator/requestor identifier
359 * Returns first available channel (6-15) or -1 if all occupied
361 int dma_set_channel(int requestor
)
364 #ifdef CONFIG_NET_FEC2
371 if (used_channel
[i
] == -1) {
372 used_channel
[i
] = requestor
;
376 /* All channels taken */
381 * dma_get_channel - get the channel being initiated by the requestor
382 * @requestor: initiator/requestor identifier
384 * Returns Initiator for requestor or -1 if not found
386 int dma_get_channel(int requestor
)
390 for (i
= 0; i
< sizeof(used_channel
); ++i
) {
391 if (used_channel
[i
] == requestor
)
398 * dma_connect - connect a channel with reference on data
399 * @channel: channel number
400 * @address: reference address of data
402 * Returns 0 if success or -1 if invalid channel
404 int dma_connect(int channel
, int address
)
406 if ((channel
< 16) && (channel
>= 0)) {
407 connected_channel
[channel
] = address
;
414 * dma_disconnect - disconnect a channel
415 * @channel: channel number
417 * Returns 0 if success or -1 if invalid channel
419 int dma_disconnect(int channel
)
421 if ((channel
< 16) && (channel
>= 0)) {
422 connected_channel
[channel
] = 0;
429 * dma_remove_channel - remove channel from the active list
430 * @requestor: initiator/requestor identifier
432 void dma_remove_channel(int requestor
)
436 for (i
= 0; i
< sizeof(used_channel
); ++i
) {
437 if (used_channel
[i
] == requestor
) {
438 used_channel
[i
] = -1;
445 * dma_interrupt_handler - dma interrupt handler
446 * @irq: interrupt number
449 * Returns IRQ_HANDLED
451 irqreturn_t
dma_interrupt_handler(int irq
, void *dev_id
)
456 * Determine which interrupt(s) triggered by AND'ing the
457 * pending interrupts with those that aren't masked.
459 interrupts
= MCF_DMA_DIPR
;
460 MCF_DMA_DIPR
= interrupts
;
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
])) ();
472 * dma_remove_channel_by_number - clear dma channel
473 * @channel: channel number to clear
475 void dma_remove_channel_by_number(int channel
)
477 if ((channel
< sizeof(used_channel
)) && (channel
>= 0))
478 used_channel
[channel
] = -1;
482 * dma_init - initialize the dma subsystem
484 * Returns 0 if success non-zero if failure
486 * Handles the DMA initialization during device setup.
488 int __devinit
dma_init()
491 char *dma_version_str
;
493 MCD_getVersion(&dma_version_str
);
494 printk(KERN_INFO
"m547x_8x DMA: Initialize %s\n", dma_version_str
);
496 /* attempt to setup dma interrupt handler */
497 if (request_irq(64 + ISC_DMA
, dma_interrupt_handler
, IRQF_DISABLED
,
499 printk(KERN_ERR
"MCD-DMA: Cannot allocate the DMA IRQ(48)\n");
504 MCF_DMA_DIPR
= 0xFFFFFFFF;
506 MCF_ICR(ISC_DMA
) = ILP_DMA
;
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
);
518 device_initcall(dma_init
);