2 * Corscience GmbH & Co. KG - Simon Schwarz <schwarz@corscience.de>
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.
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.
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,
20 /* This is a basic implementation of the SDMA/DMA4 controller of OMAP3
21 * Tested on Silicon Revision major:0x4 minor:0x0
25 #include <asm/arch/cpu.h>
26 #include <asm/arch/omap3.h>
27 #include <asm/arch/dma.h>
29 #include <asm/errno.h>
31 static struct dma4 *dma4_cfg = (struct dma4 *)OMAP34XX_DMA4_BASE;
32 uint32_t dma_active; /* if a transfer is started the respective
33 bit is set for the logical channel */
35 /* Check if we have the given channel
37 * chan: Channel number
39 * RETURN of non-zero means error */
40 static inline int check_channel(uint32_t chan)
42 if (chan < CHAN_NR_MIN || chan > CHAN_NR_MAX)
47 static inline void reset_irq(uint32_t chan)
49 /* reset IRQ reason */
50 writel(0x1DFE, &dma4_cfg->chan[chan].csr);
52 writel((1 << chan), &dma4_cfg->irqstatus_l[0]);
53 dma_active &= ~(1 << chan);
56 /* Set Source, Destination and Size of DMA transfer for the
59 * chan: channel to use
60 * src: source of the transfer
61 * dst: destination of the transfer
62 * sze: Size of the transfer
64 * RETURN of non-zero means error */
65 int omap3_dma_conf_transfer(uint32_t chan, uint32_t *src, uint32_t *dst,
68 if (check_channel(chan))
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);
77 /* Start the DMA transfer */
78 int omap3_dma_start_transfer(uint32_t chan)
82 if (check_channel(chan))
85 val = readl(&dma4_cfg->chan[chan].ccr);
86 /* Test for channel already in use */
87 if (val & CCR_ENABLE_ENABLE)
90 writel((val | CCR_ENABLE_ENABLE), &dma4_cfg->chan[chan].ccr);
91 dma_active |= (1 << chan);
92 debug("started transfer...\n");
96 /* Busy-waiting for a DMA transfer
97 * This has to be called before another transfer is started
99 * chan: Channel to wait for
101 * RETURN of non-zero means error*/
102 int omap3_dma_wait_for_transfer(uint32_t chan)
106 if (!(dma_active & (1 << chan))) {
107 val = readl(&dma4_cfg->irqstatus_l[0]);
109 debug("dma: The channel you are trying to wait for "
110 "was never activated - ERROR\n");
111 return -1; /* channel was never active */
115 /* all irqs on line 0 */
116 while (!(readl(&dma4_cfg->irqstatus_l[0]) & (1 << chan)))
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");
131 /* Get the revision of the DMA module
133 * minor: Address of minor revision to write
134 * major: Address of major revision to write
136 * RETURN of non-zero means error
138 int omap3_dma_get_revision(uint32_t *minor, uint32_t *major)
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);
150 /* Initial config of omap dma
152 void omap3_dma_init(void)
155 /* All interrupts on channel 0 */
156 writel(0xFFFFFFFF, &dma4_cfg->irqenable_l[0]);
159 /* set channel config to config
161 * RETURN of non-zero means error */
162 int omap3_dma_conf_chan(uint32_t chan, struct dma4_chan *config)
164 if (check_channel(chan))
167 dma4_cfg->chan[chan] = *config;
171 /* get channel config to config
173 * RETURN of non-zero means error */
174 int omap3_dma_get_conf_chan(uint32_t chan, struct dma4_chan *config)
176 if (check_channel(chan))
178 *config = dma4_cfg->chan[chan];