blob: 3320b3d08d11fbd4382e9c735185ebc3576743e2 [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 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02004 * SPDX-License-Identifier: GPL-2.0+
Simon Schwarz4c4bb192011-09-28 05:00:26 +00005 */
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
18static struct dma4 *dma4_cfg = (struct dma4 *)OMAP34XX_DMA4_BASE;
19uint32_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 */
27static 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
34static 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 */
52int 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);
61return 0;
62}
63
64/* Start the DMA transfer */
65int 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*/
89int 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 */
125int 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 */
139void 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 */
149int 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 */
161int 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}