1 /* $OpenBSD: xhci_pci.c,v 1.8 2016/06/01 06:19:59 mpi 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 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_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 162 printf(": couldn't map interrupt\n"); 163 goto unmap_ret; 164 } 165 intrstr = pci_intr_string(pa->pa_pc, ih); 166 167 psc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_USB | IPL_MPSAFE, 168 xhci_intr, psc, psc->sc.sc_bus.bdev.dv_xname); 169 if (psc->sc_ih == NULL) { 170 printf(": couldn't establish interrupt"); 171 if (intrstr != NULL) 172 printf(" at %s", intrstr); 173 printf("\n"); 174 goto unmap_ret; 175 } 176 printf(": %s\n", intrstr); 177 178 /* Figure out vendor for root hub descriptor. */ 179 vendor = pci_findvendor(pa->pa_id); 180 psc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id); 181 if (vendor) 182 strlcpy(psc->sc.sc_vendor, vendor, sizeof(psc->sc.sc_vendor)); 183 else 184 snprintf(psc->sc.sc_vendor, sizeof(psc->sc.sc_vendor), 185 "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); 186 187 xhci_pci_takecontroller(psc, 0); 188 189 if ((error = xhci_init(&psc->sc)) != 0) { 190 printf("%s: init failed, error=%d\n", 191 psc->sc.sc_bus.bdev.dv_xname, error); 192 goto disestablish_ret; 193 } 194 195 if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) 196 xhci_pci_port_route(psc); 197 198 /* Attach usb device. */ 199 config_found(self, &psc->sc.sc_bus, usbctlprint); 200 201 /* Now that the stack is ready, config' the HC and enable interrupts. */ 202 xhci_config(&psc->sc); 203 204 return; 205 206 disestablish_ret: 207 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 208 unmap_ret: 209 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 210 } 211 212 int 213 xhci_pci_detach(struct device *self, int flags) 214 { 215 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 216 int rv; 217 218 rv = xhci_detach(self, flags); 219 if (rv) 220 return (rv); 221 if (psc->sc_ih != NULL) { 222 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 223 psc->sc_ih = NULL; 224 } 225 if (psc->sc.sc_size) { 226 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 227 psc->sc.sc_size = 0; 228 } 229 return (0); 230 } 231 232 int 233 xhci_pci_activate(struct device *self, int act) 234 { 235 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 236 237 switch (act) { 238 case DVACT_RESUME: 239 if (PCI_VENDOR(psc->sc_id) == PCI_VENDOR_INTEL) 240 xhci_pci_port_route(psc); 241 break; 242 default: 243 break; 244 } 245 246 return (xhci_activate(self, act)); 247 } 248 249 250 void 251 xhci_pci_takecontroller(struct xhci_pci_softc *psc, int silent) 252 { 253 uint32_t cparams, xecp, eec; 254 uint8_t bios_sem; 255 int i; 256 257 cparams = XREAD4(&psc->sc, XHCI_HCCPARAMS); 258 eec = -1; 259 260 /* Synchronise with the BIOS if it owns the controller. */ 261 for (xecp = XHCI_HCC_XECP(cparams) << 2; 262 xecp != 0 && XHCI_XECP_NEXT(eec); 263 xecp += XHCI_XECP_NEXT(eec) << 2) { 264 eec = XREAD4(&psc->sc, xecp); 265 if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 266 continue; 267 bios_sem = XREAD1(&psc->sc, xecp + XHCI_XECP_BIOS_SEM); 268 if (bios_sem) { 269 XWRITE1(&psc->sc, xecp + XHCI_XECP_OS_SEM, 1); 270 DPRINTF(("%s: waiting for BIOS to give up control\n", 271 psc->sc.sc_bus.bdev.dv_xname)); 272 for (i = 0; i < 5000; i++) { 273 bios_sem = XREAD1(&psc->sc, xecp + 274 XHCI_XECP_BIOS_SEM); 275 if (bios_sem == 0) 276 break; 277 DELAY(1000); 278 } 279 if (silent == 0 && bios_sem) 280 printf("%s: timed out waiting for BIOS\n", 281 psc->sc.sc_bus.bdev.dv_xname); 282 } 283 } 284 } 285