1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2010-2022 Hans Petter Selasky 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include "implementation/global_implementation.h" 29#include "controller/xhci.h" 30#include "controller/xhcireg.h" 31 32#include <linux/kernel.h> 33 34#define PCI_XHCI_VENDORID_AMD 0x1022 35#define PCI_XHCI_VENDORID_INTEL 0x8086 36 37static device_probe_t xhci_pci_probe; 38static device_attach_t xhci_pci_attach; 39static device_detach_t xhci_pci_detach; 40static usb_take_controller_t xhci_pci_take_controller; 41 42static device_method_t xhci_device_methods[] = { 43 /* device interface */ 44 DEVMETHOD(device_probe, xhci_pci_probe), 45 DEVMETHOD(device_attach, xhci_pci_attach), 46 DEVMETHOD(device_detach, xhci_pci_detach), 47 DEVMETHOD(device_suspend, bus_generic_suspend), 48 DEVMETHOD(device_resume, bus_generic_resume), 49 DEVMETHOD(device_shutdown, bus_generic_shutdown), 50 DEVMETHOD(usb_take_controller, xhci_pci_take_controller), 51 52 DEVMETHOD_END 53}; 54 55static driver_t xhci_driver = { 56 .name = "xhci", 57 .methods = xhci_device_methods, 58 .size = sizeof(struct xhci_softc), 59}; 60 61static devclass_t xhci_devclass; 62 63DRIVER_MODULE(xhci, nexus, xhci_driver, xhci_devclass, NULL, NULL); 64 65static const char * 66xhci_pci_match(device_t self) 67{ 68 (void)self; 69 return ("XHCI (generic) USB 3.0 controller"); 70} 71 72static int 73xhci_pci_probe(device_t self) 74{ 75 const char *desc = xhci_pci_match(self); 76 77 if (desc) { 78 device_set_desc(self, desc); 79 return (BUS_PROBE_DEFAULT); 80 } else { 81 return (ENXIO); 82 } 83} 84 85static int 86xhci_pci_attach(device_t self) 87{ 88 struct resource *res; 89 struct xhci_softc *sc = device_get_softc(self);; 90 int err = ENXIO; 91 uint8_t usedma32 = 0; 92 int unit = device_get_unit(self); 93 94 usb_debug("+\n"); 95 96 res = bus_alloc_resource_any(self, SYS_RES_MEMORY, &unit, 0); 97 if (res == NULL) { 98 goto error; 99 } 100 101 sc->sc_io_res = ioremap(res->start, res->count); 102 if (!sc->sc_io_res) { 103 goto error; 104 } 105 sc->sc_io_tag = (void *)sc->sc_io_res; 106 sc->sc_io_hdl = (uintptr_t)sc->sc_io_res; 107 sc->sc_io_size = res->count; 108 usb_debug("bus_setup_intr\n"); 109 110 res = bus_alloc_resource_any(self, SYS_RES_IRQ, &unit, 0); 111 if (res == NULL) { 112 goto error; 113 } 114 115 sc->sc_irq_res = res; 116 err = bus_setup_intr(res->start, 0, (driver_intr_t *)xhci_interrupt, sc); 117 if (err) { 118 goto error; 119 } 120 121 usb_debug("xhci_init\n"); 122 HiUsb3StartHcd(); 123 if (xhci_init(sc, self, usedma32)) { 124 device_printf(self, "Could not initialize softc\n"); 125 goto error; 126 } 127 usb_callout_init_mtx(&sc->sc_callout, &sc->sc_bus.bus_mtx, 0); 128 129 usb_debug("add child to usbus\n"); 130 sc->sc_bus.bdev = device_add_child(self, "usbus", -1); 131 if (sc->sc_bus.bdev == NULL) { 132 device_printf(self, "Could not add USB device\n"); 133 goto error; 134 } 135 device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); 136 137 usb_debug("xhci halt and start controller\n"); 138 err = xhci_halt_controller(sc); 139 140 if (err == 0) 141 err = xhci_start_controller(sc); 142 143 usb_debug("device_probe_and_attach bus_dev\n"); 144 if (err == 0) 145 err = device_probe_and_attach(sc->sc_bus.bdev); 146 147 if (err) { 148 device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 149 goto error; 150 } 151 152 usb_debug("-\n"); 153 154 return (0); 155error: 156 device_printf(self, "XHCI halt/start/probe failed err=%d\n", err); 157 if (sc) { 158 iounmap((void *)sc->sc_io_res); 159 } 160 (void)xhci_pci_detach(self); 161 return (err); 162} 163 164static int 165xhci_pci_detach(device_t self) 166{ 167 168 struct xhci_softc *sc = device_get_softc(self); 169 170 /* during module unload there are lots of children leftover */ 171 (void)device_delete_children(self); 172 173 usb_callout_drain(&sc->sc_callout); 174 (void)xhci_halt_controller(sc); 175 (void)xhci_reset_controller(sc); 176 177 // release resouce 178 if (sc->sc_irq_res) { 179 (void)bus_teardown_intr(sc->sc_irq_res->start, sc); 180 sc->sc_irq_res = NULL; 181 } 182 if (sc->sc_io_res) { 183 iounmap((void *)sc->sc_io_res); 184 sc->sc_io_res = NULL; 185 sc->sc_io_tag = NULL; 186 sc->sc_io_hdl = (uintptr_t)NULL; 187 sc->sc_io_size = 0; 188 } 189 190 xhci_uninit(sc); 191 192 return (0); 193} 194 195static int 196xhci_pci_take_controller(device_t self) 197{ 198 struct xhci_softc *sc = device_get_softc(self); 199 uint32_t cparams; 200 uint32_t eecp; 201 uint32_t eec; 202 uint16_t to; 203 uint8_t bios_sem; 204 205 cparams = XREAD4(sc, capa, XHCI_HCSPARAMS0); 206 207 eec = (uint32_t)(-1); 208 209 /* Synchronise with the BIOS if it owns the controller. */ 210 for (eecp = XHCI_HCS0_XECP(cparams) << 2; (eecp != 0) && XHCI_XECP_NEXT(eec); 211 eecp += (XHCI_XECP_NEXT(eec) << 2)) { 212 eec = XREAD4(sc, capa, eecp); 213 214 if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 215 continue; 216 bios_sem = XREAD1(sc, capa, eecp + 217 XHCI_XECP_BIOS_SEM); 218 if (bios_sem == 0) 219 continue; 220 device_printf(sc->sc_bus.bdev, "waiting for BIOS " 221 "to give up control\n"); 222 XWRITE1(sc, capa, eecp + 223 XHCI_XECP_OS_SEM, 1); 224 to = 500; 225 while (1) { 226 bios_sem = XREAD1(sc, capa, eecp + 227 XHCI_XECP_BIOS_SEM); 228 if (bios_sem == 0) 229 break; 230 231 if (--to == 0) { 232 device_printf(sc->sc_bus.bdev, 233 "timed out waiting for BIOS\n"); 234 break; 235 } 236 usb_pause_mtx(NULL, hz / 100); /* wait 10ms */ 237 } 238 } 239 return (0); 240} 241 242int 243hixhci_init(void) 244{ 245 DPRINTF("hixhci_init"); 246 return driver_module_handler(NULL, MOD_LOAD, &xhci_nexus_driver_mod); 247} 248 249void 250hixhci_exit(void) 251{ 252 DPRINTF("hixhci_exit"); 253 (void)driver_module_handler(NULL, MOD_UNLOAD, &xhci_nexus_driver_mod); 254} 255