xref: /freebsd/sys/dev/usb/controller/musb_otg_allwinner.c (revision d7abf6e73ce4638b56923912785fb951f4c50987)
1 /*-
2  * Copyright (c) 2016 Jared McNeill <jmcneill@invisible.ca>
3  * Copyright (c) 2018 Andrew Turner <andrew@FreeBSD.org>
4  * All rights reserved.
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33 
34 /*
35  * Allwinner USB Dual-Role Device (DRD) controller
36  */
37 
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/bus.h>
44 #include <sys/rman.h>
45 #include <sys/kernel.h>
46 #include <sys/condvar.h>
47 #include <sys/module.h>
48 #include <machine/bus.h>
49 
50 #include <dev/ofw/ofw_bus.h>
51 #include <dev/ofw/ofw_bus_subr.h>
52 
53 #include <dev/usb/usb.h>
54 #include <dev/usb/usbdi.h>
55 
56 #include <dev/usb/usb_core.h>
57 #include <dev/usb/usb_busdma.h>
58 #include <dev/usb/usb_process.h>
59 #include <dev/usb/usb_util.h>
60 
61 #include <dev/usb/usb_controller.h>
62 #include <dev/usb/usb_bus.h>
63 #include <dev/usb/controller/musb_otg.h>
64 
65 #include <dev/extres/clk/clk.h>
66 #include <dev/extres/hwreset/hwreset.h>
67 
68 #ifdef __arm__
69 #include <arm/allwinner/aw_machdep.h>
70 #include <arm/allwinner/a10_sramc.h>
71 #endif
72 
73 #define	DRD_EP_MAX		5
74 
75 #define	MUSB2_REG_AWIN_VEND0	0x0043
76 #define	VEND0_PIO_MODE		0
77 
78 #if defined(__arm__)
79 #define	bs_parent_space(bs)	((bs)->bs_parent)
80 typedef bus_space_tag_t	awusb_bs_tag;
81 #elif defined(__aarch64__)
82 #define	bs_parent_space(bs)	(bs)
83 typedef void *		awusb_bs_tag;
84 #endif
85 
86 #define	AWUSB_OKAY		0x01
87 #define	AWUSB_NO_CONFDATA	0x02
88 static struct ofw_compat_data compat_data[] = {
89 	{ "allwinner,sun4i-a10-musb",	AWUSB_OKAY },
90 	{ "allwinner,sun6i-a31-musb",	AWUSB_OKAY },
91 	{ "allwinner,sun8i-a33-musb",	AWUSB_OKAY | AWUSB_NO_CONFDATA },
92 	{ NULL,				0 }
93 };
94 
95 static const struct musb_otg_ep_cfg musbotg_ep_allwinner[] = {
96 	{
97 		.ep_end = 5,
98 		.ep_fifosz_shift = 9,
99 		.ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512,
100 	},
101 	{
102 		.ep_end = -1,
103 	},
104 };
105 
106 struct awusbdrd_softc {
107 	struct musbotg_softc	sc;
108 	struct resource		*res[2];
109 	clk_t			clk;
110 	hwreset_t		reset;
111 	struct bus_space	bs;
112 	int			flags;
113 };
114 
115 static struct resource_spec awusbdrd_spec[] = {
116 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
117 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
118 	{ -1, 0 }
119 };
120 
121 #define	REMAPFLAG	0x8000
122 #define	REGDECL(a, b)	[(a)] = ((b) | REMAPFLAG)
123 
124 /* Allwinner USB DRD register mappings */
125 static const uint16_t awusbdrd_regmap[] = {
126 	REGDECL(MUSB2_REG_EPFIFO(0),	0x0000),
127 	REGDECL(MUSB2_REG_EPFIFO(1),	0x0004),
128 	REGDECL(MUSB2_REG_EPFIFO(2),	0x0008),
129 	REGDECL(MUSB2_REG_EPFIFO(3),	0x000c),
130 	REGDECL(MUSB2_REG_EPFIFO(4),	0x0010),
131 	REGDECL(MUSB2_REG_EPFIFO(5),	0x0014),
132 	REGDECL(MUSB2_REG_POWER,	0x0040),
133 	REGDECL(MUSB2_REG_DEVCTL,	0x0041),
134 	REGDECL(MUSB2_REG_EPINDEX,	0x0042),
135 	REGDECL(MUSB2_REG_INTTX,	0x0044),
136 	REGDECL(MUSB2_REG_INTRX,	0x0046),
137 	REGDECL(MUSB2_REG_INTTXE,	0x0048),
138 	REGDECL(MUSB2_REG_INTRXE,	0x004a),
139 	REGDECL(MUSB2_REG_INTUSB,	0x004c),
140 	REGDECL(MUSB2_REG_INTUSBE,	0x0050),
141 	REGDECL(MUSB2_REG_FRAME,	0x0054),
142 	REGDECL(MUSB2_REG_TESTMODE,	0x007c),
143 	REGDECL(MUSB2_REG_TXMAXP,	0x0080),
144 	REGDECL(MUSB2_REG_TXCSRL,	0x0082),
145 	REGDECL(MUSB2_REG_TXCSRH,	0x0083),
146 	REGDECL(MUSB2_REG_RXMAXP,	0x0084),
147 	REGDECL(MUSB2_REG_RXCSRL,	0x0086),
148 	REGDECL(MUSB2_REG_RXCSRH,	0x0087),
149 	REGDECL(MUSB2_REG_RXCOUNT,	0x0088),
150 	REGDECL(MUSB2_REG_TXTI,		0x008c),
151 	REGDECL(MUSB2_REG_TXNAKLIMIT,	0x008d),
152 	REGDECL(MUSB2_REG_RXNAKLIMIT,	0x008f),
153 	REGDECL(MUSB2_REG_RXTI,		0x008e),
154 	REGDECL(MUSB2_REG_TXFIFOSZ,	0x0090),
155 	REGDECL(MUSB2_REG_TXFIFOADD,	0x0092),
156 	REGDECL(MUSB2_REG_RXFIFOSZ,	0x0094),
157 	REGDECL(MUSB2_REG_RXFIFOADD,	0x0096),
158 	REGDECL(MUSB2_REG_FADDR,	0x0098),
159 	REGDECL(MUSB2_REG_TXFADDR(0),	0x0098),
160 	REGDECL(MUSB2_REG_TXHADDR(0),	0x009a),
161 	REGDECL(MUSB2_REG_TXHUBPORT(0),	0x009b),
162 	REGDECL(MUSB2_REG_RXFADDR(0),	0x009c),
163 	REGDECL(MUSB2_REG_RXHADDR(0),	0x009e),
164 	REGDECL(MUSB2_REG_RXHUBPORT(0),	0x009f),
165 	REGDECL(MUSB2_REG_TXFADDR(1),	0x0098),
166 	REGDECL(MUSB2_REG_TXHADDR(1),	0x009a),
167 	REGDECL(MUSB2_REG_TXHUBPORT(1),	0x009b),
168 	REGDECL(MUSB2_REG_RXFADDR(1),	0x009c),
169 	REGDECL(MUSB2_REG_RXHADDR(1),	0x009e),
170 	REGDECL(MUSB2_REG_RXHUBPORT(1),	0x009f),
171 	REGDECL(MUSB2_REG_TXFADDR(2),	0x0098),
172 	REGDECL(MUSB2_REG_TXHADDR(2),	0x009a),
173 	REGDECL(MUSB2_REG_TXHUBPORT(2),	0x009b),
174 	REGDECL(MUSB2_REG_RXFADDR(2),	0x009c),
175 	REGDECL(MUSB2_REG_RXHADDR(2),	0x009e),
176 	REGDECL(MUSB2_REG_RXHUBPORT(2),	0x009f),
177 	REGDECL(MUSB2_REG_TXFADDR(3),	0x0098),
178 	REGDECL(MUSB2_REG_TXHADDR(3),	0x009a),
179 	REGDECL(MUSB2_REG_TXHUBPORT(3),	0x009b),
180 	REGDECL(MUSB2_REG_RXFADDR(3),	0x009c),
181 	REGDECL(MUSB2_REG_RXHADDR(3),	0x009e),
182 	REGDECL(MUSB2_REG_RXHUBPORT(3),	0x009f),
183 	REGDECL(MUSB2_REG_TXFADDR(4),	0x0098),
184 	REGDECL(MUSB2_REG_TXHADDR(4),	0x009a),
185 	REGDECL(MUSB2_REG_TXHUBPORT(4),	0x009b),
186 	REGDECL(MUSB2_REG_RXFADDR(4),	0x009c),
187 	REGDECL(MUSB2_REG_RXHADDR(4),	0x009e),
188 	REGDECL(MUSB2_REG_RXHUBPORT(4),	0x009f),
189 	REGDECL(MUSB2_REG_TXFADDR(5),	0x0098),
190 	REGDECL(MUSB2_REG_TXHADDR(5),	0x009a),
191 	REGDECL(MUSB2_REG_TXHUBPORT(5),	0x009b),
192 	REGDECL(MUSB2_REG_RXFADDR(5),	0x009c),
193 	REGDECL(MUSB2_REG_RXHADDR(5),	0x009e),
194 	REGDECL(MUSB2_REG_RXHUBPORT(5),	0x009f),
195 	REGDECL(MUSB2_REG_CONFDATA,	0x00c0),
196 };
197 
198 static bus_size_t
199 awusbdrd_reg(bus_size_t o)
200 {
201 	bus_size_t v;
202 
203 	KASSERT(o < nitems(awusbdrd_regmap),
204 	    ("%s: Invalid register %#lx", __func__, o));
205 	if (o >= nitems(awusbdrd_regmap))
206 		return (o);
207 
208 	v = awusbdrd_regmap[o];
209 
210 	KASSERT((v & REMAPFLAG) != 0, ("%s: reg %#lx not in regmap",
211 	    __func__, o));
212 
213 	return (v & ~REMAPFLAG);
214 }
215 
216 static int
217 awusbdrd_filt(bus_size_t o)
218 {
219 	switch (o) {
220 	case MUSB2_REG_MISC:
221 	case MUSB2_REG_RXDBDIS:
222 	case MUSB2_REG_TXDBDIS:
223 		return (1);
224 	default:
225 		return (0);
226 	}
227 }
228 
229 static uint8_t
230 awusbdrd_bs_r_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
231 {
232 	const struct bus_space *bs = t;
233 
234 	switch (o) {
235 	case MUSB2_REG_HWVERS:
236 		return (0);	/* no known equivalent */
237 	}
238 
239 	return (bus_space_read_1(bs_parent_space(bs), h, awusbdrd_reg(o)));
240 }
241 
242 static uint8_t
243 awusbdrd_bs_r_1_noconf(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
244 {
245 
246 	/*
247 	 * There is no confdata register on some SoCs, return the same
248 	 * magic value as Linux.
249 	 */
250 	if (o == MUSB2_REG_CONFDATA)
251 		return (0xde);
252 
253 	return (awusbdrd_bs_r_1(t, h, o));
254 }
255 
256 
257 static uint16_t
258 awusbdrd_bs_r_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
259 {
260 	const struct bus_space *bs = t;
261 
262 	if (awusbdrd_filt(o) != 0)
263 		return (0);
264 	return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o));
265 }
266 
267 static void
268 awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
269     uint8_t v)
270 {
271 	const struct bus_space *bs = t;
272 
273 	if (awusbdrd_filt(o) != 0)
274 		return;
275 
276 	bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v);
277 }
278 
279 static void
280 awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
281     uint16_t v)
282 {
283 	const struct bus_space *bs = t;
284 
285 	if (awusbdrd_filt(o) != 0)
286 		return;
287 
288 	bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v);
289 }
290 
291 static void
292 awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
293     uint8_t *d, bus_size_t c)
294 {
295 	const struct bus_space *bs = t;
296 
297 	bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
298 }
299 
300 static void
301 awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
302     uint32_t *d, bus_size_t c)
303 {
304 	const struct bus_space *bs = t;
305 
306 	bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
307 }
308 
309 static void
310 awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
311     const uint8_t *d, bus_size_t c)
312 {
313 	const struct bus_space *bs = t;
314 
315 	if (awusbdrd_filt(o) != 0)
316 		return;
317 
318 	bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
319 }
320 
321 static void
322 awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
323     const uint32_t *d, bus_size_t c)
324 {
325 	const struct bus_space *bs = t;
326 
327 	if (awusbdrd_filt(o) != 0)
328 		return;
329 
330 	bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
331 }
332 
333 static void
334 awusbdrd_intr(void *arg)
335 {
336 	struct awusbdrd_softc *sc = arg;
337 	uint8_t intusb;
338 	uint16_t inttx, intrx;
339 
340 	intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB);
341 	inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX);
342 	intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX);
343 	if (intusb == 0 && inttx == 0 && intrx == 0)
344 		return;
345 
346 	if (intusb)
347 		MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb);
348 	if (inttx)
349 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx);
350 	if (intrx)
351 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx);
352 
353 	musbotg_interrupt(arg, intrx, inttx, intusb);
354 }
355 
356 static int
357 awusbdrd_probe(device_t dev)
358 {
359 	if (!ofw_bus_status_okay(dev))
360 		return (ENXIO);
361 
362 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
363 		return (ENXIO);
364 
365 	device_set_desc(dev, "Allwinner USB DRD");
366 	return (BUS_PROBE_DEFAULT);
367 }
368 
369 static int
370 awusbdrd_attach(device_t dev)
371 {
372 	struct awusbdrd_softc *sc;
373 	int error;
374 
375 	sc = device_get_softc(dev);
376 	sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
377 
378 	error = bus_alloc_resources(dev, awusbdrd_spec, sc->res);
379 	if (error != 0)
380 		return (error);
381 
382 	/* AHB gate clock is required */
383 	error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
384 	if (error != 0)
385 		goto fail;
386 
387 	/* AHB reset is only present on some SoCs */
388 	(void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset);
389 
390 	/* Enable clocks */
391 	error = clk_enable(sc->clk);
392 	if (error != 0) {
393 		device_printf(dev, "failed to enable clock: %d\n", error);
394 		goto fail;
395 	}
396 	if (sc->reset != NULL) {
397 		error = hwreset_deassert(sc->reset);
398 		if (error != 0) {
399 			device_printf(dev, "failed to de-assert reset: %d\n",
400 			    error);
401 			goto fail;
402 		}
403 	}
404 
405 	sc->sc.sc_bus.parent = dev;
406 	sc->sc.sc_bus.devices = sc->sc.sc_devices;
407 	sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES;
408 	sc->sc.sc_bus.dma_bits = 32;
409 
410 	error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev),
411 	    NULL);
412 	if (error != 0) {
413 		error = ENOMEM;
414 		goto fail;
415 	}
416 
417 #if defined(__arm__)
418 	sc->bs.bs_parent = rman_get_bustag(sc->res[0]);
419 #elif defined(__aarch64__)
420 	sc->bs.bs_cookie = rman_get_bustag(sc->res[0]);
421 #endif
422 
423 	if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA)
424 		sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf;
425 	else
426 		sc->bs.bs_r_1 = awusbdrd_bs_r_1;
427 	sc->bs.bs_r_2 = awusbdrd_bs_r_2;
428 	sc->bs.bs_w_1 = awusbdrd_bs_w_1;
429 	sc->bs.bs_w_2 = awusbdrd_bs_w_2;
430 	sc->bs.bs_rm_1 = awusbdrd_bs_rm_1;
431 	sc->bs.bs_rm_4 = awusbdrd_bs_rm_4;
432 	sc->bs.bs_wm_1 = awusbdrd_bs_wm_1;
433 	sc->bs.bs_wm_4 = awusbdrd_bs_wm_4;
434 
435 	sc->sc.sc_io_tag = &sc->bs;
436 	sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]);
437 	sc->sc.sc_io_size = rman_get_size(sc->res[0]);
438 
439 	sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
440 	if (sc->sc.sc_bus.bdev == NULL) {
441 		error = ENXIO;
442 		goto fail;
443 	}
444 	device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus);
445 	sc->sc.sc_id = 0;
446 	sc->sc.sc_platform_data = sc;
447 	sc->sc.sc_mode = MUSB2_HOST_MODE;	/* XXX HOST vs DEVICE mode */
448 	sc->sc.sc_ep_max = DRD_EP_MAX;
449 	sc->sc.sc_ep_cfg = musbotg_ep_allwinner;
450 
451 	error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO,
452 	    NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl);
453 	if (error != 0)
454 		goto fail;
455 
456 	/* Enable PIO mode */
457 	bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE);
458 
459 #ifdef __arm__
460 	/* Map SRAMD area to USB0 (sun4i/sun7i only) */
461 	switch (allwinner_soc_family()) {
462 	case ALLWINNERSOC_SUN4I:
463 	case ALLWINNERSOC_SUN7I:
464 		a10_map_to_otg();
465 		break;
466 	}
467 #endif
468 
469 	error = musbotg_init(&sc->sc);
470 	if (error != 0)
471 		goto fail;
472 
473 	error = device_probe_and_attach(sc->sc.sc_bus.bdev);
474 	if (error != 0)
475 		goto fail;
476 
477 	musbotg_vbus_interrupt(&sc->sc, 1);	/* XXX VBUS */
478 
479 	return (0);
480 
481 fail:
482 	if (sc->reset != NULL)
483 		hwreset_release(sc->reset);
484 	if (sc->clk != NULL)
485 		clk_release(sc->clk);
486 	bus_release_resources(dev, awusbdrd_spec, sc->res);
487 	return (error);
488 }
489 
490 static int
491 awusbdrd_detach(device_t dev)
492 {
493 	struct awusbdrd_softc *sc;
494 	device_t bdev;
495 	int error;
496 
497 	sc = device_get_softc(dev);
498 
499 	if (sc->sc.sc_bus.bdev != NULL) {
500 		bdev = sc->sc.sc_bus.bdev;
501 		device_detach(bdev);
502 		device_delete_child(dev, bdev);
503 	}
504 
505 	musbotg_uninit(&sc->sc);
506 	error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl);
507 	if (error != 0)
508 		return (error);
509 
510 	usb_bus_mem_free_all(&sc->sc.sc_bus, NULL);
511 
512 	if (sc->reset != NULL)
513 		hwreset_release(sc->reset);
514 	if (sc->clk != NULL)
515 		clk_release(sc->clk);
516 
517 	bus_release_resources(dev, awusbdrd_spec, sc->res);
518 
519 	device_delete_children(dev);
520 
521 	return (0);
522 }
523 
524 static device_method_t awusbdrd_methods[] = {
525 	/* Device interface */
526 	DEVMETHOD(device_probe,		awusbdrd_probe),
527 	DEVMETHOD(device_attach,	awusbdrd_attach),
528 	DEVMETHOD(device_detach,	awusbdrd_detach),
529 	DEVMETHOD(device_suspend,	bus_generic_suspend),
530 	DEVMETHOD(device_resume,	bus_generic_resume),
531 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
532 
533 	DEVMETHOD_END
534 };
535 
536 static driver_t awusbdrd_driver = {
537 	.name = "musbotg",
538 	.methods = awusbdrd_methods,
539 	.size = sizeof(struct awusbdrd_softc),
540 };
541 
542 static devclass_t awusbdrd_devclass;
543 
544 DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, awusbdrd_devclass, 0, 0);
545 MODULE_DEPEND(musbotg, usb, 1, 1, 1);
546