1 /* $OpenBSD: xhci_pci.c,v 1.5 2014/10/30 18:25:08 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 void *sc_ih; /* interrupt vectoring */ 65 }; 66 67 int xhci_pci_match(struct device *, void *, void *); 68 void xhci_pci_attach(struct device *, struct device *, void *); 69 int xhci_pci_detach(struct device *, int); 70 void xhci_pci_takecontroller(struct xhci_pci_softc *, int); 71 72 struct cfattach xhci_pci_ca = { 73 sizeof(struct xhci_pci_softc), xhci_pci_match, xhci_pci_attach, 74 xhci_pci_detach, xhci_activate 75 }; 76 77 int 78 xhci_pci_match(struct device *parent, void *match, void *aux) 79 { 80 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 81 82 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && 83 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && 84 PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_XHCI) 85 return (1); 86 87 return (0); 88 } 89 90 static int 91 xhci_pci_port_route(struct xhci_pci_softc *psc) 92 { 93 pcireg_t val; 94 95 /* 96 * Check USB3 Port Routing Mask register that indicates the ports 97 * can be changed from OS, and turn on by USB3 Port SS Enable register. 98 */ 99 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3PRM); 100 DPRINTF(("%s: USB3PRM / USB3.0 configurable ports: 0x%08x\n", 101 psc->sc.sc_bus.bdev.dv_xname, val)); 102 103 pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN, val); 104 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_USB3_PSSEN); 105 DPRINTF(("%s: USB3_PSSEN / Enabled USB3.0 ports under xHCI: 0x%08x\n", 106 psc->sc.sc_bus.bdev.dv_xname, val)); 107 108 /* 109 * Check USB2 Port Routing Mask register that indicates the USB2.0 110 * ports to be controlled by xHCI HC, and switch them to xHCI HC. 111 */ 112 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PRM); 113 DPRINTF(("%s: XUSB2PRM / USB2.0 ports can switch from EHCI to xHCI:" 114 "0x%08x\n", psc->sc.sc_bus.bdev.dv_xname, val)); 115 116 pci_conf_write(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR, val); 117 val = pci_conf_read(psc->sc_pc, psc->sc_tag, PCI_XHCI_INTEL_XUSB2PR); 118 DPRINTF(("%s: XUSB2PR / USB2.0 ports under xHCI: 0x%08x\n", 119 psc->sc.sc_bus.bdev.dv_xname, val)); 120 121 return (0); 122 } 123 124 125 void 126 xhci_pci_attach(struct device *parent, struct device *self, void *aux) 127 { 128 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 129 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 130 const char *intrstr; 131 const char *vendor; 132 pci_intr_handle_t ih; 133 pcireg_t reg; 134 int error; 135 136 reg = pci_mapreg_type(pa->pa_pc, pa->pa_tag, PCI_CBMEM); 137 if (pci_mapreg_map(pa, PCI_CBMEM, reg, 0, &psc->sc.iot, &psc->sc.ioh, 138 NULL, &psc->sc.sc_size, 0)) { 139 printf(": can't map mem space\n"); 140 return; 141 } 142 143 psc->sc_pc = pa->pa_pc; 144 psc->sc_tag = pa->pa_tag; 145 psc->sc.sc_bus.dmatag = pa->pa_dmat; 146 147 /* Handle quirks */ 148 switch (PCI_VENDOR(pa->pa_id)) { 149 case PCI_VENDOR_FRESCO: 150 /* FL1000 / FL1400 claim MSI support but do not support MSI */ 151 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FRESCO_FL1000 || 152 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_FRESCO_FL1400) 153 pa->pa_flags &= ~PCI_FLAGS_MSI_ENABLED; 154 break; 155 } 156 157 /* Map and establish the interrupt. */ 158 if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { 159 printf(": couldn't map interrupt\n"); 160 goto unmap_ret; 161 } 162 intrstr = pci_intr_string(pa->pa_pc, ih); 163 164 psc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_USB, 165 xhci_intr, psc, psc->sc.sc_bus.bdev.dv_xname); 166 if (psc->sc_ih == NULL) { 167 printf(": couldn't establish interrupt"); 168 if (intrstr != NULL) 169 printf(" at %s", intrstr); 170 printf("\n"); 171 goto unmap_ret; 172 } 173 printf(": %s\n", intrstr); 174 175 /* Figure out vendor for root hub descriptor. */ 176 vendor = pci_findvendor(pa->pa_id); 177 psc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id); 178 if (vendor) 179 strlcpy(psc->sc.sc_vendor, vendor, sizeof(psc->sc.sc_vendor)); 180 else 181 snprintf(psc->sc.sc_vendor, sizeof(psc->sc.sc_vendor), 182 "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); 183 184 xhci_pci_takecontroller(psc, 0); 185 186 if ((error = xhci_init(&psc->sc)) != 0) { 187 printf("%s: init failed, error=%d\n", 188 psc->sc.sc_bus.bdev.dv_xname, error); 189 goto disestablish_ret; 190 } 191 192 switch (PCI_VENDOR(pa->pa_id)) { 193 case PCI_VENDOR_INTEL: 194 switch (PCI_PRODUCT(pa->pa_id)) { 195 case PCI_PRODUCT_INTEL_8SERIES_XHCI: 196 case PCI_PRODUCT_INTEL_8SERIES_LP_XHCI: 197 case PCI_PRODUCT_INTEL_7SERIES_XHCI: 198 xhci_pci_port_route(psc); 199 break; 200 } 201 } 202 203 /* Attach usb device. */ 204 config_found(self, &psc->sc.sc_bus, usbctlprint); 205 206 /* Now that the stack is ready, config' the HC and enable interrupts. */ 207 xhci_config(&psc->sc); 208 209 return; 210 211 disestablish_ret: 212 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 213 unmap_ret: 214 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 215 } 216 217 int 218 xhci_pci_detach(struct device *self, int flags) 219 { 220 struct xhci_pci_softc *psc = (struct xhci_pci_softc *)self; 221 int rv; 222 223 rv = xhci_detach(self, flags); 224 if (rv) 225 return (rv); 226 if (psc->sc_ih != NULL) { 227 pci_intr_disestablish(psc->sc_pc, psc->sc_ih); 228 psc->sc_ih = NULL; 229 } 230 if (psc->sc.sc_size) { 231 bus_space_unmap(psc->sc.iot, psc->sc.ioh, psc->sc.sc_size); 232 psc->sc.sc_size = 0; 233 } 234 return (0); 235 } 236 237 void 238 xhci_pci_takecontroller(struct xhci_pci_softc *psc, int silent) 239 { 240 uint32_t cparams, xecp, eec; 241 uint8_t bios_sem; 242 int i; 243 244 cparams = XREAD4(&psc->sc, XHCI_HCCPARAMS); 245 eec = -1; 246 247 /* Synchronise with the BIOS if it owns the controller. */ 248 for (xecp = XHCI_HCC_XECP(cparams) << 2; xecp != 0; 249 xecp = XHCI_XECP_NEXT(eec) << 2) { 250 eec = XREAD4(&psc->sc, xecp); 251 if (XHCI_XECP_ID(eec) != XHCI_ID_USB_LEGACY) 252 continue; 253 bios_sem = XREAD1(&psc->sc, xecp + XHCI_XECP_BIOS_SEM); 254 if (bios_sem) { 255 XWRITE1(&psc->sc, xecp + XHCI_XECP_OS_SEM, 1); 256 DPRINTF(("%s: waiting for BIOS to give up control\n", 257 psc->sc.sc_bus.bdev.dv_xname)); 258 for (i = 0; i < 5000; i++) { 259 bios_sem = XREAD1(&psc->sc, xecp + 260 XHCI_XECP_BIOS_SEM); 261 if (bios_sem == 0) 262 break; 263 DELAY(1000); 264 } 265 if (silent == 0 && bios_sem) 266 printf("%s: timed out waiting for BIOS\n", 267 psc->sc.sc_bus.bdev.dv_xname); 268 } 269 } 270 } 271