1 /* $NetBSD: ti_edma.c,v 1.5 2022/05/21 19:07:23 andvar Exp $ */
2
3 /*-
4 * Copyright (c) 2014 Jared D. McNeill <jmcneill@invisible.ca>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: ti_edma.c,v 1.5 2022/05/21 19:07:23 andvar Exp $");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/device.h>
34 #include <sys/conf.h>
35 #include <sys/intr.h>
36 #include <sys/mutex.h>
37 #include <sys/bus.h>
38 #include <sys/bitops.h>
39
40 #include <dev/fdt/fdtvar.h>
41
42 #include <arm/ti/ti_prcm.h>
43 #include <arm/ti/ti_edma.h>
44
45 #define NUM_DMA_CHANNELS 64
46 #define NUM_PARAM_SETS 256
47 #define MAX_PARAM_PER_CHANNEL 32
48
49 #ifdef EDMA_DEBUG
50 int edmadebug = 1;
51 #define DPRINTF(n,s) do { if ((n) <= edmadebug) device_printf s; } while (0)
52 #else
53 #define DPRINTF(n,s) do {} while (0)
54 #endif
55
56 struct edma_softc;
57
58 struct edma_channel {
59 struct edma_softc *ch_sc;
60 enum edma_type ch_type;
61 uint8_t ch_index;
62 void (*ch_callback)(void *);
63 void *ch_callbackarg;
64 unsigned int ch_nparams;
65 };
66
67 struct edma_softc {
68 device_t sc_dev;
69 bus_space_tag_t sc_iot;
70 bus_space_handle_t sc_ioh;
71 kmutex_t sc_lock;
72 struct edma_channel sc_dma[NUM_DMA_CHANNELS];
73
74 void *sc_ih;
75
76 uint32_t sc_dmamask[NUM_DMA_CHANNELS / 32];
77 uint32_t sc_parammask[NUM_PARAM_SETS / 32];
78 };
79
80 static int edma_match(device_t, cfdata_t, void *);
81 static void edma_attach(device_t, device_t, void *);
82
83 static void edma_init(struct edma_softc *);
84 static int edma_intr(void *);
85 static void edma_write_param(struct edma_softc *,
86 unsigned int, const struct edma_param *);
87 static bool edma_bit_isset(uint32_t *, unsigned int);
88 static void edma_bit_set(uint32_t *, unsigned int);
89 static void edma_bit_clr(uint32_t *, unsigned int);
90
91 CFATTACH_DECL_NEW(ti_edma, sizeof(struct edma_softc),
92 edma_match, edma_attach, NULL, NULL);
93
94 #define EDMA_READ(sc, reg) \
95 bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
96 #define EDMA_WRITE(sc, reg, val) \
97 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
98
99 static const struct device_compatible_entry compat_data[] = {
100 { .compat = "ti,edma3-tpcc" },
101 DEVICE_COMPAT_EOL
102 };
103
104 static int
edma_match(device_t parent,cfdata_t match,void * aux)105 edma_match(device_t parent, cfdata_t match, void *aux)
106 {
107 struct fdt_attach_args * const faa = aux;
108
109 return of_compatible_match(faa->faa_phandle, compat_data);
110 }
111
112 static void
edma_attach(device_t parent,device_t self,void * aux)113 edma_attach(device_t parent, device_t self, void *aux)
114 {
115 struct edma_softc *sc = device_private(self);
116 struct fdt_attach_args * const faa = aux;
117 const int phandle = faa->faa_phandle;
118 char intrstr[128];
119 bus_addr_t addr;
120 bus_size_t size;
121 int idx;
122
123 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
124 aprint_error(": couldn't get registers\n");
125 return;
126 }
127
128 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
129 aprint_error(": failed to decode interrupt\n");
130 return;
131 }
132
133 sc->sc_dev = self;
134 sc->sc_iot = faa->faa_bst;
135 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
136 if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
137 aprint_error(": couldn't map registers\n");
138 return;
139 }
140
141 aprint_naive("\n");
142 aprint_normal(": EDMA Channel Controller\n");
143
144 for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) {
145 struct edma_channel *ch = &sc->sc_dma[idx];
146 ch->ch_sc = sc;
147 ch->ch_type = EDMA_TYPE_DMA;
148 ch->ch_index = idx;
149 ch->ch_callback = NULL;
150 ch->ch_callbackarg = NULL;
151 ch->ch_nparams = 0;
152 }
153
154 if (ti_prcm_enable_hwmod(phandle, 0) != 0) {
155 aprint_error_dev(self, "couldn't enable module\n");
156 return;
157 }
158
159 edma_init(sc);
160
161 sc->sc_ih = fdtbus_intr_establish_byname(phandle, "edma3_ccint",
162 IPL_VM, FDT_INTR_MPSAFE, edma_intr, sc, device_xname(self));
163 if (sc->sc_ih == NULL) {
164 aprint_error_dev(self, "failed to establish interrupt\n");
165 return;
166 }
167 aprint_normal_dev(self, "interrupting on %s\n", intrstr);
168 }
169
170 /*
171 * Hardware initialization
172 */
173 static void
edma_init(struct edma_softc * sc)174 edma_init(struct edma_softc *sc)
175 {
176 struct edma_param param;
177 uint32_t val;
178 int idx;
179
180 val = EDMA_READ(sc, EDMA_CCCFG_REG);
181 if (val & EDMA_CCCFG_CHMAP_EXIST) {
182 for (idx = 0; idx < NUM_DMA_CHANNELS; idx++) {
183 EDMA_WRITE(sc, EDMA_DCHMAP_REG(idx),
184 __SHIFTIN(0, EDMA_DCHMAP_PAENTRY));
185 }
186 }
187
188 memset(¶m, 0, sizeof(param));
189 param.ep_bcnt = 1;
190 for (idx = 0; idx < NUM_PARAM_SETS; idx++) {
191 edma_write_param(sc, idx, ¶m);
192 }
193
194 /* reserve PaRAM entry 0 for dummy slot */
195 edma_bit_set(sc->sc_parammask, 0);
196 for (idx = 1; idx <= 32; idx++) {
197 edma_bit_set(sc->sc_parammask, idx);
198 }
199 }
200
201 /*
202 * Write a PaRAM entry
203 */
204 static void
edma_write_param(struct edma_softc * sc,unsigned int idx,const struct edma_param * ep)205 edma_write_param(struct edma_softc *sc,
206 unsigned int idx, const struct edma_param *ep)
207 {
208 EDMA_WRITE(sc, EDMA_PARAM_OPT_REG(idx), ep->ep_opt);
209 EDMA_WRITE(sc, EDMA_PARAM_SRC_REG(idx), ep->ep_src);
210 EDMA_WRITE(sc, EDMA_PARAM_CNT_REG(idx),
211 __SHIFTIN(ep->ep_bcnt, EDMA_PARAM_CNT_BCNT) |
212 __SHIFTIN(ep->ep_acnt, EDMA_PARAM_CNT_ACNT));
213 EDMA_WRITE(sc, EDMA_PARAM_DST_REG(idx), ep->ep_dst);
214 EDMA_WRITE(sc, EDMA_PARAM_BIDX_REG(idx),
215 __SHIFTIN(ep->ep_dstbidx, EDMA_PARAM_BIDX_DSTBIDX) |
216 __SHIFTIN(ep->ep_srcbidx, EDMA_PARAM_BIDX_SRCBIDX));
217 EDMA_WRITE(sc, EDMA_PARAM_LNK_REG(idx),
218 __SHIFTIN(ep->ep_bcntrld, EDMA_PARAM_LNK_BCNTRLD) |
219 __SHIFTIN(ep->ep_link, EDMA_PARAM_LNK_LINK));
220 EDMA_WRITE(sc, EDMA_PARAM_CIDX_REG(idx),
221 __SHIFTIN(ep->ep_dstcidx, EDMA_PARAM_CIDX_DSTCIDX) |
222 __SHIFTIN(ep->ep_srccidx, EDMA_PARAM_CIDX_SRCCIDX));
223 EDMA_WRITE(sc, EDMA_PARAM_CCNT_REG(idx),
224 __SHIFTIN(ep->ep_ccnt, EDMA_PARAM_CCNT_CCNT));
225 }
226
227 static bool
edma_bit_isset(uint32_t * bits,unsigned int bit)228 edma_bit_isset(uint32_t *bits, unsigned int bit)
229 {
230 return !!(bits[bit >> 5] & (1 << (bit & 0x1f)));
231 }
232
233 static void
edma_bit_set(uint32_t * bits,unsigned int bit)234 edma_bit_set(uint32_t *bits, unsigned int bit)
235 {
236 bits[bit >> 5] |= (1 << (bit & 0x1f));
237 }
238
239 static void
edma_bit_clr(uint32_t * bits,unsigned int bit)240 edma_bit_clr(uint32_t *bits, unsigned int bit)
241 {
242 bits[bit >> 5] &= ~(1 << (bit & 0x1f));
243 }
244
245 static int
edma_intr(void * priv)246 edma_intr(void *priv)
247 {
248 struct edma_softc *sc = priv;
249 uint64_t ipr, ier;
250 int bit, idx;
251
252 ipr = EDMA_READ(sc, EDMA_IPR_REG);
253 ipr |= (uint64_t)EDMA_READ(sc, EDMA_IPRH_REG) << 32;
254 if (ipr == 0)
255 return 0;
256
257 ier = EDMA_READ(sc, EDMA_IER_REG);
258 ier |= (uint64_t)EDMA_READ(sc, EDMA_IERH_REG) << 32;
259
260 DPRINTF(2, (sc->sc_dev, "ipr = 0x%016llx ier 0x%016llx\n", ipr, ier));
261
262 EDMA_WRITE(sc, EDMA_ICR_REG, ipr & 0xffffffff);
263 EDMA_WRITE(sc, EDMA_ICRH_REG, ipr >> 32);
264
265 while ((bit = ffs64(ipr)) != 0) {
266 idx = bit - 1;
267 ipr &= ~__BIT(idx);
268 if (!(ier & __BIT(idx)))
269 continue;
270 if (!edma_bit_isset(sc->sc_dmamask, idx))
271 continue;
272
273 sc->sc_dma[idx].ch_callback(sc->sc_dma[idx].ch_callbackarg);
274 }
275
276 EDMA_WRITE(sc, EDMA_IEVAL_REG, EDMA_IEVAL_EVAL);
277
278 return 1;
279 }
280
281 /*
282 * Allocate a DMA channel. Currently only DMA types are supported, not QDMA.
283 * Returns NULL on failure.
284 */
285 struct edma_channel *
edma_channel_alloc(enum edma_type type,unsigned int drq,void (* cb)(void *),void * cbarg)286 edma_channel_alloc(enum edma_type type, unsigned int drq,
287 void (*cb)(void *), void *cbarg)
288 {
289 struct edma_softc *sc;
290 device_t dev;
291 struct edma_channel *ch = NULL;
292
293 KASSERT(drq < __arraycount(sc->sc_dma));
294 KASSERT(type == EDMA_TYPE_DMA); /* QDMA not implemented */
295 KASSERT(cb != NULL);
296 KASSERT(cbarg != NULL);
297
298 dev = device_find_by_driver_unit("tiedma", 0);
299 if (dev == NULL)
300 return NULL;
301 sc = device_private(dev);
302
303 mutex_enter(&sc->sc_lock);
304 if (!edma_bit_isset(sc->sc_dmamask, drq)) {
305 ch = &sc->sc_dma[drq];
306 KASSERT(ch->ch_callback == NULL);
307 KASSERT(ch->ch_index == drq);
308 ch->ch_callback = cb;
309 ch->ch_callbackarg = cbarg;
310 edma_bit_set(sc->sc_dmamask, drq);
311 }
312
313 if (ch == NULL)
314 goto done;
315
316 EDMA_WRITE(sc, EDMA_DRAE_REG(0), sc->sc_dmamask[0]);
317 EDMA_WRITE(sc, EDMA_DRAEH_REG(0), sc->sc_dmamask[1]);
318
319 if (ch->ch_index < 32) {
320 EDMA_WRITE(sc, EDMA_ICR_REG, __BIT(ch->ch_index));
321 EDMA_WRITE(sc, EDMA_IESR_REG, __BIT(ch->ch_index));
322 } else {
323 EDMA_WRITE(sc, EDMA_ICRH_REG, __BIT(ch->ch_index - 32));
324 EDMA_WRITE(sc, EDMA_IESRH_REG, __BIT(ch->ch_index - 32));
325 }
326
327 done:
328 mutex_exit(&sc->sc_lock);
329
330 return ch;
331 }
332
333 /*
334 * Free a DMA channel allocated with edma_channel_alloc
335 */
336 void
edma_channel_free(struct edma_channel * ch)337 edma_channel_free(struct edma_channel *ch)
338 {
339 struct edma_softc *sc = ch->ch_sc;
340
341 KASSERT(ch->ch_nparams == 0);
342
343 mutex_enter(&sc->sc_lock);
344 if (ch->ch_index < 32) {
345 EDMA_WRITE(sc, EDMA_IECR_REG, __BIT(ch->ch_index));
346 } else {
347 EDMA_WRITE(sc, EDMA_IECRH_REG, __BIT(ch->ch_index - 32));
348 }
349 ch->ch_callback = NULL;
350 ch->ch_callbackarg = NULL;
351 edma_bit_clr(sc->sc_dmamask, ch->ch_index);
352 mutex_exit(&sc->sc_lock);
353 }
354
355 /*
356 * Allocate a PaRAM entry. The driver artificially restricts the number
357 * of PaRAM entries available for each channel to MAX_PARAM_PER_CHANNEL.
358 * If the number of entries for the channel has been exceeded, or there
359 * are no entries available, 0xffff is returned.
360 */
361 uint16_t
edma_param_alloc(struct edma_channel * ch)362 edma_param_alloc(struct edma_channel *ch)
363 {
364 struct edma_softc *sc = ch->ch_sc;
365 uint16_t param_entry = 0xffff;
366 int idx;
367
368 if (ch->ch_nparams == MAX_PARAM_PER_CHANNEL)
369 return param_entry;
370
371 mutex_enter(&sc->sc_lock);
372 for (idx = 0; idx < NUM_PARAM_SETS; idx++) {
373 if (!edma_bit_isset(sc->sc_parammask, idx)) {
374 param_entry = idx;
375 edma_bit_set(sc->sc_parammask, idx);
376 ch->ch_nparams++;
377 break;
378 }
379 }
380 mutex_exit(&sc->sc_lock);
381
382 return param_entry;
383 }
384
385 /*
386 * Free a PaRAM entry allocated with edma_param_alloc
387 */
388 void
edma_param_free(struct edma_channel * ch,uint16_t param_entry)389 edma_param_free(struct edma_channel *ch, uint16_t param_entry)
390 {
391 struct edma_softc *sc = ch->ch_sc;
392
393 KASSERT(param_entry < NUM_PARAM_SETS);
394 KASSERT(ch->ch_nparams > 0);
395 KASSERT(edma_bit_isset(sc->sc_parammask, param_entry));
396
397 mutex_enter(&sc->sc_lock);
398 edma_bit_clr(sc->sc_parammask, param_entry);
399 ch->ch_nparams--;
400 mutex_exit(&sc->sc_lock);
401 }
402
403 /*
404 * Update a PaRAM entry register set with caller-provided values
405 */
406 void
edma_set_param(struct edma_channel * ch,uint16_t param_entry,struct edma_param * ep)407 edma_set_param(struct edma_channel *ch, uint16_t param_entry,
408 struct edma_param *ep)
409 {
410 struct edma_softc *sc = ch->ch_sc;
411
412 KASSERT(param_entry < NUM_PARAM_SETS);
413 KASSERT(ch->ch_nparams > 0);
414 KASSERT(edma_bit_isset(sc->sc_parammask, param_entry));
415
416 DPRINTF(1, (sc->sc_dev, "write param entry ch# %d pe %d: 0x%08x -> 0x%08x (%u, %u, %u)\n", ch->ch_index, param_entry, ep->ep_src, ep->ep_dst, ep->ep_acnt, ep->ep_bcnt, ep->ep_ccnt));
417 edma_write_param(sc, param_entry, ep);
418 }
419
420 /*
421 * Enable a DMA channel: Point channel to the PaRam entry,
422 * clear error if any, and only set the Event Enable bit.
423 * The Even will either be generated by hardware, or with
424 * edma_transfer_start()
425 */
426 int
edma_transfer_enable(struct edma_channel * ch,uint16_t param_entry)427 edma_transfer_enable(struct edma_channel *ch, uint16_t param_entry)
428 {
429 struct edma_softc *sc = ch->ch_sc;
430 bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
431 uint32_t bit = __BIT(ch->ch_index < 32 ?
432 ch->ch_index : ch->ch_index - 32);
433
434 DPRINTF(1, (sc->sc_dev, "enable transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit, param_entry));
435
436 EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index),
437 __SHIFTIN(param_entry, EDMA_DCHMAP_PAENTRY));
438
439 uint32_t ccerr = EDMA_READ(sc, EDMA_CCERR_REG);
440 if (ccerr) {
441 device_printf(sc->sc_dev, " !!! CCER %08x\n", ccerr);
442 EDMA_WRITE(sc, EDMA_CCERRCLR_REG, ccerr);
443 }
444
445 EDMA_WRITE(sc, EDMA_EESR_REG + off, bit);
446 return 0;
447 }
448
449 /*
450 * Software-start a DMA channel: Set the Event bit.
451 */
452 int
edma_transfer_start(struct edma_channel * ch)453 edma_transfer_start(struct edma_channel *ch)
454 {
455 struct edma_softc *sc = ch->ch_sc;
456 bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
457 uint32_t bit = __BIT(ch->ch_index < 32 ?
458 ch->ch_index : ch->ch_index - 32);
459
460 DPRINTF(1, (sc->sc_dev, "start transfer ch# %d off %d bit %x pe %d\n", ch->ch_index, (int)off, bit));
461
462 EDMA_WRITE(sc, EDMA_ESR_REG + off, bit);
463 return 0;
464 }
465
466 /*
467 * Halt a DMA transfer. Called after successful transfer, or to abort
468 * a transfer.
469 */
470 void
edma_halt(struct edma_channel * ch)471 edma_halt(struct edma_channel *ch)
472 {
473 struct edma_softc *sc = ch->ch_sc;
474 bus_size_t off = (ch->ch_index < 32 ? 0 : 4);
475 uint32_t bit = __BIT(ch->ch_index < 32 ?
476 ch->ch_index : ch->ch_index - 32);
477
478 EDMA_WRITE(sc, EDMA_EECR_REG + off, bit);
479 EDMA_WRITE(sc, EDMA_ECR_REG + off, bit);
480 EDMA_WRITE(sc, EDMA_SECR_REG + off, bit);
481 EDMA_WRITE(sc, EDMA_EMCR_REG + off, bit);
482
483 EDMA_WRITE(sc, EDMA_DCHMAP_REG(ch->ch_index),
484 __SHIFTIN(0, EDMA_DCHMAP_PAENTRY));
485 }
486
487 uint8_t
edma_channel_index(struct edma_channel * ch)488 edma_channel_index(struct edma_channel *ch)
489 {
490 return ch->ch_index;
491 }
492
493 void
edma_dump(struct edma_channel * ch)494 edma_dump(struct edma_channel *ch)
495 {
496 static const struct {
497 const char *name;
498 uint16_t off;
499 } regs[] = {
500 { "ER", EDMA_ER_REG },
501 { "ERH", EDMA_ERH_REG },
502 { "EER", EDMA_EER_REG },
503 { "EERH", EDMA_EERH_REG },
504 { "SER", EDMA_SER_REG },
505 { "SERH", EDMA_SERH_REG },
506 { "IER", EDMA_IER_REG },
507 { "IERH", EDMA_IERH_REG },
508 { "IPR", EDMA_IPR_REG },
509 { "IPRH", EDMA_IPRH_REG },
510 { "CCERR", EDMA_CCERR_REG },
511 { "CCSTAT", EDMA_CCSTAT_REG },
512 { "DRAE0", EDMA_DRAE_REG(0) },
513 { "DRAEH0", EDMA_DRAEH_REG(0) },
514 { NULL, 0 }
515 };
516 struct edma_softc *sc = ch->ch_sc;
517 int i;
518
519 for (i = 0; regs[i].name; i++) {
520 device_printf(sc->sc_dev, "%s: %08x\n",
521 regs[i].name, EDMA_READ(sc, regs[i].off));
522 }
523 device_printf(sc->sc_dev, "DCHMAP%d: %08x\n", ch->ch_index,
524 EDMA_READ(sc, EDMA_DCHMAP_REG(ch->ch_index)));
525 }
526
527 void
edma_dump_param(struct edma_channel * ch,uint16_t param_entry)528 edma_dump_param(struct edma_channel *ch, uint16_t param_entry)
529 {
530 struct {
531 const char *name;
532 uint16_t off;
533 } regs[] = {
534 { "OPT", EDMA_PARAM_OPT_REG(param_entry) },
535 { "CNT", EDMA_PARAM_CNT_REG(param_entry) },
536 { "DST", EDMA_PARAM_DST_REG(param_entry) },
537 { "BIDX", EDMA_PARAM_BIDX_REG(param_entry) },
538 { "LNK", EDMA_PARAM_LNK_REG(param_entry) },
539 { "CIDX", EDMA_PARAM_CIDX_REG(param_entry) },
540 { "CCNT", EDMA_PARAM_CCNT_REG(param_entry) },
541 { NULL, 0 }
542 };
543 struct edma_softc *sc = ch->ch_sc;
544 int i;
545
546 for (i = 0; regs[i].name; i++) {
547 device_printf(sc->sc_dev, "%s%d: %08x\n",
548 regs[i].name, param_entry, EDMA_READ(sc, regs[i].off));
549 }
550 }
551