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
32 /*
33 * Allwinner USB Dual-Role Device (DRD) controller
34 */
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/kernel.h>
41 #include <sys/condvar.h>
42 #include <sys/module.h>
43
44 #include <machine/bus.h>
45
46 #include <dev/ofw/ofw_bus.h>
47 #include <dev/ofw/ofw_bus_subr.h>
48
49 #include <dev/usb/usb.h>
50 #include <dev/usb/usbdi.h>
51
52 #include <dev/usb/usb_core.h>
53 #include <dev/usb/usb_busdma.h>
54 #include <dev/usb/usb_process.h>
55 #include <dev/usb/usb_util.h>
56
57 #include <dev/usb/usb_controller.h>
58 #include <dev/usb/usb_bus.h>
59 #include <dev/usb/controller/musb_otg.h>
60
61 #include <dev/clk/clk.h>
62 #include <dev/hwreset/hwreset.h>
63 #include <dev/phy/phy.h>
64 #include <dev/phy/phy_usb.h>
65
66 #ifdef __arm__
67 #include <arm/allwinner/aw_machdep.h>
68 #include <arm/allwinner/a10_sramc.h>
69 #endif
70
71 #define DRD_EP_MAX 5
72 #define DRD_EP_MAX_H3 4
73
74 #define MUSB2_REG_AWIN_VEND0 0x0043
75 #define VEND0_PIO_MODE 0
76
77 #if defined(__arm__)
78 #define bs_parent_space(bs) ((bs)->bs_parent)
79 typedef bus_space_tag_t awusb_bs_tag;
80 #elif defined(__aarch64__) || defined(__riscv)
81 #define bs_parent_space(bs) (bs)
82 typedef void * awusb_bs_tag;
83 #endif
84
85 #define AWUSB_OKAY 0x01
86 #define AWUSB_NO_CONFDATA 0x02
87 static struct ofw_compat_data compat_data[] = {
88 { "allwinner,sun4i-a10-musb", AWUSB_OKAY },
89 { "allwinner,sun6i-a31-musb", AWUSB_OKAY },
90 { "allwinner,sun8i-a33-musb", AWUSB_OKAY | AWUSB_NO_CONFDATA },
91 { "allwinner,sun8i-h3-musb", AWUSB_OKAY | AWUSB_NO_CONFDATA },
92 { "allwinner,sun20i-d1-musb", AWUSB_OKAY | AWUSB_NO_CONFDATA },
93 { NULL, 0 }
94 };
95
96 static const struct musb_otg_ep_cfg musbotg_ep_allwinner[] = {
97 {
98 .ep_end = DRD_EP_MAX,
99 .ep_fifosz_shift = 9,
100 .ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512,
101 },
102 {
103 .ep_end = -1,
104 },
105 };
106
107 static const struct musb_otg_ep_cfg musbotg_ep_allwinner_h3[] = {
108 {
109 .ep_end = DRD_EP_MAX_H3,
110 .ep_fifosz_shift = 9,
111 .ep_fifosz_reg = MUSB2_VAL_FIFOSZ_512,
112 },
113 {
114 .ep_end = -1,
115 },
116 };
117
118 struct awusbdrd_softc {
119 struct musbotg_softc sc;
120 struct resource *res[2];
121 clk_t clk;
122 hwreset_t reset;
123 phy_t phy;
124 struct bus_space bs;
125 int flags;
126 };
127
128 static struct resource_spec awusbdrd_spec[] = {
129 { SYS_RES_MEMORY, 0, RF_ACTIVE },
130 { SYS_RES_IRQ, 0, RF_ACTIVE },
131 { -1, 0 }
132 };
133
134 #define REMAPFLAG 0x8000
135 #define REGDECL(a, b) [(a)] = ((b) | REMAPFLAG)
136
137 /* Allwinner USB DRD register mappings */
138 static const uint16_t awusbdrd_regmap[] = {
139 REGDECL(MUSB2_REG_EPFIFO(0), 0x0000),
140 REGDECL(MUSB2_REG_EPFIFO(1), 0x0004),
141 REGDECL(MUSB2_REG_EPFIFO(2), 0x0008),
142 REGDECL(MUSB2_REG_EPFIFO(3), 0x000c),
143 REGDECL(MUSB2_REG_EPFIFO(4), 0x0010),
144 REGDECL(MUSB2_REG_EPFIFO(5), 0x0014),
145 REGDECL(MUSB2_REG_POWER, 0x0040),
146 REGDECL(MUSB2_REG_DEVCTL, 0x0041),
147 REGDECL(MUSB2_REG_EPINDEX, 0x0042),
148 REGDECL(MUSB2_REG_INTTX, 0x0044),
149 REGDECL(MUSB2_REG_INTRX, 0x0046),
150 REGDECL(MUSB2_REG_INTTXE, 0x0048),
151 REGDECL(MUSB2_REG_INTRXE, 0x004a),
152 REGDECL(MUSB2_REG_INTUSB, 0x004c),
153 REGDECL(MUSB2_REG_INTUSBE, 0x0050),
154 REGDECL(MUSB2_REG_FRAME, 0x0054),
155 REGDECL(MUSB2_REG_TESTMODE, 0x007c),
156 REGDECL(MUSB2_REG_TXMAXP, 0x0080),
157 REGDECL(MUSB2_REG_TXCSRL, 0x0082),
158 REGDECL(MUSB2_REG_TXCSRH, 0x0083),
159 REGDECL(MUSB2_REG_RXMAXP, 0x0084),
160 REGDECL(MUSB2_REG_RXCSRL, 0x0086),
161 REGDECL(MUSB2_REG_RXCSRH, 0x0087),
162 REGDECL(MUSB2_REG_RXCOUNT, 0x0088),
163 REGDECL(MUSB2_REG_TXTI, 0x008c),
164 REGDECL(MUSB2_REG_TXNAKLIMIT, 0x008d),
165 REGDECL(MUSB2_REG_RXNAKLIMIT, 0x008f),
166 REGDECL(MUSB2_REG_RXTI, 0x008e),
167 REGDECL(MUSB2_REG_TXFIFOSZ, 0x0090),
168 REGDECL(MUSB2_REG_TXFIFOADD, 0x0092),
169 REGDECL(MUSB2_REG_RXFIFOSZ, 0x0094),
170 REGDECL(MUSB2_REG_RXFIFOADD, 0x0096),
171 REGDECL(MUSB2_REG_FADDR, 0x0098),
172 REGDECL(MUSB2_REG_TXFADDR(0), 0x0098),
173 REGDECL(MUSB2_REG_TXHADDR(0), 0x009a),
174 REGDECL(MUSB2_REG_TXHUBPORT(0), 0x009b),
175 REGDECL(MUSB2_REG_RXFADDR(0), 0x009c),
176 REGDECL(MUSB2_REG_RXHADDR(0), 0x009e),
177 REGDECL(MUSB2_REG_RXHUBPORT(0), 0x009f),
178 REGDECL(MUSB2_REG_TXFADDR(1), 0x0098),
179 REGDECL(MUSB2_REG_TXHADDR(1), 0x009a),
180 REGDECL(MUSB2_REG_TXHUBPORT(1), 0x009b),
181 REGDECL(MUSB2_REG_RXFADDR(1), 0x009c),
182 REGDECL(MUSB2_REG_RXHADDR(1), 0x009e),
183 REGDECL(MUSB2_REG_RXHUBPORT(1), 0x009f),
184 REGDECL(MUSB2_REG_TXFADDR(2), 0x0098),
185 REGDECL(MUSB2_REG_TXHADDR(2), 0x009a),
186 REGDECL(MUSB2_REG_TXHUBPORT(2), 0x009b),
187 REGDECL(MUSB2_REG_RXFADDR(2), 0x009c),
188 REGDECL(MUSB2_REG_RXHADDR(2), 0x009e),
189 REGDECL(MUSB2_REG_RXHUBPORT(2), 0x009f),
190 REGDECL(MUSB2_REG_TXFADDR(3), 0x0098),
191 REGDECL(MUSB2_REG_TXHADDR(3), 0x009a),
192 REGDECL(MUSB2_REG_TXHUBPORT(3), 0x009b),
193 REGDECL(MUSB2_REG_RXFADDR(3), 0x009c),
194 REGDECL(MUSB2_REG_RXHADDR(3), 0x009e),
195 REGDECL(MUSB2_REG_RXHUBPORT(3), 0x009f),
196 REGDECL(MUSB2_REG_TXFADDR(4), 0x0098),
197 REGDECL(MUSB2_REG_TXHADDR(4), 0x009a),
198 REGDECL(MUSB2_REG_TXHUBPORT(4), 0x009b),
199 REGDECL(MUSB2_REG_RXFADDR(4), 0x009c),
200 REGDECL(MUSB2_REG_RXHADDR(4), 0x009e),
201 REGDECL(MUSB2_REG_RXHUBPORT(4), 0x009f),
202 REGDECL(MUSB2_REG_TXFADDR(5), 0x0098),
203 REGDECL(MUSB2_REG_TXHADDR(5), 0x009a),
204 REGDECL(MUSB2_REG_TXHUBPORT(5), 0x009b),
205 REGDECL(MUSB2_REG_RXFADDR(5), 0x009c),
206 REGDECL(MUSB2_REG_RXHADDR(5), 0x009e),
207 REGDECL(MUSB2_REG_RXHUBPORT(5), 0x009f),
208 REGDECL(MUSB2_REG_CONFDATA, 0x00c0),
209 };
210
211 static bus_size_t
awusbdrd_reg(bus_size_t o)212 awusbdrd_reg(bus_size_t o)
213 {
214 bus_size_t v;
215
216 KASSERT(o < nitems(awusbdrd_regmap),
217 ("%s: Invalid register %#lx", __func__, o));
218 if (o >= nitems(awusbdrd_regmap))
219 return (o);
220
221 v = awusbdrd_regmap[o];
222
223 KASSERT((v & REMAPFLAG) != 0, ("%s: reg %#lx not in regmap",
224 __func__, o));
225
226 return (v & ~REMAPFLAG);
227 }
228
229 static int
awusbdrd_filt(bus_size_t o)230 awusbdrd_filt(bus_size_t o)
231 {
232 switch (o) {
233 case MUSB2_REG_MISC:
234 case MUSB2_REG_RXDBDIS:
235 case MUSB2_REG_TXDBDIS:
236 return (1);
237 default:
238 return (0);
239 }
240 }
241
242 static uint8_t
awusbdrd_bs_r_1(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o)243 awusbdrd_bs_r_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
244 {
245 struct bus_space *bs = t;
246
247 switch (o) {
248 case MUSB2_REG_HWVERS:
249 return (0); /* no known equivalent */
250 }
251
252 return (bus_space_read_1(bs_parent_space(bs), h, awusbdrd_reg(o)));
253 }
254
255 static uint8_t
awusbdrd_bs_r_1_noconf(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o)256 awusbdrd_bs_r_1_noconf(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
257 {
258
259 /*
260 * There is no confdata register on some SoCs, return the same
261 * magic value as Linux.
262 */
263 if (o == MUSB2_REG_CONFDATA)
264 return (0xde);
265
266 return (awusbdrd_bs_r_1(t, h, o));
267 }
268
269
270 static uint16_t
awusbdrd_bs_r_2(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o)271 awusbdrd_bs_r_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o)
272 {
273 struct bus_space *bs = t;
274
275 if (awusbdrd_filt(o) != 0)
276 return (0);
277 return bus_space_read_2(bs_parent_space(bs), h, awusbdrd_reg(o));
278 }
279
280 static void
awusbdrd_bs_w_1(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,uint8_t v)281 awusbdrd_bs_w_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
282 uint8_t v)
283 {
284 struct bus_space *bs = t;
285
286 if (awusbdrd_filt(o) != 0)
287 return;
288
289 bus_space_write_1(bs_parent_space(bs), h, awusbdrd_reg(o), v);
290 }
291
292 static void
awusbdrd_bs_w_2(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,uint16_t v)293 awusbdrd_bs_w_2(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
294 uint16_t v)
295 {
296 struct bus_space *bs = t;
297
298 if (awusbdrd_filt(o) != 0)
299 return;
300
301 bus_space_write_2(bs_parent_space(bs), h, awusbdrd_reg(o), v);
302 }
303
304 static void
awusbdrd_bs_rm_1(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,uint8_t * d,bus_size_t c)305 awusbdrd_bs_rm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
306 uint8_t *d, bus_size_t c)
307 {
308 struct bus_space *bs = t;
309
310 bus_space_read_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
311 }
312
313 static void
awusbdrd_bs_rm_4(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,uint32_t * d,bus_size_t c)314 awusbdrd_bs_rm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
315 uint32_t *d, bus_size_t c)
316 {
317 struct bus_space *bs = t;
318
319 bus_space_read_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
320 }
321
322 static void
awusbdrd_bs_wm_1(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,const uint8_t * d,bus_size_t c)323 awusbdrd_bs_wm_1(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
324 const uint8_t *d, bus_size_t c)
325 {
326 struct bus_space *bs = t;
327
328 if (awusbdrd_filt(o) != 0)
329 return;
330
331 bus_space_write_multi_1(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
332 }
333
334 static void
awusbdrd_bs_wm_4(awusb_bs_tag t,bus_space_handle_t h,bus_size_t o,const uint32_t * d,bus_size_t c)335 awusbdrd_bs_wm_4(awusb_bs_tag t, bus_space_handle_t h, bus_size_t o,
336 const uint32_t *d, bus_size_t c)
337 {
338 struct bus_space *bs = t;
339
340 if (awusbdrd_filt(o) != 0)
341 return;
342
343 bus_space_write_multi_4(bs_parent_space(bs), h, awusbdrd_reg(o), d, c);
344 }
345
346 static void
awusbdrd_intr(void * arg)347 awusbdrd_intr(void *arg)
348 {
349 struct awusbdrd_softc *sc = arg;
350 uint8_t intusb;
351 uint16_t inttx, intrx;
352
353 intusb = MUSB2_READ_1(&sc->sc, MUSB2_REG_INTUSB);
354 inttx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTTX);
355 intrx = MUSB2_READ_2(&sc->sc, MUSB2_REG_INTRX);
356 if (intusb == 0 && inttx == 0 && intrx == 0)
357 return;
358
359 if (intusb)
360 MUSB2_WRITE_1(&sc->sc, MUSB2_REG_INTUSB, intusb);
361 if (inttx)
362 MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTTX, inttx);
363 if (intrx)
364 MUSB2_WRITE_2(&sc->sc, MUSB2_REG_INTRX, intrx);
365
366 musbotg_interrupt(arg, intrx, inttx, intusb);
367 }
368
369 static int
awusbdrd_probe(device_t dev)370 awusbdrd_probe(device_t dev)
371 {
372 if (!ofw_bus_status_okay(dev))
373 return (ENXIO);
374
375 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
376 return (ENXIO);
377
378 device_set_desc(dev, "Allwinner USB DRD");
379 return (BUS_PROBE_DEFAULT);
380 }
381
382 static int
awusbdrd_attach(device_t dev)383 awusbdrd_attach(device_t dev)
384 {
385 char usb_mode[24];
386 struct awusbdrd_softc *sc;
387 uint8_t musb_mode;
388 int phy_mode;
389 int error;
390
391 sc = device_get_softc(dev);
392 sc->flags = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
393
394 error = bus_alloc_resources(dev, awusbdrd_spec, sc->res);
395 if (error != 0)
396 return (error);
397
398 musb_mode = MUSB2_HOST_MODE; /* default */
399 phy_mode = PHY_USB_MODE_HOST;
400 if (OF_getprop(ofw_bus_get_node(dev), "dr_mode",
401 &usb_mode, sizeof(usb_mode)) > 0) {
402 usb_mode[sizeof(usb_mode) - 1] = 0;
403 if (strcasecmp(usb_mode, "host") == 0) {
404 musb_mode = MUSB2_HOST_MODE;
405 phy_mode = PHY_USB_MODE_HOST;
406 } else if (strcasecmp(usb_mode, "peripheral") == 0) {
407 musb_mode = MUSB2_DEVICE_MODE;
408 phy_mode = PHY_USB_MODE_DEVICE;
409 } else if (strcasecmp(usb_mode, "otg") == 0) {
410 /*
411 * XXX phy has PHY_USB_MODE_OTG, but MUSB does not have
412 * it. It's not clear how to propagate mode changes
413 * from phy layer (that detects them) to MUSB.
414 */
415 musb_mode = MUSB2_DEVICE_MODE;
416 phy_mode = PHY_USB_MODE_DEVICE;
417 } else {
418 device_printf(dev, "Invalid FDT dr_mode: %s\n",
419 usb_mode);
420 }
421 }
422
423 /* AHB gate clock is required */
424 error = clk_get_by_ofw_index(dev, 0, 0, &sc->clk);
425 if (error != 0)
426 goto fail;
427
428 /* AHB reset is only present on some SoCs */
429 (void)hwreset_get_by_ofw_idx(dev, 0, 0, &sc->reset);
430
431 /* Enable clocks */
432 error = clk_enable(sc->clk);
433 if (error != 0) {
434 device_printf(dev, "failed to enable clock: %d\n", error);
435 goto fail;
436 }
437 if (sc->reset != NULL) {
438 error = hwreset_deassert(sc->reset);
439 if (error != 0) {
440 device_printf(dev, "failed to de-assert reset: %d\n",
441 error);
442 goto fail;
443 }
444 }
445
446 /* XXX not sure if this is universally needed. */
447 (void)phy_get_by_ofw_name(dev, 0, "usb", &sc->phy);
448 if (sc->phy != NULL) {
449 device_printf(dev, "setting phy mode %d\n", phy_mode);
450 if (musb_mode == MUSB2_HOST_MODE) {
451 error = phy_enable(sc->phy);
452 if (error != 0) {
453 device_printf(dev, "Could not enable phy\n");
454 goto fail;
455 }
456 }
457 error = phy_usb_set_mode(sc->phy, phy_mode);
458 if (error != 0) {
459 device_printf(dev, "Could not set phy mode\n");
460 goto fail;
461 }
462 }
463
464 sc->sc.sc_bus.parent = dev;
465 sc->sc.sc_bus.devices = sc->sc.sc_devices;
466 sc->sc.sc_bus.devices_max = MUSB2_MAX_DEVICES;
467 sc->sc.sc_bus.dma_bits = 32;
468
469 error = usb_bus_mem_alloc_all(&sc->sc.sc_bus, USB_GET_DMA_TAG(dev),
470 NULL);
471 if (error != 0) {
472 error = ENOMEM;
473 goto fail;
474 }
475
476 #if defined(__arm__)
477 sc->bs.bs_parent = rman_get_bustag(sc->res[0]);
478 #elif defined(__aarch64__) || defined(__riscv)
479 sc->bs.bs_cookie = rman_get_bustag(sc->res[0]);
480 #endif
481
482 if ((sc->flags & AWUSB_NO_CONFDATA) == AWUSB_NO_CONFDATA)
483 sc->bs.bs_r_1 = awusbdrd_bs_r_1_noconf;
484 else
485 sc->bs.bs_r_1 = awusbdrd_bs_r_1;
486 sc->bs.bs_r_2 = awusbdrd_bs_r_2;
487 sc->bs.bs_w_1 = awusbdrd_bs_w_1;
488 sc->bs.bs_w_2 = awusbdrd_bs_w_2;
489 sc->bs.bs_rm_1 = awusbdrd_bs_rm_1;
490 sc->bs.bs_rm_4 = awusbdrd_bs_rm_4;
491 sc->bs.bs_wm_1 = awusbdrd_bs_wm_1;
492 sc->bs.bs_wm_4 = awusbdrd_bs_wm_4;
493
494 sc->sc.sc_io_tag = &sc->bs;
495 sc->sc.sc_io_hdl = rman_get_bushandle(sc->res[0]);
496 sc->sc.sc_io_size = rman_get_size(sc->res[0]);
497
498 sc->sc.sc_bus.bdev = device_add_child(dev, "usbus", DEVICE_UNIT_ANY);
499 if (sc->sc.sc_bus.bdev == NULL) {
500 error = ENXIO;
501 goto fail;
502 }
503 device_set_ivars(sc->sc.sc_bus.bdev, &sc->sc.sc_bus);
504 sc->sc.sc_id = 0;
505 sc->sc.sc_platform_data = sc;
506 sc->sc.sc_mode = musb_mode;
507 if (ofw_bus_is_compatible(dev, "allwinner,sun8i-h3-musb")) {
508 sc->sc.sc_ep_cfg = musbotg_ep_allwinner_h3;
509 sc->sc.sc_ep_max = DRD_EP_MAX_H3;
510 } else {
511 sc->sc.sc_ep_cfg = musbotg_ep_allwinner;
512 sc->sc.sc_ep_max = DRD_EP_MAX;
513 }
514
515 error = bus_setup_intr(dev, sc->res[1], INTR_MPSAFE | INTR_TYPE_BIO,
516 NULL, awusbdrd_intr, sc, &sc->sc.sc_intr_hdl);
517 if (error != 0)
518 goto fail;
519
520 /* Enable PIO mode */
521 bus_write_1(sc->res[0], MUSB2_REG_AWIN_VEND0, VEND0_PIO_MODE);
522
523 #ifdef __arm__
524 /* Map SRAMD area to USB0 (sun4i/sun7i only) */
525 switch (allwinner_soc_family()) {
526 case ALLWINNERSOC_SUN4I:
527 case ALLWINNERSOC_SUN7I:
528 a10_map_to_otg();
529 break;
530 }
531 #endif
532
533 error = musbotg_init(&sc->sc);
534 if (error != 0)
535 goto fail;
536
537 error = device_probe_and_attach(sc->sc.sc_bus.bdev);
538 if (error != 0)
539 goto fail;
540
541 musbotg_vbus_interrupt(&sc->sc, 1); /* XXX VBUS */
542
543 return (0);
544
545 fail:
546 if (sc->phy != NULL) {
547 if (musb_mode == MUSB2_HOST_MODE)
548 (void)phy_disable(sc->phy);
549 phy_release(sc->phy);
550 }
551 if (sc->reset != NULL) {
552 hwreset_assert(sc->reset);
553 hwreset_release(sc->reset);
554 }
555 if (sc->clk != NULL)
556 clk_release(sc->clk);
557 bus_release_resources(dev, awusbdrd_spec, sc->res);
558 return (error);
559 }
560
561 static int
awusbdrd_detach(device_t dev)562 awusbdrd_detach(device_t dev)
563 {
564 struct awusbdrd_softc *sc;
565 int error;
566
567 error = bus_generic_detach(dev);
568 if (error != 0)
569 return (error);
570
571 sc = device_get_softc(dev);
572
573 musbotg_uninit(&sc->sc);
574 error = bus_teardown_intr(dev, sc->res[1], sc->sc.sc_intr_hdl);
575 if (error != 0)
576 return (error);
577
578 usb_bus_mem_free_all(&sc->sc.sc_bus, NULL);
579
580 if (sc->phy != NULL) {
581 if (sc->sc.sc_mode == MUSB2_HOST_MODE)
582 phy_disable(sc->phy);
583 phy_release(sc->phy);
584 }
585 if (sc->reset != NULL) {
586 if (hwreset_assert(sc->reset) != 0)
587 device_printf(dev, "failed to assert reset\n");
588 hwreset_release(sc->reset);
589 }
590 if (sc->clk != NULL)
591 clk_release(sc->clk);
592
593 bus_release_resources(dev, awusbdrd_spec, sc->res);
594
595 return (0);
596 }
597
598 static device_method_t awusbdrd_methods[] = {
599 /* Device interface */
600 DEVMETHOD(device_probe, awusbdrd_probe),
601 DEVMETHOD(device_attach, awusbdrd_attach),
602 DEVMETHOD(device_detach, awusbdrd_detach),
603 DEVMETHOD(device_suspend, bus_generic_suspend),
604 DEVMETHOD(device_resume, bus_generic_resume),
605 DEVMETHOD(device_shutdown, bus_generic_shutdown),
606
607 DEVMETHOD_END
608 };
609
610 static driver_t awusbdrd_driver = {
611 .name = "musbotg",
612 .methods = awusbdrd_methods,
613 .size = sizeof(struct awusbdrd_softc),
614 };
615
616 DRIVER_MODULE(musbotg, simplebus, awusbdrd_driver, 0, 0);
617 MODULE_DEPEND(musbotg, usb, 1, 1, 1);
618