xref: /openbsd-src/sys/arch/armv7/omap/edma.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
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 
30 struct 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 
79 struct edma_softc *edma_sc;
80 
81 void	edma_attach(struct device *, struct device *, void *);
82 int	edma_comp_intr(void *);
83 
84 struct cfattach edma_ca = {
85 	sizeof(struct edma_softc), NULL, edma_attach
86 };
87 
88 struct cfdriver edma_cd = {
89 	NULL, "edma", DV_DULL
90 };
91 
92 void
93 edma_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 
149 int
150 edma_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 
182 int
183 edma_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 
203 int
204 edma_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 
219 int
220 edma_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 
246 int
247 edma_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 
270 void
271 edma_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 
277 void
278 edma_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 
284