xref: /freebsd/sys/dev/usb/controller/musb_otg_allwinner.c (revision 029e367dd195ad2d92af50133a31bea4035ab9ee)
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 	return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o));
263 }
264 
265 static void
266 awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
267     uint8_t v)
268 {
269 	const struct bus_space *bs = t;
270 
271 	if (awusbdrd_filt(o) != 0)
272 		return;
273 
274 	bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v);
275 }
276 
277 static void
278 awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
279     uint16_t v)
280 {
281 	const struct bus_space *bs = t;
282 
283 	if (awusbdrd_filt(o) != 0)
284 		return;
285 
286 	bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v);
287 }
288 
289 static void
290 awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
291     uint8_t *d, bus_size_t c)
292 {
293 	const struct bus_space *bs = t;
294 
295 	bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
296 }
297 
298 static void
299 awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
300     uint32_t *d, bus_size_t c)
301 {
302 	const struct bus_space *bs = t;
303 
304 	bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
305 }
306 
307 static void
308 awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
309     const uint8_t *d, bus_size_t c)
310 {
311 	const struct bus_space *bs = t;
312 
313 	if (awusbdrd_filt(o) != 0)
314 		return;
315 
316 	bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
317 }
318 
319 static void
320 awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
321     const uint32_t *d, bus_size_t c)
322 {
323 	const struct bus_space *bs = t;
324 
325 	if (awusbdrd_filt(o) != 0)
326 		return;
327 
328 	bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
329 }
330 
331 static void
332 awusbdrd_intr(void *arg)
333 {
334 	struct awusbdrd_softc *sc = arg;
335 	uint8_t intusb;
336 	uint16_t inttx, intrx;
337 
338 	intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB);
339 	inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX);
340 	intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX);
341 	if (intusb == 0 && inttx == 0 && intrx == 0)
342 		return;
343 
344 	if (intusb)
345 		MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb);
346 	if (inttx)
347 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx);
348 	if (intrx)
349 		MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx);
350 
351 	musbotg_interrupt(arg, intrx, inttx, intusb);
352 }
353 
354 static int
355 awusbdrd_probe(device_t dev)
356 {
357 	if (!ofw_bus_status_okay(dev))
358 		return (ENXIO);
359 
360 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
361 		return (ENXIO);
362 
363 	device_set_desc(dev, "Allwinner USB DRD");
364 	return (BUS_PROBE_DEFAULT);
365 }
366 
367 static int
368 awusbdrd_attach(device_t dev)
369 {
370 	struct awusbdrd_softc *sc;
371 	int error;
372 
373 	sc = device_get_softc(dev);
374 	sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
375 
376 	error = bus_alloc_resources(dev, awusbdrd_spec, sc->res);
377 	if (error != 0)
378 		return (error);
379 
380 	/* AHB gate clock is required */
381 	error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
382 	if (error != 0)
383 		goto fail;
384 
385 	/* AHB reset is only present on some SoCs */
386 	(void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset);
387 
388 	/* Enable clocks */
389 	error = clk_enable(sc->clk);
390 	if (error != 0) {
391 		device_printf(dev, "failed to enable clock: %d\n", error);
392 		goto fail;
393 	}
394 	if (sc->reset != NULL) {
395 		error = hwreset_deassert(sc->reset);
396 		if (error != 0) {
397 			device_printf(dev, "failed to de-assert reset: %d\n",
398 			    error);
399 			goto fail;
400 		}
401 	}
402 
403 	sc->sc.sc_bus.parent = dev;
404 	sc->sc.sc_bus.devices = sc->sc.sc_devices;
405 	sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES;
406 	sc->sc.sc_bus.dma_bits = 32;
407 
408 	error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev),
409 	    NULL);
410 	if (error != 0) {
411 		error = ENOMEM;
412 		goto fail;
413 	}
414 
415 #if defined(__arm__)
416 	sc->bs.bs_parent = rman_get_bustag(sc->res[0]);
417 #elif defined(__aarch64__)
418 	sc->bs.bs_cookie = rman_get_bustag(sc->res[0]);
419 #endif
420 
421 	if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA)
422 		sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf;
423 	else
424 		sc->bs.bs_r_1 = awusbdrd_bs_r_1;
425 	sc->bs.bs_r_2 = awusbdrd_bs_r_2;
426 	sc->bs.bs_w_1 = awusbdrd_bs_w_1;
427 	sc->bs.bs_w_2 = awusbdrd_bs_w_2;
428 	sc->bs.bs_rm_1 = awusbdrd_bs_rm_1;
429 	sc->bs.bs_rm_4 = awusbdrd_bs_rm_4;
430 	sc->bs.bs_wm_1 = awusbdrd_bs_wm_1;
431 	sc->bs.bs_wm_4 = awusbdrd_bs_wm_4;
432 
433 	sc->sc.sc_io_tag = &sc->bs;
434 	sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]);
435 	sc->sc.sc_io_size = rman_get_size(sc->res[0]);
436 
437 	sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", -1);
438 	if (sc->sc.sc_bus.bdev == NULL) {
439 		error = ENXIO;
440 		goto fail;
441 	}
442 	device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus);
443 	sc->sc.sc_id = 0;
444 	sc->sc.sc_platform_data = sc;
445 	sc->sc.sc_mode = MUSB2_HOST_MODE;	/* XXX HOST vs DEVICE mode */
446 	sc->sc.sc_ep_max = DRD_EP_MAX;
447 	sc->sc.sc_ep_cfg = musbotg_ep_allwinner;
448 
449 	error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO,
450 	    NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl);
451 	if (error != 0)
452 		goto fail;
453 
454 	/* Enable PIO mode */
455 	bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE);
456 
457 #ifdef __arm__
458 	/* Map SRAMD area to USB0 (sun4i/sun7i only) */
459 	switch (allwinner_soc_family()) {
460 	case ALLWINNERSOC_SUN4I:
461 	case ALLWINNERSOC_SUN7I:
462 		a10_map_to_otg();
463 		break;
464 	}
465 #endif
466 
467 	error = musbotg_init(&sc->sc);
468 	if (error != 0)
469 		goto fail;
470 
471 	error = device_probe_and_attach(sc->sc.sc_bus.bdev);
472 	if (error != 0)
473 		goto fail;
474 
475 	musbotg_vbus_interrupt(&sc->sc, 1);	/* XXX VBUS */
476 
477 	return (0);
478 
479 fail:
480 	if (sc->reset != NULL)
481 		hwreset_release(sc->reset);
482 	if (sc->clk != NULL)
483 		clk_release(sc->clk);
484 	bus_release_resources(dev, awusbdrd_spec, sc->res);
485 	return (error);
486 }
487 
488 static int
489 awusbdrd_detach(device_t dev)
490 {
491 	struct awusbdrd_softc *sc;
492 	device_t bdev;
493 	int error;
494 
495 	sc = device_get_softc(dev);
496 
497 	if (sc->sc.sc_bus.bdev != NULL) {
498 		bdev = sc->sc.sc_bus.bdev;
499 		device_detach(bdev);
500 		device_delete_child(dev, bdev);
501 	}
502 
503 	musbotg_uninit(&sc->sc);
504 	error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl);
505 	if (error != 0)
506 		return (error);
507 
508 	usb_bus_mem_free_all(&sc->sc.sc_bus, NULL);
509 
510 	if (sc->reset != NULL)
511 		hwreset_release(sc->reset);
512 	if (sc->clk != NULL)
513 		clk_release(sc->clk);
514 
515 	bus_release_resources(dev, awusbdrd_spec, sc->res);
516 
517 	device_delete_children(dev);
518 
519 	return (0);
520 }
521 
522 static device_method_t awusbdrd_methods[] = {
523 	/* Device interface */
524 	DEVMETHOD(device_probe,		awusbdrd_probe),
525 	DEVMETHOD(device_attach,	awusbdrd_attach),
526 	DEVMETHOD(device_detach,	awusbdrd_detach),
527 	DEVMETHOD(device_suspend,	bus_generic_suspend),
528 	DEVMETHOD(device_resume,	bus_generic_resume),
529 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
530 
531 	DEVMETHOD_END
532 };
533 
534 static driver_t awusbdrd_driver = {
535 	.name = "musbotg",
536 	.methods = awusbdrd_methods,
537 	.size = sizeof(struct awusbdrd_softc),
538 };
539 
540 static devclass_t awusbdrd_devclass;
541 
542 DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, awusbdrd_devclass, 0, 0);
543 MODULE_DEPEND(musbotg, usb, 1, 1, 1);
544