xref: /freebsd-13-stable/sys/mips/ingenic/jz4780_pdma.c (revision 3bc80996974a61a4223eae4c1ccd47b6ee32a48a)
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