1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2010, Aleksandr Rybalko <ray@ddteam.net>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice unmodified, this list of conditions, and the following
12 * disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 /*
34 * Ported version of BroadCom USB core driver from ZRouter project
35 */
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/module.h>
40 #include <sys/errno.h>
41 #include <sys/bus.h>
42 #include <sys/rman.h>
43 #include <sys/malloc.h>
44
45 #include <machine/bus.h>
46 #include <machine/resource.h>
47
48 #include <dev/bhnd/bhnd.h>
49
50 #include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
51
52 #include "bhnd_usbvar.h"
53
54 /****************************** Variables ************************************/
55 static const struct bhnd_device bhnd_usb_devs[] = {
56 BHND_DEVICE(BCM, USB20H, "USB2.0 Host core", NULL),
57 BHND_DEVICE_END
58 };
59
60 /****************************** Prototypes ***********************************/
61
62 static int bhnd_usb_attach(device_t);
63 static int bhnd_usb_probe(device_t);
64 static device_t bhnd_usb_add_child(device_t dev, u_int order, const char *name,
65 int unit);
66 static int bhnd_usb_print_all_resources(device_t dev);
67 static int bhnd_usb_print_child(device_t bus, device_t child);
68
69 static struct resource * bhnd_usb_alloc_resource(device_t bus,
70 device_t child, int type, int *rid,
71 rman_res_t start, rman_res_t end,
72 rman_res_t count, u_int flags);
73 static int bhnd_usb_release_resource(device_t dev,
74 device_t child, int type, int rid,
75 struct resource *r);
76
77 static struct resource_list * bhnd_usb_get_reslist(device_t dev,
78 device_t child);
79
80 static int
81 bhnd_usb_probe(device_t dev)
82 {
83 const struct bhnd_device *id;
84
85 id = bhnd_device_lookup(dev, bhnd_usb_devs, sizeof(bhnd_usb_devs[0]));
86 if (id == NULL)
87 return (ENXIO);
88
89 device_set_desc(dev, id->desc);
90 return (BUS_PROBE_DEFAULT);
91 }
92
93 static int
94 bhnd_usb_attach(device_t dev)
95 {
96 struct bhnd_usb_softc *sc;
97 int rid;
98 uint32_t tmp;
99 int tries, err;
100
101 sc = device_get_softc(dev);
102
103 bhnd_reset_hw(dev, 0, 0);
104
105 /*
106 * Allocate the resources which the parent bus has already
107 * determined for us.
108 * XXX: There are few windows (usually 2), RID should be chip-specific
109 */
110 rid = 0;
111 sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
112 if (sc->sc_mem == NULL) {
113 BHND_ERROR_DEV(dev, "unable to allocate memory");
114 return (ENXIO);
115 }
116
117 sc->sc_bt = rman_get_bustag(sc->sc_mem);
118 sc->sc_bh = rman_get_bushandle(sc->sc_mem);
119 sc->sc_maddr = rman_get_start(sc->sc_mem);
120 sc->sc_msize = rman_get_size(sc->sc_mem);
121
122 rid = 0;
123 sc->sc_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
124 RF_SHAREABLE | RF_ACTIVE);
125 if (sc->sc_irq == NULL) {
126 BHND_ERROR_DEV(dev, "unable to allocate IRQ");
127 return (ENXIO);
128 }
129
130 sc->sc_irqn = rman_get_start(sc->sc_irq);
131
132 sc->mem_rman.rm_start = sc->sc_maddr;
133 sc->mem_rman.rm_end = sc->sc_maddr + sc->sc_msize - 1;
134 sc->mem_rman.rm_type = RMAN_ARRAY;
135 sc->mem_rman.rm_descr = "BHND USB core I/O memory addresses";
136 if (rman_init(&sc->mem_rman) != 0 ||
137 rman_manage_region(&sc->mem_rman, sc->mem_rman.rm_start,
138 sc->mem_rman.rm_end) != 0) {
139 panic("%s: sc->mem_rman", __func__);
140 }
141
142 /* TODO: macros for registers */
143 bus_write_4(sc->sc_mem, 0x200, 0x7ff);
144 DELAY(100);
145
146 #define OHCI_CONTROL 0x04
147 bus_write_4(sc->sc_mem, OHCI_CONTROL, 0);
148
149 if ( bhnd_get_device(dev) == BHND_COREID_USB20H) {
150 uint32_t rev = bhnd_get_hwrev(dev);
151 BHND_INFO_DEV(dev, "USB HOST 2.0 setup for rev %d", rev);
152 if (rev == 1/* ? == 2 */) {
153 /* SiBa code */
154
155 /* Change Flush control reg */
156 tmp = bus_read_4(sc->sc_mem, 0x400) & ~0x8;
157 bus_write_4(sc->sc_mem, 0x400, tmp);
158 tmp = bus_read_4(sc->sc_mem, 0x400);
159 BHND_DEBUG_DEV(dev, "USB20H fcr: 0x%x", tmp);
160
161 /* Change Shim control reg */
162 tmp = bus_read_4(sc->sc_mem, 0x304) & ~0x100;
163 bus_write_4(sc->sc_mem, 0x304, tmp);
164 tmp = bus_read_4(sc->sc_mem, 0x304);
165 BHND_DEBUG_DEV(dev, "USB20H shim: 0x%x", tmp);
166 } else if (rev >= 5) {
167 /* BCMA code */
168 err = bhnd_alloc_pmu(dev);
169 if(err) {
170 BHND_ERROR_DEV(dev, "can't alloc pmu: %d", err);
171 return (err);
172 }
173
174 err = bhnd_request_ext_rsrc(dev, 1);
175 if(err) {
176 BHND_ERROR_DEV(dev, "can't req ext: %d", err);
177 return (err);
178 }
179 /* Take out of resets */
180 bus_write_4(sc->sc_mem, 0x200, 0x4ff);
181 DELAY(25);
182 bus_write_4(sc->sc_mem, 0x200, 0x6ff);
183 DELAY(25);
184
185 /* Make sure digital and AFE are locked in USB PHY */
186 bus_write_4(sc->sc_mem, 0x524, 0x6b);
187 DELAY(50);
188 bus_read_4(sc->sc_mem, 0x524);
189 DELAY(50);
190 bus_write_4(sc->sc_mem, 0x524, 0xab);
191 DELAY(50);
192 bus_read_4(sc->sc_mem, 0x524);
193 DELAY(50);
194 bus_write_4(sc->sc_mem, 0x524, 0x2b);
195 DELAY(50);
196 bus_read_4(sc->sc_mem, 0x524);
197 DELAY(50);
198 bus_write_4(sc->sc_mem, 0x524, 0x10ab);
199 DELAY(50);
200 bus_read_4(sc->sc_mem, 0x524);
201
202 tries = 10000;
203 for (;;) {
204 DELAY(10);
205 tmp = bus_read_4(sc->sc_mem, 0x528);
206 if (tmp & 0xc000)
207 break;
208 if (--tries != 0)
209 continue;
210
211 tmp = bus_read_4(sc->sc_mem, 0x528);
212 BHND_ERROR_DEV(dev, "USB20H mdio_rddata 0x%08x", tmp);
213 }
214
215 /* XXX: Puzzle code */
216 bus_write_4(sc->sc_mem, 0x528, 0x80000000);
217 bus_read_4(sc->sc_mem, 0x314);
218 DELAY(265);
219 bus_write_4(sc->sc_mem, 0x200, 0x7ff);
220 DELAY(10);
221
222 /* Take USB and HSIC out of non-driving modes */
223 bus_write_4(sc->sc_mem, 0x510, 0);
224 }
225 }
226
227 bus_generic_probe(dev);
228
229 if (bhnd_get_device(dev) == BHND_COREID_USB20H &&
230 ( bhnd_get_hwrev(dev) > 0))
231 bhnd_usb_add_child(dev, 0, "ehci", -1);
232 bhnd_usb_add_child(dev, 1, "ohci", -1);
233
234 bus_generic_attach(dev);
235
236 return (0);
237 }
238
239 static struct resource *
240 bhnd_usb_alloc_resource(device_t bus, device_t child, int type, int *rid,
241 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
242 {
243 struct resource *rv;
244 struct resource_list *rl;
245 struct resource_list_entry *rle;
246 int passthrough, isdefault, needactivate;
247 struct bhnd_usb_softc *sc = device_get_softc(bus);
248
249 isdefault = RMAN_IS_DEFAULT_RANGE(start,end);
250 passthrough = (device_get_parent(child) != bus);
251 needactivate = flags & RF_ACTIVE;
252 rle = NULL;
253
254 if (!passthrough && isdefault) {
255 BHND_INFO_DEV(bus, "trying allocate def %d - %d for %s", type,
256 *rid, device_get_nameunit(child) );
257
258 rl = BUS_GET_RESOURCE_LIST(bus, child);
259 rle = resource_list_find(rl, type, *rid);
260 if (rle == NULL)
261 return (NULL);
262 if (rle->res != NULL)
263 panic("%s: resource entry is busy", __func__);
264 start = rle->start;
265 end = rle->end;
266 count = rle->count;
267 } else {
268 BHND_INFO_DEV(bus, "trying allocate %d - %d (%jx-%jx) for %s", type,
269 *rid, start, end, device_get_nameunit(child) );
270 }
271
272 /*
273 * If the request is for a resource which we manage,
274 * attempt to satisfy the allocation ourselves.
275 */
276 if (type == SYS_RES_MEMORY) {
277 rv = rman_reserve_resource(&sc->mem_rman, start, end, count,
278 flags, child);
279 if (rv == NULL) {
280 BHND_ERROR_DEV(bus, "could not reserve resource");
281 return (0);
282 }
283
284 rman_set_rid(rv, *rid);
285
286 if (needactivate &&
287 bus_activate_resource(child, type, *rid, rv)) {
288 BHND_ERROR_DEV(bus, "could not activate resource");
289 rman_release_resource(rv);
290 return (0);
291 }
292
293 return (rv);
294 }
295
296 /*
297 * Pass the request to the parent.
298 */
299 return (bus_generic_rl_alloc_resource(bus, child, type, rid, start, end,
300 count, flags));
301 }
302
303 static struct resource_list *
304 bhnd_usb_get_reslist(device_t dev, device_t child)
305 {
306 struct bhnd_usb_devinfo *sdi;
307
308 sdi = device_get_ivars(child);
309
310 return (&sdi->sdi_rl);
311 }
312
313 static int
314 bhnd_usb_release_resource(device_t dev, device_t child, int type,
315 int rid, struct resource *r)
316 {
317 struct bhnd_usb_softc *sc;
318 struct resource_list_entry *rle;
319 bool passthrough;
320 int error;
321
322 sc = device_get_softc(dev);
323 passthrough = (device_get_parent(child) != dev);
324
325 /* Delegate to our parent device's bus if the requested resource type
326 * isn't handled locally. */
327 if (type != SYS_RES_MEMORY) {
328 return (bus_generic_rl_release_resource(dev, child, type, rid,
329 r));
330 }
331
332 /* Deactivate resources */
333 if (rman_get_flags(r) & RF_ACTIVE) {
334 error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r);
335 if (error)
336 return (error);
337 }
338
339 if ((error = rman_release_resource(r)))
340 return (error);
341
342 if (!passthrough) {
343 /* Clean resource list entry */
344 rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
345 type, rid);
346 if (rle != NULL)
347 rle->res = NULL;
348 }
349
350 return (0);
351 }
352
353 static int
354 bhnd_usb_print_all_resources(device_t dev)
355 {
356 struct bhnd_usb_devinfo *sdi;
357 struct resource_list *rl;
358 int retval;
359
360 retval = 0;
361 sdi = device_get_ivars(dev);
362 rl = &sdi->sdi_rl;
363
364 if (STAILQ_FIRST(rl))
365 retval += printf(" at");
366
367 retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%jx");
368 retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
369
370 return (retval);
371 }
372
373 static int
374 bhnd_usb_print_child(device_t bus, device_t child)
375 {
376 int retval = 0;
377
378 retval += bus_print_child_header(bus, child);
379 retval += bhnd_usb_print_all_resources(child);
380 if (device_get_flags(child))
381 retval += printf(" flags %#x", device_get_flags(child));
382 retval += printf(" on %s\n", device_get_nameunit(bus));
383
384 return (retval);
385 }
386
387 static device_t
388 bhnd_usb_add_child(device_t dev, u_int order, const char *name, int unit)
389 {
390 struct bhnd_usb_softc *sc;
391 struct bhnd_usb_devinfo *sdi;
392 device_t child;
393 int error;
394
395 sc = device_get_softc(dev);
396
397 sdi = malloc(sizeof(struct bhnd_usb_devinfo), M_DEVBUF, M_NOWAIT|M_ZERO);
398 if (sdi == NULL)
399 return (NULL);
400
401 resource_list_init(&sdi->sdi_rl);
402 sdi->sdi_irq_mapped = false;
403
404 if (strncmp(name, "ohci", 4) == 0)
405 {
406 sdi->sdi_maddr = sc->sc_maddr + 0x000;
407 sdi->sdi_msize = 0x200;
408 }
409 else if (strncmp(name, "ehci", 4) == 0)
410 {
411 sdi->sdi_maddr = sc->sc_maddr + 0x000;
412 sdi->sdi_msize = 0x1000;
413 }
414 else
415 {
416 panic("Unknown subdevice");
417 }
418
419 /* Map the child's IRQ */
420 if ((error = bhnd_map_intr(dev, 0, &sdi->sdi_irq))) {
421 BHND_ERROR_DEV(dev, "could not map %s interrupt: %d", name,
422 error);
423 goto failed;
424 }
425 sdi->sdi_irq_mapped = true;
426
427 BHND_INFO_DEV(dev, "%s: irq=%ju maddr=0x%jx", name, sdi->sdi_irq,
428 sdi->sdi_maddr);
429
430 /*
431 * Add memory window and irq to child's resource list.
432 */
433 resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, 0, sdi->sdi_maddr,
434 sdi->sdi_maddr + sdi->sdi_msize - 1, sdi->sdi_msize);
435
436 resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, 0, sdi->sdi_irq,
437 sdi->sdi_irq, 1);
438
439 child = device_add_child_ordered(dev, order, name, unit);
440 if (child == NULL) {
441 BHND_ERROR_DEV(dev, "could not add %s", name);
442 goto failed;
443 }
444
445 device_set_ivars(child, sdi);
446 return (child);
447
448 failed:
449 if (sdi->sdi_irq_mapped)
450 bhnd_unmap_intr(dev, sdi->sdi_irq);
451
452 resource_list_free(&sdi->sdi_rl);
453
454 free(sdi, M_DEVBUF);
455 return (NULL);
456 }
457
458 static void
459 bhnd_usb_child_deleted(device_t dev, device_t child)
460 {
461 struct bhnd_usb_devinfo *dinfo;
462
463 if ((dinfo = device_get_ivars(child)) == NULL)
464 return;
465
466 if (dinfo->sdi_irq_mapped)
467 bhnd_unmap_intr(dev, dinfo->sdi_irq);
468
469 resource_list_free(&dinfo->sdi_rl);
470 free(dinfo, M_DEVBUF);
471 }
472
473 static device_method_t bhnd_usb_methods[] = {
474 /* Device interface */
475 DEVMETHOD(device_attach, bhnd_usb_attach),
476 DEVMETHOD(device_probe, bhnd_usb_probe),
477
478 /* Bus interface */
479 DEVMETHOD(bus_add_child, bhnd_usb_add_child),
480 DEVMETHOD(bus_child_deleted, bhnd_usb_child_deleted),
481 DEVMETHOD(bus_alloc_resource, bhnd_usb_alloc_resource),
482 DEVMETHOD(bus_get_resource_list, bhnd_usb_get_reslist),
483 DEVMETHOD(bus_print_child, bhnd_usb_print_child),
484 DEVMETHOD(bus_release_resource, bhnd_usb_release_resource),
485 /* Bus interface: generic part */
486 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
487 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
488 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
489 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
490
491 DEVMETHOD_END
492 };
493
494 DEFINE_CLASS_0(bhnd_usb, bhnd_usb_driver, bhnd_usb_methods,
495 sizeof(struct bhnd_usb_softc));
496 DRIVER_MODULE(bhnd_usb, bhnd, bhnd_usb_driver, 0, 0);
497
498 MODULE_VERSION(bhnd_usb, 1);
Cache object: 6d00e6f43554f30593b95e32f90b9e5f
|