xref: /openbsd/sys/arch/armv7/omap/edma.c (revision 3cab2bb3)
1 /*	$OpenBSD: edma.c,v 1.7 2017/09/08 05:36:51 deraadt 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/systm.h>
20 
21 #include <machine/fdt.h>
22 
23 #include <armv7/armv7/armv7var.h>
24 #include <armv7/omap/prcmvar.h>
25 #include <armv7/omap/edmavar.h>
26 
27 #include <dev/ofw/openfirm.h>
28 #include <dev/ofw/fdt.h>
29 
30 #define DEVNAME(s)		((s)->sc_dev.dv_xname)
31 
32 struct edma_softc {
33 	struct device		sc_dev;
34 
35 	bus_space_tag_t		sc_iot;
36 	bus_space_handle_t	sc_tpcc;
37 
38 	void			*sc_ih_comp;
39 	edma_intr_cb_t		sc_intr_cb[64];
40 	void			*sc_intr_dat[64];
41 };
42 
43 #define EDMA_NUM_DMA_CHANS	64
44 #define EDMA_NUM_QDMA_CHANS	8
45 #define EDMA_TPCC_DHCM(x)	(0x100 + (x * 4))
46 #define EDMA_REG_X(x)		(0x1000 + (0x200 * x))
47 #define EDMA_TPCC_PID		0x0
48 #define EDMA_TPCC_EMCR		0x308
49 #define EDMA_TPCC_EMCRH		0x30c
50 #define EDMA_TPCC_CCERRCLR	0x31c
51 #define EDMA_TPCC_DRAE0		0x340
52 #define EDMA_TPCC_DRAEH0	0x344
53 #define EDMA_TPCC_ESR		0x1010
54 #define EDMA_TPCC_ESRH		0x1014
55 #define EDMA_TPCC_EESR		0x1030
56 #define EDMA_TPCC_EESRH		0x1034
57 #define EDMA_TPCC_SECR		0x1040
58 #define EDMA_TPCC_SECRH		0x1044
59 #define EDMA_TPCC_IER		0x1050
60 #define EDMA_TPCC_IERH		0x1054
61 #define EDMA_TPCC_IECR		0x1058
62 #define EDMA_TPCC_IECRH		0x105c
63 #define EDMA_TPCC_IESR		0x1060
64 #define EDMA_TPCC_IESRH		0x1064
65 #define EDMA_TPCC_IPR		0x1068
66 #define EDMA_TPCC_IPRH		0x106c
67 #define EDMA_TPCC_ICR		0x1070
68 #define EDMA_TPCC_ICRH		0x1074
69 #define EDMA_TPCC_IEVAL		0x1078
70 #define EDMA_TPCC_OPT(x)	(0x4000 + (x * 0x20))
71 
72 #define TPCC_READ_4(sc, reg)						\
73 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_tpcc, (reg)))
74 #define TPCC_WRITE_4(sc, reg, val)					\
75 	(bus_space_write_4((sc)->sc_iot, (sc)->sc_tpcc, (reg), (val)))
76 #define TPCC_SET(sc, reg, val)						\
77 	(TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) | (val))))
78 #define TPCC_FILTSET(sc, reg, val, filt)				\
79 	(TPCC_WRITE_4((sc), (reg), (TPCC_READ_4(sc, reg) & (filt)) | (val)))
80 
81 struct edma_softc *edma_sc;
82 
83 int	edma_match(struct device *, void *, void *);
84 void	edma_attach(struct device *, struct device *, void *);
85 int	edma_comp_intr(void *);
86 
87 struct cfattach edma_ca = {
88 	sizeof(struct edma_softc), edma_match, edma_attach
89 };
90 
91 struct cfdriver edma_cd = {
92 	NULL, "edma", DV_DULL
93 };
94 
95 int
96 edma_match(struct device *parent, void *match, void *aux)
97 {
98 	struct fdt_attach_args *faa = aux;
99 
100 	return OF_is_compatible(faa->fa_node, "ti,edma3-tpcc");
101 }
102 
103 void
104 edma_attach(struct device *parent, struct device *self, void *aux)
105 {
106 	struct fdt_attach_args *faa = aux;
107 	struct edma_softc *sc = (struct edma_softc *)self;
108 	uint32_t rev;
109 	int i;
110 
111 	if (faa->fa_nreg < 1)
112 		return;
113 
114 	sc->sc_iot = faa->fa_iot;
115 
116 	/* Map Base address for TPCC and TPCTX */
117 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
118 	    faa->fa_reg[0].size, 0, &sc->sc_tpcc)) {
119 		printf("%s: bus_space_map failed for TPCC\n", DEVNAME(sc));
120 		return ;
121 	}
122 
123 	/* Enable TPCC and TPTC0 in PRCM */
124 	prcm_enablemodule(PRCM_TPCC);
125 	prcm_enablemodule(PRCM_TPTC0);
126 
127 	rev = TPCC_READ_4(sc, EDMA_TPCC_PID);
128 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
129 
130 	/* XXX IPL_VM ? */
131 	/* Enable interrupts line */
132 	sc->sc_ih_comp = arm_intr_establish_fdt(faa->fa_node, IPL_VM,
133 	    edma_comp_intr, sc, DEVNAME(sc));
134 	if (sc->sc_ih_comp == NULL) {
135 		printf("%s: unable to establish interrupt comp\n", DEVNAME(sc));
136 		bus_space_unmap(sc->sc_iot, sc->sc_tpcc,
137 		    faa->fa_reg[0].size);
138 		return ;
139 	}
140 
141 	/* Set global softc */
142 	edma_sc = sc;
143 
144 	/* Clear Event Missed Events */
145 	TPCC_WRITE_4(sc, EDMA_TPCC_EMCR, 0xffffffff);
146 	TPCC_WRITE_4(sc, EDMA_TPCC_EMCRH, 0xffffffff);
147 	TPCC_WRITE_4(sc, EDMA_TPCC_CCERRCLR, 0xffffffff);
148 
149 	/* Identity Map Channels PaRAM */
150 	for (i = 0; i < EDMA_NUM_DMA_CHANS; i++)
151 		TPCC_WRITE_4(sc, EDMA_TPCC_DHCM(i), i << 5);
152 
153 	/*
154 	 * Enable SHADOW Region 0 and only use this region
155 	 * This is needed to have working intr...
156 	 */
157 	TPCC_WRITE_4(sc, EDMA_TPCC_DRAE0, 0xffffffff);
158 	TPCC_WRITE_4(sc, EDMA_TPCC_DRAEH0, 0xffffffff);
159 
160 	return ;
161 }
162 
163 int
164 edma_comp_intr(void *arg)
165 {
166 	struct edma_softc *sc = arg;
167 	uint32_t ipr, iprh;
168 	int i;
169 
170 	ipr = TPCC_READ_4(sc, EDMA_TPCC_IPR);
171 	iprh = TPCC_READ_4(sc, EDMA_TPCC_IPRH);
172 
173 	/* Lookup to intr in the first 32 chans */
174 	for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
175 		if (ISSET(ipr, (1<<i))) {
176 			TPCC_WRITE_4(sc, EDMA_TPCC_ICR, (1<<i));
177 			if (sc->sc_intr_cb[i])
178 				sc->sc_intr_cb[i](sc->sc_intr_dat[i]);
179 		}
180 	}
181 
182 	for (i = 0; i < (EDMA_NUM_DMA_CHANS/2); i++) {
183 		if (ISSET(iprh, (1<<i))) {
184 			TPCC_WRITE_4(sc, EDMA_TPCC_ICRH, (1<<i));
185 			if (sc->sc_intr_cb[i + 32])
186 				sc->sc_intr_cb[i + 32](sc->sc_intr_dat[i + 32]);
187 		}
188 	}
189 
190 	/* Trig pending intr */
191 	TPCC_WRITE_4(sc, EDMA_TPCC_IEVAL, 1);
192 
193 	return (1);
194 }
195 
196 int
197 edma_intr_dma_en(uint32_t ch, edma_intr_cb_t cb, void *dat)
198 {
199 	if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
200 		return (EINVAL);
201 
202 	edma_sc->sc_intr_cb[ch] = cb;
203 	edma_sc->sc_intr_dat[ch] = dat;
204 
205 	if (ch < 32) {
206 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR, 1 << ch);
207 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESR + EDMA_REG_X(0), 1 << ch);
208 	} else {
209 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH, 1 << (ch - 32));
210 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IESRH + EDMA_REG_X(0),
211 		    1 << (ch - 32));
212 	}
213 
214 	return (0);
215 }
216 
217 int
218 edma_intr_dma_dis(uint32_t ch)
219 {
220 	if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
221 		return (EINVAL);
222 
223 	if (ch < 32)
224 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECR, 1 << ch);
225 	else
226 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_IECRH, 1 << (ch - 32));
227 	edma_sc->sc_intr_cb[ch] = NULL;
228 	edma_sc->sc_intr_dat[ch] = NULL;
229 
230 	return (0);
231 }
232 
233 int
234 edma_trig_xfer_man(uint32_t ch)
235 {
236 	if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
237 		return (EINVAL);
238 
239 	/*
240 	 * Trig xfer
241 	 * enable IEVAL only if there is an intr associated
242 	 */
243 	if (ch < 32) {
244 		if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
245 			TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
246 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
247 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
248 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESR, 1 << ch);
249 	} else {
250 		if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
251 			TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
252 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
253 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
254 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ESRH, 1 << (ch - 32));
255 	}
256 
257 	return (0);
258 }
259 
260 int
261 edma_trig_xfer_by_dev(uint32_t ch)
262 {
263 	if (edma_sc == NULL || ch >= EDMA_NUM_DMA_CHANS)
264 		return (EINVAL);
265 
266 	if (ch < 32) {
267 		if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IER), 1 << ch))
268 			TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
269 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICR, 1 << ch);
270 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECR, 1 << ch);
271 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCR, 1 << ch);
272 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESR, 1 << ch);
273 	} else {
274 		if (ISSET(TPCC_READ_4(edma_sc, EDMA_TPCC_IERH), 1 << (ch - 32)))
275 			TPCC_WRITE_4(edma_sc, EDMA_TPCC_IEVAL, 1);
276 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_ICRH, 1 << (ch - 32));
277 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_SECRH, 1 << (ch - 32));
278 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EMCRH, 1 << (ch - 32));
279 		TPCC_WRITE_4(edma_sc, EDMA_TPCC_EESRH, 1 << (ch - 32));
280 	}
281 	return (0);
282 }
283 
284 void
285 edma_param_write(uint32_t ch, struct edma_param *params)
286 {
287 	bus_space_write_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
288 	    EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
289 }
290 
291 void
292 edma_param_read(uint32_t ch, struct edma_param *params)
293 {
294 	bus_space_read_region_4(edma_sc->sc_iot, edma_sc->sc_tpcc,
295 	    EDMA_TPCC_OPT(ch), (uint32_t *)params, 8);
296 }
297 
298