1 1.78 riastrad /* $NetBSD: ehci_pci.c,v 1.78 2025/03/31 14:45:35 riastradh Exp $ */ 2 1.1 augustss 3 1.1 augustss /* 4 1.8 augustss * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. 5 1.1 augustss * All rights reserved. 6 1.1 augustss * 7 1.1 augustss * This code is derived from software contributed to The NetBSD Foundation 8 1.1 augustss * by Lennart Augustsson (lennart (at) augustsson.net). 9 1.1 augustss * 10 1.1 augustss * Redistribution and use in source and binary forms, with or without 11 1.1 augustss * modification, are permitted provided that the following conditions 12 1.1 augustss * are met: 13 1.1 augustss * 1. Redistributions of source code must retain the above copyright 14 1.1 augustss * notice, this list of conditions and the following disclaimer. 15 1.1 augustss * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 augustss * notice, this list of conditions and the following disclaimer in the 17 1.1 augustss * documentation and/or other materials provided with the distribution. 18 1.1 augustss * 19 1.1 augustss * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 augustss * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 augustss * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 augustss * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 augustss * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 augustss * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 augustss * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 augustss * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 augustss * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 augustss * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 augustss * POSSIBILITY OF SUCH DAMAGE. 30 1.1 augustss */ 31 1.6 lukem 32 1.6 lukem #include <sys/cdefs.h> 33 1.78 riastrad __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.78 2025/03/31 14:45:35 riastradh Exp $"); 34 1.1 augustss 35 1.1 augustss #include <sys/param.h> 36 1.1 augustss #include <sys/systm.h> 37 1.1 augustss #include <sys/kernel.h> 38 1.1 augustss #include <sys/device.h> 39 1.1 augustss #include <sys/proc.h> 40 1.1 augustss #include <sys/queue.h> 41 1.1 augustss 42 1.31 ad #include <sys/bus.h> 43 1.1 augustss 44 1.22 xtraeme #include <dev/pci/pcidevs.h> 45 1.1 augustss #include <dev/pci/pcivar.h> 46 1.4 augustss #include <dev/pci/usb_pci.h> 47 1.1 augustss 48 1.1 augustss #include <dev/usb/usb.h> 49 1.1 augustss #include <dev/usb/usbdi.h> 50 1.1 augustss #include <dev/usb/usbdivar.h> 51 1.1 augustss #include <dev/usb/usb_mem.h> 52 1.1 augustss 53 1.1 augustss #include <dev/usb/ehcireg.h> 54 1.1 augustss #include <dev/usb/ehcivar.h> 55 1.1 augustss 56 1.5 augustss #ifdef EHCI_DEBUG 57 1.5 augustss #define DPRINTF(x) if (ehcidebug) printf x 58 1.5 augustss extern int ehcidebug; 59 1.5 augustss #else 60 1.5 augustss #define DPRINTF(x) 61 1.5 augustss #endif 62 1.5 augustss 63 1.45 cegger enum ehci_pci_quirk_flags { 64 1.45 cegger EHCI_PCI_QUIRK_AMD_SB600 = 0x1, /* always need a quirk */ 65 1.45 cegger EHCI_PCI_QUIRK_AMD_SB700 = 0x2, /* depends on the SMB revision */ 66 1.45 cegger }; 67 1.45 cegger 68 1.45 cegger static const struct pci_quirkdata ehci_pci_quirks[] = { 69 1.45 cegger { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_USB_EHCI, 70 1.45 cegger EHCI_PCI_QUIRK_AMD_SB600 }, 71 1.45 cegger { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_USB_EHCI, 72 1.45 cegger EHCI_PCI_QUIRK_AMD_SB700 }, 73 1.45 cegger }; 74 1.45 cegger 75 1.69 maxv static void ehci_release_ownership(ehci_softc_t *, pci_chipset_tag_t, pcitag_t); 76 1.69 maxv static void ehci_get_ownership(ehci_softc_t *, pci_chipset_tag_t, pcitag_t); 77 1.47 dyoung static bool ehci_pci_suspend(device_t, const pmf_qual_t *); 78 1.47 dyoung static bool ehci_pci_resume(device_t, const pmf_qual_t *); 79 1.19 augustss 80 1.1 augustss struct ehci_pci_softc { 81 1.1 augustss ehci_softc_t sc; 82 1.1 augustss pci_chipset_tag_t sc_pc; 83 1.1 augustss pcitag_t sc_tag; 84 1.68 jdolecek pci_intr_handle_t *sc_pihp; 85 1.1 augustss void *sc_ih; /* interrupt vectoring */ 86 1.70 maxv enum { 87 1.70 maxv EHCI_INIT_NONE, 88 1.77 mrg EHCI_INIT_OWNER, 89 1.70 maxv EHCI_INIT_INITED 90 1.70 maxv } sc_init_state; 91 1.1 augustss }; 92 1.1 augustss 93 1.77 mrg static void ehci_pci_release_resources(struct ehci_pci_softc *); 94 1.69 maxv static int ehci_sb700_match(const struct pci_attach_args *); 95 1.69 maxv static int ehci_apply_amd_quirks(struct ehci_pci_softc *); 96 1.69 maxv static enum ehci_pci_quirk_flags ehci_pci_lookup_quirkdata(pci_vendor_id_t, 97 1.69 maxv pci_product_id_t); 98 1.45 cegger 99 1.53 jmcneill #define EHCI_MAX_BIOS_WAIT 100 /* ms*10 */ 100 1.45 cegger #define EHCI_SBx00_WORKAROUND_REG 0x50 101 1.45 cegger #define EHCI_SBx00_WORKAROUND_ENABLE __BIT(27) 102 1.45 cegger 103 1.18 thorpej static int 104 1.41 dyoung ehci_pci_match(device_t parent, cfdata_t match, void *aux) 105 1.1 augustss { 106 1.1 augustss struct pci_attach_args *pa = (struct pci_attach_args *) aux; 107 1.1 augustss 108 1.1 augustss if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && 109 1.1 augustss PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && 110 1.1 augustss PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI) 111 1.41 dyoung return 1; 112 1.17 perry 113 1.41 dyoung return 0; 114 1.1 augustss } 115 1.1 augustss 116 1.18 thorpej static void 117 1.41 dyoung ehci_pci_attach(device_t parent, device_t self, void *aux) 118 1.1 augustss { 119 1.37 drochner struct ehci_pci_softc *sc = device_private(self); 120 1.1 augustss struct pci_attach_args *pa = (struct pci_attach_args *)aux; 121 1.1 augustss pci_chipset_tag_t pc = pa->pa_pc; 122 1.1 augustss pcitag_t tag = pa->pa_tag; 123 1.69 maxv char intrbuf[PCI_INTRSTR_LEN]; 124 1.1 augustss char const *intrstr; 125 1.69 maxv struct usb_pci *up; 126 1.69 maxv int ncomp, quirk; 127 1.1 augustss pcireg_t csr; 128 1.1 augustss 129 1.70 maxv sc->sc_init_state = EHCI_INIT_NONE; 130 1.37 drochner sc->sc.sc_dev = self; 131 1.63 skrll sc->sc.sc_bus.ub_hcpriv = sc; 132 1.37 drochner 133 1.54 drochner pci_aprint_devinfo(pa, "USB controller"); 134 1.1 augustss 135 1.45 cegger /* Check for quirks */ 136 1.45 cegger quirk = ehci_pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), 137 1.69 maxv PCI_PRODUCT(pa->pa_id)); 138 1.45 cegger 139 1.1 augustss /* Map I/O registers */ 140 1.1 augustss if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, 141 1.69 maxv &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) { 142 1.43 cegger sc->sc.sc_size = 0; 143 1.43 cegger aprint_error_dev(self, "can't map memory space\n"); 144 1.1 augustss return; 145 1.1 augustss } 146 1.1 augustss 147 1.60 msaitoh sc->sc_pc = pc; 148 1.60 msaitoh sc->sc_tag = tag; 149 1.73 skrll 150 1.73 skrll const uint32_t hccparams = EREAD4(&sc->sc, EHCI_HCCPARAMS); 151 1.73 skrll 152 1.73 skrll if (EHCI_HCC_64BIT(hccparams)) { 153 1.73 skrll aprint_verbose_dev(self, "64-bit DMA"); 154 1.73 skrll if (pci_dma64_available(pa)) { 155 1.73 skrll sc->sc.sc_bus.ub_dmatag = pa->pa_dmat64; 156 1.73 skrll aprint_verbose("\n"); 157 1.73 skrll } else { 158 1.73 skrll aprint_verbose(" - limited\n"); 159 1.73 skrll sc->sc.sc_bus.ub_dmatag = pa->pa_dmat; 160 1.73 skrll } 161 1.73 skrll } else { 162 1.73 skrll aprint_verbose_dev(self, "32-bit DMA\n"); 163 1.73 skrll sc->sc.sc_bus.ub_dmatag = pa->pa_dmat; 164 1.73 skrll } 165 1.60 msaitoh 166 1.43 cegger /* Disable interrupts, so we don't get any spurious ones. */ 167 1.43 cegger sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); 168 1.43 cegger DPRINTF(("%s: offs=%d\n", device_xname(self), sc->sc.sc_offs)); 169 1.56 uwe EOWRITE4(&sc->sc, EHCI_USBINTR, 0); 170 1.43 cegger 171 1.45 cegger /* Handle quirks */ 172 1.45 cegger switch (quirk) { 173 1.45 cegger case EHCI_PCI_QUIRK_AMD_SB600: 174 1.45 cegger ehci_apply_amd_quirks(sc); 175 1.45 cegger break; 176 1.45 cegger case EHCI_PCI_QUIRK_AMD_SB700: 177 1.45 cegger if (pci_find_device(NULL, ehci_sb700_match)) 178 1.45 cegger ehci_apply_amd_quirks(sc); 179 1.45 cegger break; 180 1.45 cegger } 181 1.45 cegger 182 1.65 sborrill pcireg_t intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); 183 1.65 sborrill int pin = PCI_INTERRUPT_PIN(intr); 184 1.65 sborrill 185 1.1 augustss /* Enable the device. */ 186 1.1 augustss csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 187 1.65 sborrill csr |= PCI_COMMAND_MASTER_ENABLE; 188 1.65 sborrill csr &= ~(pin ? PCI_COMMAND_INTERRUPT_DISABLE : 0); 189 1.65 sborrill pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, csr); 190 1.1 augustss 191 1.1 augustss /* Map and establish the interrupt. */ 192 1.68 jdolecek if (pci_intr_alloc(pa, &sc->sc_pihp, NULL, 0) != 0) { 193 1.43 cegger aprint_error_dev(self, "couldn't map interrupt\n"); 194 1.43 cegger goto fail; 195 1.1 augustss } 196 1.43 cegger 197 1.43 cegger /* 198 1.43 cegger * Allocate IRQ 199 1.43 cegger */ 200 1.68 jdolecek intrstr = pci_intr_string(pc, sc->sc_pihp[0], intrbuf, sizeof(intrbuf)); 201 1.76 mlelstv pci_intr_setattr(pc, &sc->sc_pihp[0], PCI_INTR_MPSAFE, true); 202 1.68 jdolecek sc->sc_ih = pci_intr_establish_xname(pc, sc->sc_pihp[0], IPL_USB, 203 1.68 jdolecek ehci_intr, sc, device_xname(self)); 204 1.1 augustss if (sc->sc_ih == NULL) { 205 1.43 cegger aprint_error_dev(self, "couldn't establish interrupt"); 206 1.1 augustss if (intrstr != NULL) 207 1.43 cegger aprint_error(" at %s", intrstr); 208 1.43 cegger aprint_error("\n"); 209 1.62 skrll goto fail; 210 1.1 augustss } 211 1.43 cegger aprint_normal_dev(self, "interrupting at %s\n", intrstr); 212 1.1 augustss 213 1.67 msaitoh switch (pci_conf_read(pc, tag, PCI_USBREV) & PCI_USBREV_MASK) { 214 1.1 augustss case PCI_USBREV_PRE_1_0: 215 1.1 augustss case PCI_USBREV_1_0: 216 1.1 augustss case PCI_USBREV_1_1: 217 1.63 skrll sc->sc.sc_bus.ub_revision = USBREV_UNKNOWN; 218 1.69 maxv aprint_verbose_dev(self, "pre-2.0 USB rev, device ignored\n"); 219 1.62 skrll goto fail; 220 1.1 augustss case PCI_USBREV_2_0: 221 1.63 skrll sc->sc.sc_bus.ub_revision = USBREV_2_0; 222 1.1 augustss break; 223 1.1 augustss default: 224 1.63 skrll sc->sc.sc_bus.ub_revision = USBREV_UNKNOWN; 225 1.1 augustss break; 226 1.1 augustss } 227 1.1 augustss 228 1.22 xtraeme /* Enable workaround for dropped interrupts as required */ 229 1.66 jakllsch switch (PCI_VENDOR(pa->pa_id)) { 230 1.30 tsutsui case PCI_VENDOR_ATI: 231 1.30 tsutsui case PCI_VENDOR_VIATECH: 232 1.22 xtraeme sc->sc.sc_flags |= EHCIF_DROPPED_INTR_WORKAROUND; 233 1.43 cegger aprint_normal_dev(self, "dropped intr workaround enabled\n"); 234 1.30 tsutsui break; 235 1.30 tsutsui default: 236 1.30 tsutsui break; 237 1.30 tsutsui } 238 1.22 xtraeme 239 1.5 augustss /* 240 1.5 augustss * Find companion controllers. According to the spec they always 241 1.5 augustss * have lower function numbers so they should be enumerated already. 242 1.5 augustss */ 243 1.50 matt const u_int maxncomp = EHCI_HCS_N_CC(EREAD4(&sc->sc, EHCI_HCSPARAMS)); 244 1.50 matt KASSERT(maxncomp <= EHCI_COMPANION_MAX); 245 1.5 augustss ncomp = 0; 246 1.78 riastrad KASSERT(KERNEL_LOCKED_P()); /* XXXSMP ehci_pci_alldevs */ 247 1.5 augustss TAILQ_FOREACH(up, &ehci_pci_alldevs, next) { 248 1.69 maxv if (up->bus == pa->pa_bus && up->device == pa->pa_device && 249 1.69 maxv !up->claimed) { 250 1.5 augustss DPRINTF(("ehci_pci_attach: companion %s\n", 251 1.69 maxv device_xname(up->usb))); 252 1.5 augustss sc->sc.sc_comps[ncomp++] = up->usb; 253 1.50 matt up->claimed = true; 254 1.50 matt if (ncomp == maxncomp) 255 1.5 augustss break; 256 1.5 augustss } 257 1.5 augustss } 258 1.5 augustss sc->sc.sc_ncomp = ncomp; 259 1.5 augustss 260 1.19 augustss ehci_get_ownership(&sc->sc, pc, tag); 261 1.77 mrg sc->sc_init_state = EHCI_INIT_OWNER; 262 1.19 augustss 263 1.63 skrll int err = ehci_init(&sc->sc); 264 1.63 skrll if (err) { 265 1.63 skrll aprint_error_dev(self, "init failed, error=%d\n", err); 266 1.43 cegger goto fail; 267 1.1 augustss } 268 1.70 maxv sc->sc_init_state = EHCI_INIT_INITED; 269 1.1 augustss 270 1.77 mrg pmf_device_register1(self, ehci_pci_suspend, ehci_pci_resume, 271 1.77 mrg ehci_shutdown); 272 1.32 jmcneill 273 1.1 augustss /* Attach usb device. */ 274 1.71 thorpej sc->sc.sc_child = config_found(self, &sc->sc.sc_bus, usbctlprint, 275 1.72 thorpej CFARGS_NONE); 276 1.43 cegger return; 277 1.43 cegger 278 1.43 cegger fail: 279 1.77 mrg ehci_pci_release_resources(sc); 280 1.77 mrg pmf_device_register(self, NULL, NULL); 281 1.77 mrg } 282 1.77 mrg 283 1.77 mrg static void 284 1.77 mrg ehci_pci_release_resources(struct ehci_pci_softc *sc) 285 1.77 mrg { 286 1.77 mrg if (sc->sc_init_state >= EHCI_INIT_OWNER) 287 1.77 mrg ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); 288 1.77 mrg 289 1.43 cegger if (sc->sc_ih) { 290 1.43 cegger pci_intr_disestablish(sc->sc_pc, sc->sc_ih); 291 1.43 cegger sc->sc_ih = NULL; 292 1.43 cegger } 293 1.77 mrg if (sc->sc_pihp != NULL) { 294 1.77 mrg pci_intr_release(sc->sc_pc, sc->sc_pihp, 1); 295 1.77 mrg sc->sc_pihp = NULL; 296 1.77 mrg } 297 1.77 mrg 298 1.43 cegger if (sc->sc.sc_size) { 299 1.43 cegger bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); 300 1.43 cegger sc->sc.sc_size = 0; 301 1.43 cegger } 302 1.77 mrg 303 1.77 mrg sc->sc_init_state = EHCI_INIT_NONE; 304 1.1 augustss } 305 1.1 augustss 306 1.18 thorpej static int 307 1.41 dyoung ehci_pci_detach(device_t self, int flags) 308 1.1 augustss { 309 1.37 drochner struct ehci_pci_softc *sc = device_private(self); 310 1.1 augustss int rv; 311 1.1 augustss 312 1.70 maxv if (sc->sc_init_state >= EHCI_INIT_INITED) { 313 1.70 maxv rv = ehci_detach(&sc->sc, flags); 314 1.70 maxv if (rv) 315 1.70 maxv return rv; 316 1.70 maxv } 317 1.40 dyoung 318 1.52 dyoung pmf_device_deregister(self); 319 1.52 dyoung ehci_shutdown(self, flags); 320 1.52 dyoung 321 1.77 mrg if (sc->sc_init_state >= EHCI_INIT_INITED) { 322 1.77 mrg /* disable interrupts */ 323 1.77 mrg EOWRITE4(&sc->sc, EHCI_USBINTR, 0); 324 1.77 mrg /* XXX grotty hack to flush the write */ 325 1.77 mrg (void)EOREAD4(&sc->sc, EHCI_USBINTR); 326 1.68 jdolecek } 327 1.68 jdolecek 328 1.77 mrg ehci_pci_release_resources(sc); 329 1.34 jmcneill 330 1.55 mrg #if 1 331 1.55 mrg /* XXX created in ehci.c */ 332 1.70 maxv if (sc->sc_init_state >= EHCI_INIT_INITED) { 333 1.74 riastrad mutex_destroy(&sc->sc.sc_rhlock); 334 1.70 maxv mutex_destroy(&sc->sc.sc_lock); 335 1.70 maxv mutex_destroy(&sc->sc.sc_intr_lock); 336 1.70 maxv softint_disestablish(sc->sc.sc_doorbell_si); 337 1.70 maxv softint_disestablish(sc->sc.sc_pcd_si); 338 1.70 maxv } 339 1.55 mrg #endif 340 1.55 mrg 341 1.41 dyoung return 0; 342 1.1 augustss } 343 1.18 thorpej 344 1.39 dyoung CFATTACH_DECL3_NEW(ehci_pci, sizeof(struct ehci_pci_softc), 345 1.35 dyoung ehci_pci_match, ehci_pci_attach, ehci_pci_detach, ehci_activate, NULL, 346 1.39 dyoung ehci_childdet, DVF_DETACH_SHUTDOWN); 347 1.19 augustss 348 1.19 augustss #ifdef EHCI_DEBUG 349 1.19 augustss static void 350 1.19 augustss ehci_dump_caps(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag) 351 1.19 augustss { 352 1.44 cegger uint32_t cparams, legctlsts, addr, cap, id; 353 1.19 augustss int maxdump = 10; 354 1.19 augustss 355 1.19 augustss cparams = EREAD4(sc, EHCI_HCCPARAMS); 356 1.19 augustss addr = EHCI_HCC_EECP(cparams); 357 1.19 augustss while (addr != 0) { 358 1.19 augustss cap = pci_conf_read(pc, tag, addr); 359 1.19 augustss id = EHCI_CAP_GET_ID(cap); 360 1.19 augustss switch (id) { 361 1.19 augustss case EHCI_CAP_ID_LEGACY: 362 1.19 augustss legctlsts = pci_conf_read(pc, tag, 363 1.60 msaitoh addr + PCI_EHCI_USBLEGCTLSTS); 364 1.20 augustss printf("ehci_dump_caps: legsup=0x%08x " 365 1.20 augustss "legctlsts=0x%08x\n", cap, legctlsts); 366 1.19 augustss break; 367 1.19 augustss default: 368 1.20 augustss printf("ehci_dump_caps: cap=0x%08x\n", cap); 369 1.19 augustss break; 370 1.19 augustss } 371 1.19 augustss if (--maxdump < 0) 372 1.19 augustss break; 373 1.19 augustss addr = EHCI_CAP_GET_NEXT(cap); 374 1.19 augustss } 375 1.19 augustss } 376 1.19 augustss #endif 377 1.19 augustss 378 1.19 augustss static void 379 1.34 jmcneill ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag) 380 1.34 jmcneill { 381 1.37 drochner const char *devname = device_xname(sc->sc_dev); 382 1.44 cegger uint32_t cparams, addr, cap; 383 1.34 jmcneill pcireg_t legsup; 384 1.34 jmcneill int maxcap = 10; 385 1.34 jmcneill 386 1.34 jmcneill cparams = EREAD4(sc, EHCI_HCCPARAMS); 387 1.34 jmcneill addr = EHCI_HCC_EECP(cparams); 388 1.34 jmcneill while (addr != 0) { 389 1.34 jmcneill cap = pci_conf_read(pc, tag, addr); 390 1.34 jmcneill if (EHCI_CAP_GET_ID(cap) != EHCI_CAP_ID_LEGACY) 391 1.34 jmcneill goto next; 392 1.34 jmcneill legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP); 393 1.34 jmcneill pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, 394 1.34 jmcneill legsup & ~EHCI_LEG_HC_OS_OWNED); 395 1.34 jmcneill 396 1.34 jmcneill next: 397 1.34 jmcneill if (--maxcap < 0) { 398 1.34 jmcneill aprint_normal("%s: broken extended capabilities " 399 1.34 jmcneill "ignored\n", devname); 400 1.34 jmcneill return; 401 1.34 jmcneill } 402 1.34 jmcneill addr = EHCI_CAP_GET_NEXT(cap); 403 1.34 jmcneill } 404 1.34 jmcneill } 405 1.34 jmcneill 406 1.34 jmcneill static void 407 1.19 augustss ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, pcitag_t tag) 408 1.19 augustss { 409 1.37 drochner const char *devname = device_xname(sc->sc_dev); 410 1.44 cegger uint32_t cparams, addr, cap; 411 1.33 jmcneill pcireg_t legsup; 412 1.19 augustss int maxcap = 10; 413 1.19 augustss int ms; 414 1.19 augustss 415 1.19 augustss #ifdef EHCI_DEBUG 416 1.20 augustss if (ehcidebug) 417 1.20 augustss ehci_dump_caps(sc, pc, tag); 418 1.19 augustss #endif 419 1.19 augustss cparams = EREAD4(sc, EHCI_HCCPARAMS); 420 1.19 augustss addr = EHCI_HCC_EECP(cparams); 421 1.19 augustss while (addr != 0) { 422 1.19 augustss cap = pci_conf_read(pc, tag, addr); 423 1.34 jmcneill if (EHCI_CAP_GET_ID(cap) != EHCI_CAP_ID_LEGACY) 424 1.34 jmcneill goto next; 425 1.34 jmcneill legsup = pci_conf_read(pc, tag, addr + PCI_EHCI_USBLEGSUP); 426 1.34 jmcneill if (legsup & EHCI_LEG_HC_BIOS_OWNED) { 427 1.53 jmcneill /* Ask BIOS to give up ownership */ 428 1.53 jmcneill pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGSUP, 429 1.57 tsutsui legsup | EHCI_LEG_HC_OS_OWNED); 430 1.34 jmcneill for (ms = 0; ms < EHCI_MAX_BIOS_WAIT; ms++) { 431 1.34 jmcneill legsup = pci_conf_read(pc, tag, 432 1.34 jmcneill addr + PCI_EHCI_USBLEGSUP); 433 1.34 jmcneill if (!(legsup & EHCI_LEG_HC_BIOS_OWNED)) 434 1.34 jmcneill break; 435 1.53 jmcneill delay(10000); 436 1.34 jmcneill } 437 1.34 jmcneill if (ms == EHCI_MAX_BIOS_WAIT) { 438 1.34 jmcneill aprint_normal("%s: BIOS refuses to give up " 439 1.34 jmcneill "ownership, using force\n", devname); 440 1.34 jmcneill pci_conf_write(pc, tag, 441 1.34 jmcneill addr + PCI_EHCI_USBLEGSUP, 0); 442 1.34 jmcneill } else 443 1.34 jmcneill aprint_verbose("%s: BIOS has given up " 444 1.34 jmcneill "ownership\n", devname); 445 1.34 jmcneill } 446 1.34 jmcneill 447 1.34 jmcneill /* Disable SMIs */ 448 1.53 jmcneill pci_conf_write(pc, tag, addr + PCI_EHCI_USBLEGCTLSTS, 0); 449 1.34 jmcneill 450 1.34 jmcneill next: 451 1.21 augustss if (--maxcap < 0) { 452 1.21 augustss aprint_normal("%s: broken extended capabilities " 453 1.21 augustss "ignored\n", devname); 454 1.19 augustss return; 455 1.21 augustss } 456 1.19 augustss addr = EHCI_CAP_GET_NEXT(cap); 457 1.19 augustss } 458 1.19 augustss 459 1.34 jmcneill } 460 1.34 jmcneill 461 1.34 jmcneill static bool 462 1.47 dyoung ehci_pci_suspend(device_t dv, const pmf_qual_t *qual) 463 1.34 jmcneill { 464 1.34 jmcneill struct ehci_pci_softc *sc = device_private(dv); 465 1.28 jmcneill 466 1.46 dyoung ehci_suspend(dv, qual); 467 1.34 jmcneill ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); 468 1.33 jmcneill 469 1.34 jmcneill return true; 470 1.19 augustss } 471 1.23 jmcneill 472 1.32 jmcneill static bool 473 1.47 dyoung ehci_pci_resume(device_t dv, const pmf_qual_t *qual) 474 1.23 jmcneill { 475 1.32 jmcneill struct ehci_pci_softc *sc = device_private(dv); 476 1.23 jmcneill 477 1.32 jmcneill ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); 478 1.46 dyoung return ehci_resume(dv, qual); 479 1.23 jmcneill } 480 1.45 cegger 481 1.45 cegger static int 482 1.51 dyoung ehci_sb700_match(const struct pci_attach_args *pa) 483 1.45 cegger { 484 1.45 cegger if (!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && 485 1.45 cegger PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB)) 486 1.45 cegger return 0; 487 1.45 cegger 488 1.45 cegger switch (PCI_REVISION(pa->pa_class)) { 489 1.45 cegger case 0x3a: 490 1.45 cegger case 0x3b: 491 1.45 cegger return 1; 492 1.45 cegger } 493 1.45 cegger 494 1.45 cegger return 0; 495 1.45 cegger } 496 1.45 cegger 497 1.45 cegger static int 498 1.45 cegger ehci_apply_amd_quirks(struct ehci_pci_softc *sc) 499 1.45 cegger { 500 1.45 cegger pcireg_t value; 501 1.63 skrll 502 1.45 cegger aprint_normal_dev(sc->sc.sc_dev, 503 1.45 cegger "applying AMD SB600/SB700 USB freeze workaround\n"); 504 1.45 cegger value = pci_conf_read(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG); 505 1.45 cegger pci_conf_write(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG, 506 1.45 cegger value | EHCI_SBx00_WORKAROUND_ENABLE); 507 1.45 cegger 508 1.45 cegger return 0; 509 1.45 cegger } 510 1.45 cegger 511 1.69 maxv static enum ehci_pci_quirk_flags 512 1.45 cegger ehci_pci_lookup_quirkdata(pci_vendor_id_t vendor, pci_product_id_t product) 513 1.45 cegger { 514 1.45 cegger int i; 515 1.45 cegger 516 1.45 cegger for (i = 0; i < __arraycount(ehci_pci_quirks); i++) { 517 1.45 cegger if (vendor == ehci_pci_quirks[i].vendor && 518 1.45 cegger product == ehci_pci_quirks[i].product) 519 1.45 cegger return ehci_pci_quirks[i].quirks; 520 1.45 cegger } 521 1.45 cegger return 0; 522 1.45 cegger } 523 1.45 cegger 524