Root/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 */
48static 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 */
64static char used_channel[16] = {
65    -1, -1, -1, -1, -1, -1, -1, -1,
66    -1, -1, -1, -1, -1, -1, -1, -1
67};
68
69unsigned 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 */
83int 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 */
302unsigned 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 */
317void 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 */
335int 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 */
361int 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 */
386int 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 */
404int 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 */
419int 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 */
432void 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 */
451irqreturn_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 */
475void 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 */
488int __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}
518device_initcall(dma_init);
519

Archive Download this file



interactive