]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/dma/omap3_dma.c
mx6sxsabresd: Add Ethernet support
[karo-tx-uboot.git] / drivers / dma / omap3_dma.c
1 /* Copyright (C) 2011
2  * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 /* This is a basic implementation of the SDMA/DMA4 controller of OMAP3
8  * Tested on Silicon Revision major:0x4 minor:0x0
9  */
10
11 #include <common.h>
12 #include <asm/arch/cpu.h>
13 #include <asm/arch/omap3.h>
14 #include <asm/arch/dma.h>
15 #include <asm/io.h>
16 #include <asm/errno.h>
17
18 static struct dma4 *dma4_cfg = (struct dma4 *)OMAP34XX_DMA4_BASE;
19 uint32_t dma_active; /* if a transfer is started the respective
20         bit is set for the logical channel */
21
22 /* Check if we have the given channel
23  * PARAMETERS:
24  * chan: Channel number
25  *
26  * RETURN of non-zero means error */
27 static inline int check_channel(uint32_t chan)
28 {
29         if (chan < CHAN_NR_MIN || chan > CHAN_NR_MAX)
30                 return -EINVAL;
31         return 0;
32 }
33
34 static inline void reset_irq(uint32_t chan)
35 {
36         /* reset IRQ reason */
37         writel(0x1DFE, &dma4_cfg->chan[chan].csr);
38         /* reset IRQ */
39         writel((1 << chan), &dma4_cfg->irqstatus_l[0]);
40         dma_active &= ~(1 << chan);
41 }
42
43 /* Set Source, Destination and Size of DMA transfer for the
44  * specified channel.
45  * PARAMETERS:
46  * chan: channel to use
47  * src: source of the transfer
48  * dst: destination of the transfer
49  * sze: Size of the transfer
50  *
51  * RETURN of non-zero means error */
52 int omap3_dma_conf_transfer(uint32_t chan, uint32_t *src, uint32_t *dst,
53                 uint32_t sze)
54 {
55         if (check_channel(chan))
56                 return -EINVAL;
57         /* CDSA0 */
58         writel((uint32_t)src, &dma4_cfg->chan[chan].cssa);
59         writel((uint32_t)dst, &dma4_cfg->chan[chan].cdsa);
60         writel(sze, &dma4_cfg->chan[chan].cen);
61 return 0;
62 }
63
64 /* Start the DMA transfer */
65 int omap3_dma_start_transfer(uint32_t chan)
66 {
67         uint32_t val;
68
69         if (check_channel(chan))
70                 return -EINVAL;
71
72         val = readl(&dma4_cfg->chan[chan].ccr);
73         /* Test for channel already in use */
74         if (val & CCR_ENABLE_ENABLE)
75                 return -EBUSY;
76
77         writel((val | CCR_ENABLE_ENABLE), &dma4_cfg->chan[chan].ccr);
78         dma_active |= (1 << chan);
79         debug("started transfer...\n");
80         return 0;
81 }
82
83 /* Busy-waiting for a DMA transfer
84  * This has to be called before another transfer is started
85  * PARAMETER
86  * chan: Channel to wait for
87  *
88  * RETURN of non-zero means error*/
89 int omap3_dma_wait_for_transfer(uint32_t chan)
90 {
91         uint32_t val;
92
93         if (!(dma_active & (1 << chan))) {
94                 val = readl(&dma4_cfg->irqstatus_l[0]);
95                 if (!(val & chan)) {
96                         debug("dma: The channel you are trying to wait for "
97                                 "was never activated - ERROR\n");
98                         return -1; /* channel was never active */
99                 }
100         }
101
102         /* all irqs on line 0 */
103         while (!(readl(&dma4_cfg->irqstatus_l[0]) & (1 << chan)))
104                 asm("nop");
105
106         val = readl(&dma4_cfg->chan[chan].csr);
107         if ((val & CSR_TRANS_ERR) | (val & CSR_SUPERVISOR_ERR) |
108                         (val & CSR_MISALIGNED_ADRS_ERR)) {
109                 debug("err code: %X\n", val);
110                 debug("dma: transfer error detected\n");
111                 reset_irq(chan);
112                 return -1;
113         }
114         reset_irq(chan);
115         return 0;
116 }
117
118 /* Get the revision of the DMA module
119  * PARAMETER
120  * minor: Address of minor revision to write
121  * major: Address of major revision to write
122  *
123  * RETURN of non-zero means error
124  */
125 int omap3_dma_get_revision(uint32_t *minor, uint32_t *major)
126 {
127         uint32_t val;
128
129         /* debug information */
130         val = readl(&dma4_cfg->revision);
131         *major = (val & 0x000000F0) >> 4;
132         *minor = (val & 0x0000000F);
133         debug("DMA Silicon revision (maj/min): 0x%X/0x%X\n", *major, *minor);
134         return 0;
135 }
136
137 /* Initial config of omap dma
138  */
139 void omap3_dma_init(void)
140 {
141         dma_active = 0;
142         /* All interrupts on channel 0 */
143         writel(0xFFFFFFFF, &dma4_cfg->irqenable_l[0]);
144 }
145
146 /* set channel config to config
147  *
148  * RETURN of non-zero means error */
149 int omap3_dma_conf_chan(uint32_t chan, struct dma4_chan *config)
150 {
151         if (check_channel(chan))
152                 return -EINVAL;
153
154         dma4_cfg->chan[chan] = *config;
155         return 0;
156 }
157
158 /* get channel config to config
159  *
160  * RETURN of non-zero means error */
161 int omap3_dma_get_conf_chan(uint32_t chan, struct dma4_chan *config)
162 {
163         if (check_channel(chan))
164                 return -EINVAL;
165         *config = dma4_cfg->chan[chan];
166         return 0;
167 }