1 /* $OpenBSD: ehci_pci.c,v 1.27 2014/05/16 18:17:03 mpi Exp $ */ 2 /* $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $ */ 3 4 /* 5 * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (lennart@augustsson.net). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/rwlock.h> 37 #include <sys/device.h> 38 #include <sys/timeout.h> 39 #include <sys/queue.h> 40 41 #include <machine/bus.h> 42 43 #include <dev/pci/pcidevs.h> 44 #include <dev/pci/pcivar.h> 45 46 #include <dev/usb/usb.h> 47 #include <dev/usb/usbdi.h> 48 #include <dev/usb/usbdivar.h> 49 #include <dev/usb/usb_mem.h> 50 51 #include <dev/usb/ehcireg.h> 52 #include <dev/usb/ehcivar.h> 53 54 #ifdef EHCI_DEBUG 55 #define DPRINTF(x) if (ehcidebug) printf x 56 extern int ehcidebug; 57 #else 58 #define DPRINTF(x) 59 #endif 60 61 struct ehci_pci_softc { 62 struct ehci_softc sc; 63 pci_chipset_tag_t sc_pc; 64 pcitag_t sc_tag; 65 void *sc_ih; /* interrupt vectoring */ 66 }; 67 68 int ehci_sb700_match(struct pci_attach_args *pa); 69 70 #define EHCI_SBx00_WORKAROUND_REG 0x50 71 #define EHCI_SBx00_WORKAROUND_ENABLE (1 << 3) 72 #define EHCI_VT6202_WORKAROUND_REG 0x48 73 74 int ehci_pci_match(struct device *, void *, void *); 75 void ehci_pci_attach(struct device *, struct device *, void *); 76 int ehci_pci_detach(struct device *, int); 77 int ehci_pci_activate(struct device *, int); 78 #if 0 79 void ehci_pci_givecontroller(struct ehci_pci_softc *); 80 #endif 81 void ehci_pci_takecontroller(struct ehci_pci_softc *, int); 82 83 struct cfattach ehci_pci_ca = { 84 sizeof(struct ehci_pci_softc), ehci_pci_match, ehci_pci_attach, 85 ehci_pci_detach, ehci_pci_activate 86 }; 87 88 int 89 ehci_pci_match(struct device *parent, void *match, void *aux) 90 { 91 struct pci_attach_args *pa = (struct pci_attach_args *) aux; 92 93 if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && 94 PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && 95 PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI) 96 return (1); 97 98 return (0); 99 } 100 101 void 102 ehci_pci_attach(struct device *parent, struct device *self, void *aux) 103 { 104 struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self; 105 struct pci_attach_args *pa = (struct pci_attach_args *)aux; 106 pci_chipset_tag_t pc = pa->pa_pc; 107 pcitag_t tag = pa->pa_tag; 108 char const *intrstr; 109 pci_intr_handle_t ih; 110 const char *vendor; 111 char *devname = sc->sc.sc_bus.bdev.dv_xname; 112 usbd_status r; 113 int s; 114 115 /* Map I/O registers */ 116 if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, 117 &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size, 0)) { 118 printf(": can't map mem space\n"); 119 return; 120 } 121 122 sc->sc_pc = pc; 123 sc->sc_tag = tag; 124 sc->sc.sc_bus.dmatag = pa->pa_dmat; 125 126 /* Disable interrupts, so we don't get any spurious ones. */ 127 s = splhardusb(); 128 sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); 129 DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs)); 130 EOWRITE2(&sc->sc, EHCI_USBINTR, 0); 131 132 /* Handle quirks */ 133 switch (PCI_VENDOR(pa->pa_id)) { 134 case PCI_VENDOR_ATI: 135 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_EHCI || 136 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB700_EHCI && 137 pci_find_device(NULL, ehci_sb700_match))) { 138 pcireg_t value; 139 140 /* apply the ATI SB600/SB700 workaround */ 141 value = pci_conf_read(sc->sc_pc, sc->sc_tag, 142 EHCI_SBx00_WORKAROUND_REG); 143 pci_conf_write(sc->sc_pc, sc->sc_tag, 144 EHCI_SBx00_WORKAROUND_REG, value | 145 EHCI_SBx00_WORKAROUND_ENABLE); 146 } 147 break; 148 149 case PCI_VENDOR_VIATECH: 150 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_VIATECH_VT6202 && 151 (PCI_REVISION(pa->pa_class) & 0xf0) == 0x60) { 152 pcireg_t value; 153 154 /* 155 * The VT6202 defaults to a 1 usec EHCI sleep time 156 * which hogs the PCI bus *badly*. Setting bit 5 of 157 * the register makes that sleep time use the conventional 158 * 10 usec. 159 */ 160 value = pci_conf_read(sc->sc_pc, sc->sc_tag, 161 EHCI_VT6202_WORKAROUND_REG); 162 pci_conf_write(sc->sc_pc, sc->sc_tag, 163 EHCI_VT6202_WORKAROUND_REG, value | 0x20000000); 164 } 165 break; 166 } 167 168 /* Map and establish the interrupt. */ 169 if (pci_intr_map(pa, &ih)) { 170 printf(": couldn't map interrupt\n"); 171 goto unmap_ret; 172 } 173 intrstr = pci_intr_string(pc, ih); 174 sc->sc_ih = pci_intr_establish(pc, ih, IPL_USB, ehci_intr, sc, devname); 175 if (sc->sc_ih == NULL) { 176 printf(": couldn't establish interrupt"); 177 if (intrstr != NULL) 178 printf(" at %s", intrstr); 179 printf("\n"); 180 goto unmap_ret; 181 } 182 printf(": %s\n", intrstr); 183 184 switch(pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) { 185 case PCI_USBREV_PRE_1_0: 186 case PCI_USBREV_1_0: 187 case PCI_USBREV_1_1: 188 sc->sc.sc_bus.usbrev = USBREV_UNKNOWN; 189 printf("%s: pre-2.0 USB rev\n", devname); 190 goto disestablish_ret; 191 case PCI_USBREV_2_0: 192 sc->sc.sc_bus.usbrev = USBREV_2_0; 193 break; 194 default: 195 sc->sc.sc_bus.usbrev = USBREV_UNKNOWN; 196 break; 197 } 198 199 /* Figure out vendor for root hub descriptor. */ 200 vendor = pci_findvendor(pa->pa_id); 201 sc->sc.sc_id_vendor = PCI_VENDOR(pa->pa_id); 202 if (vendor) 203 strlcpy(sc->sc.sc_vendor, vendor, sizeof(sc->sc.sc_vendor)); 204 else 205 snprintf(sc->sc.sc_vendor, sizeof(sc->sc.sc_vendor), 206 "vendor 0x%04x", PCI_VENDOR(pa->pa_id)); 207 208 /* Enable workaround for dropped interrupts as required */ 209 if (sc->sc.sc_id_vendor == PCI_VENDOR_VIATECH) 210 sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND; 211 212 ehci_pci_takecontroller(sc, 0); 213 r = ehci_init(&sc->sc); 214 if (r != USBD_NORMAL_COMPLETION) { 215 printf("%s: init failed, error=%d\n", devname, r); 216 goto disestablish_ret; 217 } 218 219 splx(s); 220 221 /* Attach usb device. */ 222 config_found(self, &sc->sc.sc_bus, usbctlprint); 223 return; 224 225 disestablish_ret: 226 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 227 unmap_ret: 228 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 229 splx(s); 230 } 231 232 int 233 ehci_pci_activate(struct device *self, int act) 234 { 235 struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self; 236 int rv; 237 238 switch (act) { 239 case DVACT_RESUME: 240 ehci_pci_takecontroller(sc, 1); 241 break; 242 } 243 244 rv = ehci_activate(self, act); 245 246 #if 0 247 switch (act) { 248 case DVACT_POWERDOWN: 249 ehci_pci_givecontroller(sc); 250 break; 251 } 252 #endif 253 return (rv); 254 } 255 256 int 257 ehci_pci_detach(struct device *self, int flags) 258 { 259 struct ehci_pci_softc *sc = (struct ehci_pci_softc *)self; 260 int rv; 261 262 rv = ehci_detach(self, flags); 263 if (rv) 264 return (rv); 265 if (sc->sc_ih != NULL) { 266 pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 267 sc->sc_ih = NULL; 268 } 269 if (sc->sc.sc_size) { 270 bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 271 sc->sc.sc_size = 0; 272 } 273 return (0); 274 } 275 276 #if 0 277 void 278 ehci_pci_givecontroller(struct ehci_pci_softc *sc) 279 { 280 u_int32_t cparams, eec, legsup; 281 int eecp; 282 283 cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS); 284 for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; 285 eecp = EHCI_EECP_NEXT(eec)) { 286 eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp); 287 if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) 288 continue; 289 legsup = eec; 290 pci_conf_write(sc->sc_pc, sc->sc_tag, eecp, 291 legsup & ~EHCI_LEGSUP_OSOWNED); 292 } 293 } 294 #endif 295 296 void 297 ehci_pci_takecontroller(struct ehci_pci_softc *sc, int silent) 298 { 299 u_int32_t cparams, eec, legsup; 300 int eecp, i; 301 302 cparams = EREAD4(&sc->sc, EHCI_HCCPARAMS); 303 /* Synchronise with the BIOS if it owns the controller. */ 304 for (eecp = EHCI_HCC_EECP(cparams); eecp != 0; 305 eecp = EHCI_EECP_NEXT(eec)) { 306 eec = pci_conf_read(sc->sc_pc, sc->sc_tag, eecp); 307 if (EHCI_EECP_ID(eec) != EHCI_EC_LEGSUP) 308 continue; 309 legsup = eec; 310 if (legsup & EHCI_LEGSUP_BIOSOWNED) { 311 pci_conf_write(sc->sc_pc, sc->sc_tag, eecp, 312 legsup | EHCI_LEGSUP_OSOWNED); 313 DPRINTF(("%s: waiting for BIOS to give up control\n", 314 sc->sc.sc_bus.bdev.dv_xname)); 315 for (i = 0; i < 5000; i++) { 316 legsup = pci_conf_read(sc->sc_pc, sc->sc_tag, 317 eecp); 318 if ((legsup & EHCI_LEGSUP_BIOSOWNED) == 0) 319 break; 320 DELAY(1000); 321 } 322 if (silent == 0 && (legsup & EHCI_LEGSUP_BIOSOWNED)) 323 printf("%s: timed out waiting for BIOS\n", 324 sc->sc.sc_bus.bdev.dv_xname); 325 } 326 } 327 } 328 329 int 330 ehci_sb700_match(struct pci_attach_args *pa) 331 { 332 if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && 333 PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB && 334 (PCI_REVISION(pa->pa_class) == 0x3a || 335 PCI_REVISION(pa->pa_class) == 0x3b)) 336 return (1); 337 338 return (0); 339 } 340