1/*	$OpenBSD: edma.c,v 1.8 2021/10/24 17:52:27 mpi 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
32struct 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
81struct edma_softc *edma_sc;
82
83int	edma_match(struct device *, void *, void *);
84void	edma_attach(struct device *, struct device *, void *);
85int	edma_comp_intr(void *);
86
87const struct cfattach edma_ca = {
88	sizeof(struct edma_softc), edma_match, edma_attach
89};
90
91struct cfdriver edma_cd = {
92	NULL, "edma", DV_DULL
93};
94
95int
96edma_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
103void
104edma_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
163int
164edma_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
196int
197edma_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
217int
218edma_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
233int
234edma_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
260int
261edma_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
284void
285edma_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
291void
292edma_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