blob: b98eca119c0cb020e5eb6c7143a1113b8c453da2 [file] [log] [blame]
Simon Schwarz4c4bb192011-09-28 05:00:26 +00001/* Copyright (C) 2011
2 * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
17 * MA 02111-1307 USA
18 */
19
20/* This is a basic implementation of the SDMA/DMA4 controller of OMAP3
21 * Tested on Silicon Revision major:0x4 minor:0x0
22 */
23
24#include <common.h>
25#include <asm/arch/cpu.h>
26#include <asm/arch/omap3.h>
27#include <asm/arch/dma.h>
28#include <asm/io.h>
29#include <asm/errno.h>
30
31static struct dma4 *dma4_cfg = (struct dma4 *)OMAP34XX_DMA4_BASE;
32uint32_t dma_active; /* if a transfer is started the respective
33 bit is set for the logical channel */
34
35/* Check if we have the given channel
36 * PARAMETERS:
37 * chan: Channel number
38 *
39 * RETURN of non-zero means error */
40static inline int check_channel(uint32_t chan)
41{
42 if (chan < CHAN_NR_MIN || chan > CHAN_NR_MAX)
43 return -EINVAL;
44 return 0;
45}
46
47static inline void reset_irq(uint32_t chan)
48{
49 /* reset IRQ reason */
50 writel(0x1DFE, &dma4_cfg->chan[chan].csr);
51 /* reset IRQ */
52 writel((1 << chan), &dma4_cfg->irqstatus_l[0]);
53 dma_active &= ~(1 << chan);
54}
55
56/* Set Source, Destination and Size of DMA transfer for the
57 * specified channel.
58 * PARAMETERS:
59 * chan: channel to use
60 * src: source of the transfer
61 * dst: destination of the transfer
62 * sze: Size of the transfer
63 *
64 * RETURN of non-zero means error */
65int omap3_dma_conf_transfer(uint32_t chan, uint32_t *src, uint32_t *dst,
66 uint32_t sze)
67{
68 if (check_channel(chan))
69 return -EINVAL;
70 /* CDSA0 */
71 writel((uint32_t)src, &dma4_cfg->chan[chan].cssa);
72 writel((uint32_t)dst, &dma4_cfg->chan[chan].cdsa);
73 writel(sze, &dma4_cfg->chan[chan].cen);
74return 0;
75}
76
77/* Start the DMA transfer */
78int omap3_dma_start_transfer(uint32_t chan)
79{
80 uint32_t val;
81
82 if (check_channel(chan))
83 return -EINVAL;
84
85 val = readl(&dma4_cfg->chan[chan].ccr);
86 /* Test for channel already in use */
87 if (val & CCR_ENABLE_ENABLE)
88 return -EBUSY;
89
90 writel((val | CCR_ENABLE_ENABLE), &dma4_cfg->chan[chan].ccr);
91 dma_active |= (1 << chan);
92 debug("started transfer...\n");
93 return 0;
94}
95
96/* Busy-waiting for a DMA transfer
97 * This has to be called before another transfer is started
98 * PARAMETER
99 * chan: Channel to wait for
100 *
101 * RETURN of non-zero means error*/
102int omap3_dma_wait_for_transfer(uint32_t chan)
103{
104 uint32_t val;
105
106 if (!(dma_active & (1 << chan))) {
107 val = readl(&dma4_cfg->irqstatus_l[0]);
108 if (!(val & chan)) {
109 debug("dma: The channel you are trying to wait for "
110 "was never activated - ERROR\n");
111 return -1; /* channel was never active */
112 }
113 }
114
115 /* all irqs on line 0 */
116 while (!(readl(&dma4_cfg->irqstatus_l[0]) & (1 << chan)))
117 asm("nop");
118
119 val = readl(&dma4_cfg->chan[chan].csr);
120 if ((val & CSR_TRANS_ERR) | (val & CSR_SUPERVISOR_ERR) |
121 (val & CSR_MISALIGNED_ADRS_ERR)) {
122 debug("err code: %X\n", val);
123 debug("dma: transfer error detected\n");
124 reset_irq(chan);
125 return -1;
126 }
127 reset_irq(chan);
128 return 0;
129}
130
131/* Get the revision of the DMA module
132 * PARAMETER
133 * minor: Address of minor revision to write
134 * major: Address of major revision to write
135 *
136 * RETURN of non-zero means error
137 */
138int omap3_dma_get_revision(uint32_t *minor, uint32_t *major)
139{
140 uint32_t val;
141
142 /* debug information */
143 val = readl(&dma4_cfg->revision);
144 *major = (val & 0x000000F0) >> 4;
145 *minor = (val & 0x0000000F);
146 debug("DMA Silicon revision (maj/min): 0x%X/0x%X\n", *major, *minor);
147 return 0;
148}
149
150/* Initial config of omap dma
151 */
152void omap3_dma_init(void)
153{
154 dma_active = 0;
155 /* All interrupts on channel 0 */
156 writel(0xFFFFFFFF, &dma4_cfg->irqenable_l[0]);
157}
158
159/* set channel config to config
160 *
161 * RETURN of non-zero means error */
162int omap3_dma_conf_chan(uint32_t chan, struct dma4_chan *config)
163{
164 if (check_channel(chan))
165 return -EINVAL;
166
167 dma4_cfg->chan[chan] = *config;
168 return 0;
169}
170
171/* get channel config to config
172 *
173 * RETURN of non-zero means error */
174int omap3_dma_get_conf_chan(uint32_t chan, struct dma4_chan *config)
175{
176 if (check_channel(chan))
177 return -EINVAL;
178 *config = dma4_cfg->chan[chan];
179 return 0;
180}