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