1 /* $OpenBSD: xhci_pci.c,v 1.12 2023/04/18 21:22:00 patrick Exp $ */ 2 3 /* 4 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Lennart Augustsson (lennart@augustsson.net). 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/kernel.h> 35 #include <sys/rwlock.h> 36 #include <sys/device.h> 37 #include <sys/timeout.h> 38 #include <sys/queue.h> 39 40 #include <machine/bus.h> 41 42 #include <dev/pci/pcidevs.h> 43 #include <dev/pci/pcivar.h> 44 45 #include <dev/usb/usb.h> 46 #include <dev/usb/usbdi.h> 47 #include <dev/usb/usbdivar.h> 48 #include <dev/usb/usb_mem.h> 49 50 #include <dev/usb/xhcireg.h> 51 #include <dev/usb/xhcivar.h> 52 53 #ifdef XHCI_DEBUG 54 #define DPRINTF(x) if (xhcidebug) printf x 55 extern int xhcidebug; 56 #else 57 #define DPRINTF(x) 58 #endif 59 60 struct xhci_pci_softc { 61 struct xhci_softc sc; 62 pci_chipset_tag_t sc_pc; 63 pcitag_t sc_tag; 64 pcireg_t sc_id; 65 void *sc_ih; /* interrupt vectoring */ 66 }; 67 68 int xhci_pci_match(struct device *, void *, void *); 69 void xhci_pci_attach(struct device *, struct device *, void *); 70 int xhci_pci_detach(struct device *, int); 71 int xhci_pci_activate(struct device *, int); 72 void xhci_pci_takecontroller(struct xhci_pci_softc *, int); 73 74 const struct cfattach xhci_pci_ca = { 75 sizeof(struct xhci_pci_softc), xhci_pci_match, xhci_pci_attach, 76 xhci_pci_detach, xhci_pci_activate 77 }; 78 79 int 80 xhci_pci_match(struct device *parent, void *match, void *aux) 81 { 82 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 83 84 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && 85 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && 86 PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_XHCI) 87 return (1); 88 89 return (0); 90 } 91 92 static int 93 xhci_pci_port_route(struct xhci_pci_softc *psc) 94 { 95 pcireg_t val; 96 97 /* 98 * Check USB3 Port Routing Mask register that indicates the ports 99 * can be changed from OS, and turn on by USB3 Port SS Enable register. 100 */ 101 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3PRM); 102 DPRINTF(("%s: USB3PRM / USB3.0 configurable ports: 0x%08x\n", 103 psc->sc.sc_bus.bdev.dv_xname, val)); 104 105 pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN, val); 106 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN); 107 DPRINTF(("%s: USB3_PSSEN / Enabled USB3.0 ports under xHCI: 0x%08x\n", 108 psc->sc.sc_bus.bdev.dv_xname, val)); 109 110 /* 111 * Check USB2 Port Routing Mask register that indicates the USB2.0 112 * ports to be controlled by xHCI HC, and switch them to xHCI HC. 113 */ 114 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PRM); 115 DPRINTF(("%s: XUSB2PRM / USB2.0 ports can switch from EHCI to xHCI:" 116 "0x%08x\n", psc->sc.sc_bus.bdev.dv_xname, val)); 117 118 pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR, val); 119 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR); 120 DPRINTF(("%s: XUSB2PR / USB2.0 ports under xHCI: 0x%08x\n", 121 psc->sc.sc_bus.bdev.dv_xname, val)); 122 123 return (0); 124 } 125 126 127 void 128 xhci_pci_attach(struct device *parent, struct device *self, void *aux) 129 { 130 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 131 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 132 const char *intrstr; 133 const char *vendor; 134 pci_intr_handle_t ih; 135 pcireg_t reg; 136 int error; 137 138 reg = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_CBMEM); 139 if (pci_mapreg_map(pa, PCI_CBMEM, reg, 0, &psc->sc.iot, &psc->sc.ioh, 140 NULL, &psc->sc.sc_size, 0)) { 141 printf(": can't map mem space\n"); 142 return; 143 } 144 145 psc->sc_pc = pa->pa_pc; 146 psc->sc_tag = pa->pa_tag; 147 psc->sc_id = pa->pa_id; 148 psc->sc.sc_bus.dmatag = pa->pa_dmat; 149 150 /* Handle quirks */ 151 switch (PCI_VENDOR(pa->pa_id)) { 152 case PCI_VENDOR_FRESCO: 153 /* FL1000 / FL1400 claim MSI support but do not support MSI */ 154 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FRESCO_FL1000 || 155 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FRESCO_FL1400) 156 pa->pa_flags &= ~PCI_FLAGS_MSI_ENABLED; 157 break; 158 } 159 160 /* Map and establish the interrupt. */ 161 if (pci_intr_map_msix(pa, 0, &ih) != 0 && 162 pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 163 printf(": couldn't map interrupt\n"); 164 goto unmap_ret; 165 } 166 intrstr = pci_intr_string(pa->pa_pc, ih); 167 168 psc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_USB | IPL_MPSAFE, 169 xhci_intr, psc, psc->sc.sc_bus.bdev.dv_xname); 170 if (psc->sc_ih == NULL) { 171 printf(": couldn't establish interrupt"); 172 if (intrstr != NULL) 173 printf(" at %s", intrstr); 174 printf("\n"); 175 goto unmap_ret; 176 } 177 printf(": %s", intrstr); 178 179 /* Figure out vendor for root hub descriptor. */ 180 vendor = pci_findvendor(pa->pa_id); 181 psc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id); 182 if (vendor) 183 strlcpy(psc->sc.sc_vendor, vendor, sizeof(psc->sc.sc_vendor)); 184 else 185 snprintf(psc->sc.sc_vendor, sizeof(psc->sc.sc_vendor), 186 "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); 187 188 xhci_pci_takecontroller(psc, 0); 189 190 if ((error = xhci_init(&psc->sc)) != 0) { 191 printf("%s: init failed, error=%d\n", 192 psc->sc.sc_bus.bdev.dv_xname, error); 193 goto disestablish_ret; 194 } 195 196 if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) 197 xhci_pci_port_route(psc); 198 199 /* Attach usb device. */ 200 config_found(self, &psc->sc.sc_bus, usbctlprint); 201 202 /* Now that the stack is ready, config' the HC and enable interrupts. */ 203 xhci_config(&psc->sc); 204 205 return; 206 207 disestablish_ret: 208 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 209 unmap_ret: 210 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 211 } 212 213 int 214 xhci_pci_detach(struct device *self, int flags) 215 { 216 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 217 int rv; 218 219 rv = xhci_detach(self, flags); 220 if (rv) 221 return (rv); 222 if (psc->sc_ih != NULL) { 223 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 224 psc->sc_ih = NULL; 225 } 226 if (psc->sc.sc_size) { 227 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 228 psc->sc.sc_size = 0; 229 } 230 return (0); 231 } 232 233 int 234 xhci_pci_activate(struct device *self, int act) 235 { 236 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 237 238 switch (act) { 239 case DVACT_RESUME: 240 if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) 241 xhci_pci_port_route(psc); 242 break; 243 default: 244 break; 245 } 246 247 return (xhci_activate(self, act)); 248 } 249 250 251 void 252 xhci_pci_takecontroller(struct xhci_pci_softc *psc, int silent) 253 { 254 uint32_t cparams, xecp, eec; 255 uint8_t bios_sem; 256 int i; 257 258 cparams = XREAD4(&psc->sc, XHCI_HCCPARAMS); 259 if (cparams == 0xffffffff) 260 return; 261 262 eec = -1; 263 264 /* Synchronise with the BIOS if it owns the controller. */ 265 for (xecp = XHCI_HCC_XECP(cparams) << 2; 266 xecp != 0 && XHCI_XECP_NEXT(eec); 267 xecp += XHCI_XECP_NEXT(eec) << 2) { 268 eec = XREAD4(&psc->sc, xecp); 269 if (eec == 0xffffffff) 270 return; 271 if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 272 continue; 273 bios_sem = XREAD1(&psc->sc, xecp + XHCI_XECP_BIOS_SEM); 274 if (bios_sem) { 275 XWRITE1(&psc->sc, xecp + XHCI_XECP_OS_SEM, 1); 276 DPRINTF(("%s: waiting for BIOS to give up control\n", 277 psc->sc.sc_bus.bdev.dv_xname)); 278 for (i = 0; i < 5000; i++) { 279 bios_sem = XREAD1(&psc->sc, xecp + 280 XHCI_XECP_BIOS_SEM); 281 if (bios_sem == 0) 282 break; 283 DELAY(1000); 284 } 285 if (silent == 0 && bios_sem) 286 printf("%s: timed out waiting for BIOS\n", 287 psc->sc.sc_bus.bdev.dv_xname); 288 } 289 } 290 } 291