initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / edma.c
CommitLineData
cf3c20ae 1/* $OpenBSD: edma.c,v 1.5 2015/01/22 14:33:01 krw Exp $ */
2/*
3 * Copyright (c) 2013 Sylvestre Gallon <ccna.syl@gmail.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/param.h>
19#include <sys/types.h>
20#include <sys/systm.h>
21
22#include <machine/bus.h>
23
24#include <armv7/armv7/armv7var.h>
25#include <armv7/omap/prcmvar.h>
26#include <armv7/omap/edmavar.h>
27
28#define DEVNAME(s) ((s)->sc_dev.dv_xname)
29
30struct edma_softc {
31 struct device sc_dev;
32
33 bus_space_tag_t sc_iot;
34 bus_space_handle_t sc_tpcc;
35
36 void *sc_ih_comp;
37 edma_intr_cb_t sc_intr_cb[64];
38 void *sc_intr_dat[64];
39};
40
41#define EDMA_NUM_DMA_CHANS 64
42#define EDMA_NUM_QDMA_CHANS 8
43#define EDMA_TPCC_DHCM(x) (0x100 + (x * 4))
44#define EDMA_REG_X(x) (0x1000 + (0x200 * x))
45#define EDMA_TPCC_PID 0x0
46#define EDMA_TPCC_EMCR 0x308
47#define EDMA_TPCC_EMCRH 0x30c
48#define EDMA_TPCC_CCERRCLR 0x31c
49#define EDMA_TPCC_DRAE0 0x340
50#define EDMA_TPCC_DRAEH0 0x344
51#define EDMA_TPCC_ESR 0x1010
52#define EDMA_TPCC_ESRH 0x1014
53#define EDMA_TPCC_EESR 0x1030
54#define EDMA_TPCC_EESRH 0x1034
55#define EDMA_TPCC_SECR 0x1040
56#define EDMA_TPCC_SECRH 0x1044
57#define EDMA_TPCC_IER 0x1050
58#define EDMA_TPCC_IERH 0x1054
59#define EDMA_TPCC_IECR 0x1058
60#define EDMA_TPCC_IECRH 0x105c
61#define EDMA_TPCC_IESR 0x1060
62#define EDMA_TPCC_IESRH 0x1064
63#define EDMA_TPCC_IPR 0x1068
64#define EDMA_TPCC_IPRH 0x106c
65#define EDMA_TPCC_ICR 0x1070
66#define EDMA_TPCC_ICRH 0x1074
67#define EDMA_TPCC_IEVAL 0x1078
68#define EDMA_TPCC_OPT(x) (0x4000 + (x * 0x20))
69
70#define TPCC_READ_4(sc, reg) \
71 (bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg)))
72#define TPCC_WRITE_4(sc, reg, val) \
73 (bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val)))
74#define TPCC_SET(sc, reg, val) \
75 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val))))
76#define TPCC_FILTSET(sc, reg, val, filt) \
77 (TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val)))
78
79struct edma_softc *edma_sc;
80
81void edma_attach(struct device *, struct device *, void *);
82int edma_comp_intr(void *);
83
84struct cfattach edma_ca = {
85 sizeof(struct edma_softc), NULL, edma_attach
86};
87
88struct cfdriver edma_cd = {
89 NULL, "edma", DV_DULL
90};
91
92void
93edma_attach(struct device *parent, struct device *self, void *aux)
94{
95 struct armv7_attach_args *aa = aux;
96 struct edma_softc *sc = (struct edma_softc *)self;
97 uint32_t rev;
98 int i;
99
100 sc->sc_iot = aa->aa_iot;
101
102 /* Map Base address for TPCC and TPCTX */
103 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr,
104 aa->aa_dev->mem[0].size, 0, &sc->sc_tpcc)) {
105 printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc));
106 return ;
107 }
108
109 /* Enable TPCC and TPTC0 in PRCM */
110 prcm_enablemodule(PRCM_TPCC);
111 prcm_enablemodule(PRCM_TPTC0);
112
113 rev = TPCC_READ_4(sc, EDMA_TPCC_PID);
114 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
115
116 /* XXX IPL_VM ? */
117 /* Enable interrupts line */
118 sc->sc_ih_comp = arm_intr_establish(aa->aa_dev->irq[0], IPL_VM,
119 edma_comp_intr, sc, DEVNAME(sc));
120 if (sc->sc_ih_comp == NULL) {
121 printf("%s: unable to establish interrupt comp\n", DEVNAME(sc));
122 bus_space_unmap(sc->sc_iot, sc->sc_tpcc,
123 aa->aa_dev->mem[0].size);
124 return ;
125 }
126
127 /* Set global softc */
128 edma_sc = sc;
129
130 /* Clear Event Missed Events */
131 TPCC_WRITE_4(sc, EDMA_TPCC_EMCR, 0xffffffff);
132 TPCC_WRITE_4(sc, EDMA_TPCC_EMCRH, 0xffffffff);
133 TPCC_WRITE_4(sc, EDMA_TPCC_CCERRCLR, 0xffffffff);
134
135 /* Identity Map Channels PaRAM */
136 for (i = 0; i < EDMA_NUM_DMA_CHANS; i++)
137 TPCC_WRITE_4(sc, EDMA_TPCC_DHCM(i), i << 5);
138
139 /*
140 * Enable SHADOW Region 0 and only use this region
141 * This is needed to have working intr...
142 */
143 TPCC_WRITE_4(sc, EDMA_TPCC_DRAE0, 0xffffffff);
144 TPCC_WRITE_4(sc, EDMA_TPCC_DRAEH0, 0xffffffff);
145
146 return ;
147}
148
149int
150edma_comp_intr(void *arg)
151{
152 struct edma_softc *sc = arg;
153 uint32_t ipr, iprh;
154 int i;
155
156 ipr = TPCC_READ_4(sc, EDMA_TPCC_IPR);
157 iprh = TPCC_READ_4(sc, EDMA_TPCC_IPRH);
158
159 /* Lookup to intr in the first 32 chans */
160 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
161 if (ISSET(ipr, (1<<i))) {
162 TPCC_WRITE_4(sc, EDMA_TPCC_ICR, (1<<i));
163 if (sc->sc_intr_cb[i])
164 sc->sc_intr_cb[i](sc->sc_intr_dat[i]);
165 }
166 }
167
168 for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
169 if (ISSET(iprh, (1<<i))) {
170 TPCC_WRITE_4(sc, EDMA_TPCC_ICRH, (1<<i));
171 if (sc->sc_intr_cb[i + 32])
172 sc->sc_intr_cb[i + 32](sc->sc_intr_dat[i + 32]);
173 }
174 }
175
176 /* Trig pending intr */
177 TPCC_WRITE_4(sc, EDMA_TPCC_IEVAL, 1);
178
179 return (1);
180}
181
182int
183edma_intr_dma_en(uint32_t ch, edma_intr_cb_t cb, void *dat)
184{
185 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
186 return (EINVAL);
187
188 edma_sc->sc_intr_cb[ch] = cb;
189 edma_sc->sc_intr_dat[ch] = dat;
190
191 if (ch < 32) {
192 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR, 1 << ch);
193 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR + EDMA_REG_X(0), 1 << ch);
194 } else {
195 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH, 1 << (ch - 32));
196 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH + EDMA_REG_X(0),
197 1 << (ch - 32));
198 }
199
200 return (0);
201}
202
203int
204edma_intr_dma_dis(uint32_t ch)
205{
206 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
207 return (EINVAL);
208
209 if (ch < 32)
210 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECR, 1 << ch);
211 else
212 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECRH, 1 << (ch - 32));
213 edma_sc->sc_intr_cb[ch] = NULL;
214 edma_sc->sc_intr_dat[ch] = NULL;
215
216 return (0);
217}
218
219int
220edma_trig_xfer_man(uint32_t ch)
221{
222 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
223 return (EINVAL);
224
225 /*
226 * Trig xfer
227 * enable IEVAL only if there is an intr associated
228 */
229 if (ch < 32) {
230 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
231 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
232 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
233 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
234 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESR, 1 << ch);
235 } else {
236 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
237 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
238 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
239 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
240 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESRH, 1 << (ch - 32));
241 }
242
243 return (0);
244}
245
246int
247edma_trig_xfer_by_dev(uint32_t ch)
248{
249 if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
250 return (EINVAL);
251
252 if (ch < 32) {
253 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
254 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
255 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
256 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECR, 1 << ch);
257 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
258 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESR, 1 << ch);
259 } else {
260 if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
261 TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
262 TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
263 TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECRH, 1 << (ch - 32));
264 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
265 TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESRH, 1 << (ch - 32));
266 }
267 return (0);
268}
269
270void
271edma_param_write(uint32_t ch, struct edma_param *params)
272{
273 bus_space_write_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
274 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
275}
276
277void
278edma_param_read(uint32_t ch, struct edma_param *params)
279{
280 bus_space_read_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
281 EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
282}
283