1 /*-
2 * Copyright (c) 2016-2018 Ruslan Bukin <br@bsdpad.com>
3 * All rights reserved.
4 *
5 * This software was developed by SRI International and the University of
6 * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7 * ("CTSRD"), as part of the DARPA CRASH research programme.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 /* Ingenic JZ4780 PDMA Controller. */
32
33 #include <sys/cdefs.h>
34 #include "opt_platform.h"
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/lock.h>
42 #include <sys/mutex.h>
43 #include <sys/resource.h>
44 #include <sys/rman.h>
45
46 #include <machine/bus.h>
47 #include <machine/cache.h>
48
49 #ifdef FDT
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53 #endif
54
55 #include <dev/xdma/xdma.h>
56
57 #include <mips/ingenic/jz4780_common.h>
58 #include <mips/ingenic/jz4780_pdma.h>
59
60 #include "xdma_if.h"
61
62 #define PDMA_DEBUG
63 #undef PDMA_DEBUG
64
65 #ifdef PDMA_DEBUG
66 #define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
67 #else
68 #define dprintf(fmt, ...)
69 #endif
70
71 #define PDMA_DESC_RING_ALIGN 2048
72
73 struct pdma_softc {
74 device_t dev;
75 struct resource *res[2];
76 bus_space_tag_t bst;
77 bus_space_handle_t bsh;
78 void *ih;
79 };
80
81 struct pdma_fdt_data {
82 int tx;
83 int rx;
84 int chan;
85 };
86
87 struct pdma_channel {
88 struct pdma_fdt_data data;
89 int cur_desc;
90 int used;
91 int index;
92 int flags;
93 #define CHAN_DESCR_RELINK (1 << 0)
94
95 /* Descriptors */
96 bus_dma_tag_t desc_tag;
97 bus_dmamap_t desc_map;
98 struct pdma_hwdesc *desc_ring;
99 bus_addr_t desc_ring_paddr;
100
101 /* xDMA */
102 xdma_channel_t *xchan;
103 struct xdma_request *req;
104 };
105
106 #define PDMA_NCHANNELS 32
107 struct pdma_channel pdma_channels[PDMA_NCHANNELS];
108
109 static struct resource_spec pdma_spec[] = {
110 { SYS_RES_MEMORY, 0, RF_ACTIVE },
111 { SYS_RES_IRQ, 0, RF_ACTIVE },
112 { -1, 0 }
113 };
114
115 static int pdma_probe(device_t dev);
116 static int pdma_attach(device_t dev);
117 static int pdma_detach(device_t dev);
118 static int chan_start(struct pdma_softc *sc, struct pdma_channel *chan);
119
120 static void
pdma_intr(void * arg)121 pdma_intr(void *arg)
122 {
123 struct xdma_request *req;
124 xdma_transfer_status_t status;
125 struct pdma_channel *chan;
126 struct pdma_softc *sc;
127 xdma_channel_t *xchan;
128 int pending;
129 int i;
130
131 sc = arg;
132
133 pending = READ4(sc, PDMA_DIRQP);
134
135 /* Ack all the channels. */
136 WRITE4(sc, PDMA_DIRQP, 0);
137
138 for (i = 0; i < PDMA_NCHANNELS; i++) {
139 if (pending & (1 << i)) {
140 chan = &pdma_channels[i];
141 xchan = chan->xchan;
142 req = chan->req;
143
144 /* TODO: check for AR, HLT error bits here. */
145
146 /* Disable channel */
147 WRITE4(sc, PDMA_DCS(chan->index), 0);
148
149 if (chan->flags & CHAN_DESCR_RELINK) {
150 /* Enable again */
151 chan->cur_desc = (chan->cur_desc + 1) % \
152 req->block_num;
153 chan_start(sc, chan);
154 }
155
156 status.error = 0;
157 xdma_callback(chan->xchan, &status);
158 }
159 }
160 }
161
162 static int
pdma_probe(device_t dev)163 pdma_probe(device_t dev)
164 {
165
166 if (!ofw_bus_status_okay(dev))
167 return (ENXIO);
168
169 if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-dma"))
170 return (ENXIO);
171
172 device_set_desc(dev, "Ingenic JZ4780 PDMA Controller");
173
174 return (BUS_PROBE_DEFAULT);
175 }
176
177 static int
pdma_attach(device_t dev)178 pdma_attach(device_t dev)
179 {
180 struct pdma_softc *sc;
181 phandle_t xref, node;
182 int err;
183 int reg;
184
185 sc = device_get_softc(dev);
186 sc->dev = dev;
187
188 if (bus_alloc_resources(dev, pdma_spec, sc->res)) {
189 device_printf(dev, "could not allocate resources for device\n");
190 return (ENXIO);
191 }
192
193 /* Memory interface */
194 sc->bst = rman_get_bustag(sc->res[0]);
195 sc->bsh = rman_get_bushandle(sc->res[0]);
196
197 /* Setup interrupt handler */
198 err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
199 NULL, pdma_intr, sc, &sc->ih);
200 if (err) {
201 device_printf(dev, "Unable to alloc interrupt resource.\n");
202 return (ENXIO);
203 }
204
205 node = ofw_bus_get_node(dev);
206 xref = OF_xref_from_node(node);
207 OF_device_register_xref(xref, dev);
208
209 reg = READ4(sc, PDMA_DMAC);
210 reg &= ~(DMAC_HLT | DMAC_AR);
211 reg |= (DMAC_DMAE);
212 WRITE4(sc, PDMA_DMAC, reg);
213
214 WRITE4(sc, PDMA_DMACP, 0);
215
216 return (0);
217 }
218
219 static int
pdma_detach(device_t dev)220 pdma_detach(device_t dev)
221 {
222 struct pdma_softc *sc;
223
224 sc = device_get_softc(dev);
225
226 bus_release_resources(dev, pdma_spec, sc->res);
227
228 return (0);
229 }
230
231 static int
chan_start(struct pdma_softc * sc,struct pdma_channel * chan)232 chan_start(struct pdma_softc *sc, struct pdma_channel *chan)
233 {
234 struct xdma_channel *xchan;
235
236 xchan = chan->xchan;
237
238 /* 8 byte descriptor. */
239 WRITE4(sc, PDMA_DCS(chan->index), DCS_DES8);
240 WRITE4(sc, PDMA_DDA(chan->index),
241 chan->desc_ring_paddr + 8 * 4 * chan->cur_desc);
242
243 WRITE4(sc, PDMA_DDS, (1 << chan->index));
244
245 /* Channel transfer enable. */
246 WRITE4(sc, PDMA_DCS(chan->index), (DCS_DES8 | DCS_CTE));
247
248 return (0);
249 }
250
251 static int
chan_stop(struct pdma_softc * sc,struct pdma_channel * chan)252 chan_stop(struct pdma_softc *sc, struct pdma_channel *chan)
253 {
254 int timeout;
255
256 WRITE4(sc, PDMA_DCS(chan->index), 0);
257
258 timeout = 100;
259
260 do {
261 if ((READ4(sc, PDMA_DCS(chan->index)) & DCS_CTE) == 0) {
262 break;
263 }
264 } while (timeout--);
265
266 if (timeout == 0) {
267 device_printf(sc->dev, "%s: Can't stop channel %d\n",
268 __func__, chan->index);
269 }
270
271 return (0);
272 }
273
274 static void
dwc_get1paddr(void * arg,bus_dma_segment_t * segs,int nsegs,int error)275 dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
276 {
277
278 if (error != 0)
279 return;
280 *(bus_addr_t *)arg = segs[0].ds_addr;
281 }
282
283 static int
pdma_channel_setup_descriptors(device_t dev,struct pdma_channel * chan)284 pdma_channel_setup_descriptors(device_t dev, struct pdma_channel *chan)
285 {
286 struct pdma_softc *sc;
287 int error;
288
289 sc = device_get_softc(dev);
290
291 /*
292 * Set up TX descriptor ring, descriptors, and dma maps.
293 */
294 error = bus_dma_tag_create(
295 bus_get_dma_tag(sc->dev), /* Parent tag. */
296 PDMA_DESC_RING_ALIGN, 0, /* alignment, boundary */
297 BUS_SPACE_MAXADDR_32BIT, /* lowaddr */
298 BUS_SPACE_MAXADDR, /* highaddr */
299 NULL, NULL, /* filter, filterarg */
300 CHAN_DESC_SIZE, 1, /* maxsize, nsegments */
301 CHAN_DESC_SIZE, /* maxsegsize */
302 0, /* flags */
303 NULL, NULL, /* lockfunc, lockarg */
304 &chan->desc_tag);
305 if (error != 0) {
306 device_printf(sc->dev,
307 "could not create TX ring DMA tag.\n");
308 return (-1);
309 }
310
311 error = bus_dmamem_alloc(chan->desc_tag, (void**)&chan->desc_ring,
312 BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
313 &chan->desc_map);
314 if (error != 0) {
315 device_printf(sc->dev,
316 "could not allocate TX descriptor ring.\n");
317 return (-1);
318 }
319
320 error = bus_dmamap_load(chan->desc_tag, chan->desc_map,
321 chan->desc_ring, CHAN_DESC_SIZE, dwc_get1paddr,
322 &chan->desc_ring_paddr, 0);
323 if (error != 0) {
324 device_printf(sc->dev,
325 "could not load TX descriptor ring map.\n");
326 return (-1);
327 }
328
329 return (0);
330 }
331
332 static int
pdma_channel_alloc(device_t dev,struct xdma_channel * xchan)333 pdma_channel_alloc(device_t dev, struct xdma_channel *xchan)
334 {
335 struct pdma_channel *chan;
336 struct pdma_softc *sc;
337 int i;
338
339 sc = device_get_softc(dev);
340
341 for (i = 0; i < PDMA_NCHANNELS; i++) {
342 chan = &pdma_channels[i];
343 if (chan->used == 0) {
344 chan->xchan = xchan;
345 xchan->chan = (void *)chan;
346 chan->used = 1;
347 chan->index = i;
348
349 pdma_channel_setup_descriptors(dev, chan);
350
351 return (0);
352 }
353 }
354
355 return (-1);
356 }
357
358 static int
pdma_channel_free(device_t dev,struct xdma_channel * xchan)359 pdma_channel_free(device_t dev, struct xdma_channel *xchan)
360 {
361 struct pdma_channel *chan;
362 struct pdma_softc *sc;
363
364 sc = device_get_softc(dev);
365
366 chan = (struct pdma_channel *)xchan->chan;
367 chan->used = 0;
368
369 return (0);
370 }
371
372 static int
access_width(struct xdma_request * req,uint32_t * dcm,uint32_t * max_width)373 access_width(struct xdma_request *req, uint32_t *dcm, uint32_t *max_width)
374 {
375
376 *dcm = 0;
377 *max_width = max(req->src_width, req->dst_width);
378
379 switch (req->src_width) {
380 case 1:
381 *dcm |= DCM_SP_1;
382 break;
383 case 2:
384 *dcm |= DCM_SP_2;
385 break;
386 case 4:
387 *dcm |= DCM_SP_4;
388 break;
389 default:
390 return (-1);
391 }
392
393 switch (req->dst_width) {
394 case 1:
395 *dcm |= DCM_DP_1;
396 break;
397 case 2:
398 *dcm |= DCM_DP_2;
399 break;
400 case 4:
401 *dcm |= DCM_DP_4;
402 break;
403 default:
404 return (-1);
405 }
406
407 switch (*max_width) {
408 case 1:
409 *dcm |= DCM_TSZ_1;
410 break;
411 case 2:
412 *dcm |= DCM_TSZ_2;
413 break;
414 case 4:
415 *dcm |= DCM_TSZ_4;
416 break;
417 default:
418 return (-1);
419 };
420
421 return (0);
422 }
423
424 static int
pdma_channel_request(device_t dev,struct xdma_channel * xchan,struct xdma_request * req)425 pdma_channel_request(device_t dev, struct xdma_channel *xchan, struct xdma_request *req)
426 {
427 struct pdma_fdt_data *data;
428 struct pdma_channel *chan;
429 struct pdma_hwdesc *desc;
430 xdma_controller_t *xdma;
431 struct pdma_softc *sc;
432 int max_width;
433 uint32_t reg;
434 uint32_t dcm;
435 int i;
436
437 sc = device_get_softc(dev);
438
439 dprintf("%s: block_len %d block_num %d\n",
440 __func__, req->block_len, req->block_num);
441
442 xdma = xchan->xdma;
443 data = (struct pdma_fdt_data *)xdma->data;
444
445 chan = (struct pdma_channel *)xchan->chan;
446 /* Ensure we are not in operation */
447 chan_stop(sc, chan);
448 if (req->operation == XDMA_CYCLIC)
449 chan->flags = CHAN_DESCR_RELINK;
450 chan->cur_desc = 0;
451 chan->req = req;
452
453 for (i = 0; i < req->block_num; i++) {
454 desc = &chan->desc_ring[i];
455
456 if (req->direction == XDMA_MEM_TO_DEV) {
457 desc->dsa = req->src_addr + (i * req->block_len);
458 desc->dta = req->dst_addr;
459 desc->drt = data->tx;
460 desc->dcm = DCM_SAI;
461 } else if (req->direction == XDMA_DEV_TO_MEM) {
462 desc->dsa = req->src_addr;
463 desc->dta = req->dst_addr + (i * req->block_len);
464 desc->drt = data->rx;
465 desc->dcm = DCM_DAI;
466 } else if (req->direction == XDMA_MEM_TO_MEM) {
467 desc->dsa = req->src_addr + (i * req->block_len);
468 desc->dta = req->dst_addr + (i * req->block_len);
469 desc->drt = DRT_AUTO;
470 desc->dcm = DCM_SAI | DCM_DAI;
471 }
472
473 if (access_width(req, &dcm, &max_width) != 0) {
474 device_printf(dev,
475 "%s: can't configure access width\n", __func__);
476 return (-1);
477 }
478
479 desc->dcm |= dcm | DCM_TIE;
480 desc->dtc = (req->block_len / max_width);
481
482 /*
483 * TODO: bus dma pre read/write sync here
484 */
485
486 /*
487 * PDMA does not provide interrupt after processing each descriptor,
488 * but after processing all the chain only.
489 * As a workaround we do unlink descriptors here, so our chain will
490 * consists of single descriptor only. And then we reconfigure channel
491 * on each interrupt again.
492 */
493 if ((chan->flags & CHAN_DESCR_RELINK) == 0) {
494 if (i != (req->block_num - 1)) {
495 desc->dcm |= DCM_LINK;
496 reg = ((i + 1) * sizeof(struct pdma_hwdesc));
497 desc->dtc |= (reg >> 4) << 24;
498 }
499 }
500 }
501
502 return (0);
503 }
504
505 static int
pdma_channel_control(device_t dev,xdma_channel_t * xchan,int cmd)506 pdma_channel_control(device_t dev, xdma_channel_t *xchan, int cmd)
507 {
508 struct pdma_channel *chan;
509 struct pdma_softc *sc;
510
511 sc = device_get_softc(dev);
512
513 chan = (struct pdma_channel *)xchan->chan;
514
515 switch (cmd) {
516 case XDMA_CMD_BEGIN:
517 chan_start(sc, chan);
518 break;
519 case XDMA_CMD_TERMINATE:
520 chan_stop(sc, chan);
521 break;
522 case XDMA_CMD_PAUSE:
523 /* TODO: implement me */
524 return (-1);
525 }
526
527 return (0);
528 }
529
530 #ifdef FDT
531 static int
pdma_ofw_md_data(device_t dev,pcell_t * cells,int ncells,void ** ptr)532 pdma_ofw_md_data(device_t dev, pcell_t *cells, int ncells, void **ptr)
533 {
534 struct pdma_fdt_data *data;
535
536 if (ncells != 3) {
537 return (-1);
538 }
539
540 data = malloc(sizeof(struct pdma_fdt_data), M_DEVBUF, (M_WAITOK | M_ZERO));
541 if (data == NULL) {
542 device_printf(dev, "%s: Cant allocate memory\n", __func__);
543 return (-1);
544 }
545
546 data->tx = cells[0];
547 data->rx = cells[1];
548 data->chan = cells[2];
549
550 *ptr = data;
551
552 return (0);
553 }
554 #endif
555
556 static device_method_t pdma_methods[] = {
557 /* Device interface */
558 DEVMETHOD(device_probe, pdma_probe),
559 DEVMETHOD(device_attach, pdma_attach),
560 DEVMETHOD(device_detach, pdma_detach),
561
562 /* xDMA Interface */
563 DEVMETHOD(xdma_channel_alloc, pdma_channel_alloc),
564 DEVMETHOD(xdma_channel_free, pdma_channel_free),
565 DEVMETHOD(xdma_channel_request, pdma_channel_request),
566 DEVMETHOD(xdma_channel_control, pdma_channel_control),
567 #ifdef FDT
568 DEVMETHOD(xdma_ofw_md_data, pdma_ofw_md_data),
569 #endif
570
571 DEVMETHOD_END
572 };
573
574 static driver_t pdma_driver = {
575 "pdma",
576 pdma_methods,
577 sizeof(struct pdma_softc),
578 };
579
580 static devclass_t pdma_devclass;
581
582 EARLY_DRIVER_MODULE(pdma, simplebus, pdma_driver, pdma_devclass, 0, 0,
583 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE);
584