2 * arch/m68k/coldfire/m547x_8x-dma.c
4 * Coldfire M547x/M548x DMA
6 * Copyright (c) 2008 Freescale Semiconductor, Inc.
7 * Kurt Mahan <kmahan@freescale.com>
9 * This code is based on patches from the Freescale M547x_8x BSP
10 * release mcf547x_8x-20070107-ltib.iso
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.
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.
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.
26 #include <linux/kernel.h>
27 #include <linux/sched.h>
29 #include <linux/init.h>
30 #include <linux/interrupt.h>
34 #include <asm/coldfire.h>
35 #include <asm/m548xsram.h>
36 #include <asm/mcfsim.h>
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
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,
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
62 static char used_channel[16] = {
63 -1, -1, -1, -1, -1, -1, -1, -1,
64 -1, -1, -1, -1, -1, -1, -1, -1
67 unsigned int connected_channel[16] = {
68 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0
73 * dma_set_initiator - enable initiator
74 * @initiator: initiator identifier
76 * Returns 0 of successful, non-zero otherwise
78 * Attempt to enable the provided Initiator in the Initiator
79 * Mux Control Register.
81 int dma_set_initiator(int initiator)
101 * These initiators are always active
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;
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;
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;
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
295 * dma_get_initiator - get the initiator for the given requestor
296 * @requestor: initiator identifier
298 * Returns initiator number (0-31) if assigned or just 0
300 unsigned int dma_get_initiator(int requestor)
304 for (i = 0; i < sizeof(used_reqs); ++i) {
305 if (used_reqs[i] == requestor)
312 * dma_remove_initiator - remove the given initiator from active list
313 * @requestor: requestor to remove
315 void dma_remove_initiator(int requestor)
319 for (i = 0; i < sizeof(used_reqs); ++i) {
320 if (used_reqs[i] == requestor) {
328 * dma_set_channel_fec: find available channel for fec and mark
329 * @requestor: initiator/requestor identifier
331 * Returns first avaialble channel (0-5) or -1 if all occupied
333 int dma_set_channel_fec(int requestor)
337 #ifdef CONFIG_FEC_548x_ENABLE_FEC2
343 for (i = 0; i < t ; ++i) {
344 if (used_channel[i] == -1) {
345 used_channel[i] = requestor;
349 /* All channels taken */
354 * dma_set_channel - find an available channel and mark as used
355 * @requestor: initiator/requestor identifier
357 * Returns first available channel (6-15) or -1 if all occupied
359 int dma_set_channel(int requestor)
362 #ifdef CONFIG_NET_FEC2
369 if (used_channel[i] == -1) {
370 used_channel[i] = requestor;
374 /* All channels taken */
379 * dma_get_channel - get the channel being initiated by the requestor
380 * @requestor: initiator/requestor identifier
382 * Returns Initiator for requestor or -1 if not found
384 int dma_get_channel(int requestor)
388 for (i = 0; i < sizeof(used_channel); ++i) {
389 if (used_channel[i] == requestor)
396 * dma_connect - connect a channel with reference on data
397 * @channel: channel number
398 * @address: reference address of data
400 * Returns 0 if success or -1 if invalid channel
402 int dma_connect(int channel, int address)
404 if ((channel < 16) && (channel >= 0)) {
405 connected_channel[channel] = address;
412 * dma_disconnect - disconnect a channel
413 * @channel: channel number
415 * Returns 0 if success or -1 if invalid channel
417 int dma_disconnect(int channel)
419 if ((channel < 16) && (channel >= 0)) {
420 connected_channel[channel] = 0;
427 * dma_remove_channel - remove channel from the active list
428 * @requestor: initiator/requestor identifier
430 void dma_remove_channel(int requestor)
434 for (i = 0; i < sizeof(used_channel); ++i) {
435 if (used_channel[i] == requestor) {
436 used_channel[i] = -1;
443 * dma_interrupt_handler - dma interrupt handler
444 * @irq: interrupt number
447 * Returns IRQ_HANDLED
449 irqreturn_t dma_interrupt_handler(int irq, void *dev_id)
454 * Determine which interrupt(s) triggered by AND'ing the
455 * pending interrupts with those that aren't masked.
457 interrupts = MCF_DMA_DIPR;
458 MCF_DMA_DIPR = interrupts;
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])) ();
470 * dma_remove_channel_by_number - clear dma channel
471 * @channel: channel number to clear
473 void dma_remove_channel_by_number(int channel)
475 if ((channel < sizeof(used_channel)) && (channel >= 0))
476 used_channel[channel] = -1;
480 * dma_init - initialize the dma subsystem
482 * Returns 0 if success non-zero if failure
484 * Handles the DMA initialization during device setup.
486 int __devinit dma_init()
489 char *dma_version_str;
491 MCD_getVersion(&dma_version_str);
492 printk(KERN_INFO "m547x_8x DMA: Initialize %s\n", dma_version_str);
494 /* attempt to setup dma interrupt handler */
495 if (request_irq(64 + ISC_DMA, dma_interrupt_handler, IRQF_DISABLED,
497 printk(KERN_ERR "MCD-DMA: Cannot allocate the DMA IRQ(48)\n");
502 MCF_DMA_DIPR = 0xFFFFFFFF;
504 MCF_ICR(ISC_DMA) = ILP_DMA;
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);
516 device_initcall(dma_init);