| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $ */ | | 1 | /* $NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2001, 2002 The NetBSD Foundation, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation | | 7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Lennart Augustsson (lennart@augustsson.net). | | 8 | * by Lennart Augustsson (lennart@augustsson.net). |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -20,27 +20,27 @@ | | | @@ -20,27 +20,27 @@ |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | | 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 | | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | 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 | | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | 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 | | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. | | 29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38 2008/04/28 20:23:54 martin Exp $"); | | 33 | __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v 1.38.10.1 2009/06/17 20:33:39 bouyer Exp $"); |
34 | | | 34 | |
35 | #include <sys/param.h> | | 35 | #include <sys/param.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
37 | #include <sys/kernel.h> | | 37 | #include <sys/kernel.h> |
38 | #include <sys/device.h> | | 38 | #include <sys/device.h> |
39 | #include <sys/proc.h> | | 39 | #include <sys/proc.h> |
40 | #include <sys/queue.h> | | 40 | #include <sys/queue.h> |
41 | | | 41 | |
42 | #include <sys/bus.h> | | 42 | #include <sys/bus.h> |
43 | | | 43 | |
44 | #include <dev/pci/pcidevs.h> | | 44 | #include <dev/pci/pcidevs.h> |
45 | #include <dev/pci/pcivar.h> | | 45 | #include <dev/pci/pcivar.h> |
46 | #include <dev/pci/usb_pci.h> | | 46 | #include <dev/pci/usb_pci.h> |
| @@ -50,41 +50,61 @@ __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v | | | @@ -50,41 +50,61 @@ __KERNEL_RCSID(0, "$NetBSD: ehci_pci.c,v |
50 | #include <dev/usb/usbdivar.h> | | 50 | #include <dev/usb/usbdivar.h> |
51 | #include <dev/usb/usb_mem.h> | | 51 | #include <dev/usb/usb_mem.h> |
52 | | | 52 | |
53 | #include <dev/usb/ehcireg.h> | | 53 | #include <dev/usb/ehcireg.h> |
54 | #include <dev/usb/ehcivar.h> | | 54 | #include <dev/usb/ehcivar.h> |
55 | | | 55 | |
56 | #ifdef EHCI_DEBUG | | 56 | #ifdef EHCI_DEBUG |
57 | #define DPRINTF(x) if (ehcidebug) printf x | | 57 | #define DPRINTF(x) if (ehcidebug) printf x |
58 | extern int ehcidebug; | | 58 | extern int ehcidebug; |
59 | #else | | 59 | #else |
60 | #define DPRINTF(x) | | 60 | #define DPRINTF(x) |
61 | #endif | | 61 | #endif |
62 | | | 62 | |
| | | 63 | enum ehci_pci_quirk_flags { |
| | | 64 | EHCI_PCI_QUIRK_AMD_SB600 = 0x1, /* always need a quirk */ |
| | | 65 | EHCI_PCI_QUIRK_AMD_SB700 = 0x2, /* depends on the SMB revision */ |
| | | 66 | }; |
| | | 67 | |
| | | 68 | static const struct pci_quirkdata ehci_pci_quirks[] = { |
| | | 69 | { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB600_USB_EHCI, |
| | | 70 | EHCI_PCI_QUIRK_AMD_SB600 }, |
| | | 71 | { PCI_VENDOR_ATI, PCI_PRODUCT_ATI_SB700_USB_EHCI, |
| | | 72 | EHCI_PCI_QUIRK_AMD_SB700 }, |
| | | 73 | }; |
| | | 74 | |
63 | static void ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, | | 75 | static void ehci_release_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, |
64 | pcitag_t tag); | | 76 | pcitag_t tag); |
65 | static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, | | 77 | static void ehci_get_ownership(ehci_softc_t *sc, pci_chipset_tag_t pc, |
66 | pcitag_t tag); | | 78 | pcitag_t tag); |
67 | static bool ehci_pci_suspend(device_t PMF_FN_PROTO); | | 79 | static bool ehci_pci_suspend(device_t PMF_FN_PROTO); |
68 | static bool ehci_pci_resume(device_t PMF_FN_PROTO); | | 80 | static bool ehci_pci_resume(device_t PMF_FN_PROTO); |
69 | | | 81 | |
70 | struct ehci_pci_softc { | | 82 | struct ehci_pci_softc { |
71 | ehci_softc_t sc; | | 83 | ehci_softc_t sc; |
72 | pci_chipset_tag_t sc_pc; | | 84 | pci_chipset_tag_t sc_pc; |
73 | pcitag_t sc_tag; | | 85 | pcitag_t sc_tag; |
74 | void *sc_ih; /* interrupt vectoring */ | | 86 | void *sc_ih; /* interrupt vectoring */ |
75 | }; | | 87 | }; |
76 | | | 88 | |
| | | 89 | static int ehci_sb700_match(struct pci_attach_args *pa); |
| | | 90 | static int ehci_apply_amd_quirks(struct ehci_pci_softc *sc); |
| | | 91 | enum ehci_pci_quirk_flags ehci_pci_lookup_quirkdata(pci_vendor_id_t, |
| | | 92 | pci_product_id_t); |
| | | 93 | |
77 | #define EHCI_MAX_BIOS_WAIT 1000 /* ms */ | | 94 | #define EHCI_MAX_BIOS_WAIT 1000 /* ms */ |
| | | 95 | #define EHCI_SBx00_WORKAROUND_REG 0x50 |
| | | 96 | #define EHCI_SBx00_WORKAROUND_ENABLE __BIT(27) |
| | | 97 | |
78 | | | 98 | |
79 | static int | | 99 | static int |
80 | ehci_pci_match(struct device *parent, struct cfdata *match, | | 100 | ehci_pci_match(struct device *parent, struct cfdata *match, |
81 | void *aux) | | 101 | void *aux) |
82 | { | | 102 | { |
83 | struct pci_attach_args *pa = (struct pci_attach_args *) aux; | | 103 | struct pci_attach_args *pa = (struct pci_attach_args *) aux; |
84 | | | 104 | |
85 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && | | 105 | if (PCI_CLASS(pa->pa_class) == PCI_CLASS_SERIALBUS && |
86 | PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && | | 106 | PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_SERIALBUS_USB && |
87 | PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI) | | 107 | PCI_INTERFACE(pa->pa_class) == PCI_INTERFACE_EHCI) |
88 | return (1); | | 108 | return (1); |
89 | | | 109 | |
90 | return (0); | | 110 | return (0); |
| @@ -96,47 +116,63 @@ ehci_pci_attach(struct device *parent, s | | | @@ -96,47 +116,63 @@ ehci_pci_attach(struct device *parent, s |
96 | struct ehci_pci_softc *sc = device_private(self); | | 116 | struct ehci_pci_softc *sc = device_private(self); |
97 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; | | 117 | struct pci_attach_args *pa = (struct pci_attach_args *)aux; |
98 | pci_chipset_tag_t pc = pa->pa_pc; | | 118 | pci_chipset_tag_t pc = pa->pa_pc; |
99 | pcitag_t tag = pa->pa_tag; | | 119 | pcitag_t tag = pa->pa_tag; |
100 | char const *intrstr; | | 120 | char const *intrstr; |
101 | pci_intr_handle_t ih; | | 121 | pci_intr_handle_t ih; |
102 | pcireg_t csr; | | 122 | pcireg_t csr; |
103 | const char *vendor; | | 123 | const char *vendor; |
104 | const char *devname = device_xname(self); | | 124 | const char *devname = device_xname(self); |
105 | char devinfo[256]; | | 125 | char devinfo[256]; |
106 | usbd_status r; | | 126 | usbd_status r; |
107 | int ncomp; | | 127 | int ncomp; |
108 | struct usb_pci *up; | | 128 | struct usb_pci *up; |
| | | 129 | int quirk; |
109 | | | 130 | |
110 | sc->sc.sc_dev = self; | | 131 | sc->sc.sc_dev = self; |
111 | sc->sc.sc_bus.hci_private = sc; | | 132 | sc->sc.sc_bus.hci_private = sc; |
112 | | | 133 | |
113 | aprint_naive(": USB controller\n"); | | 134 | aprint_naive(": USB controller\n"); |
114 | | | 135 | |
115 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); | | 136 | pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo, sizeof(devinfo)); |
116 | aprint_normal(": %s (rev. 0x%02x)\n", devinfo, | | 137 | aprint_normal(": %s (rev. 0x%02x)\n", devinfo, |
117 | PCI_REVISION(pa->pa_class)); | | 138 | PCI_REVISION(pa->pa_class)); |
118 | | | 139 | |
| | | 140 | /* Check for quirks */ |
| | | 141 | quirk = ehci_pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), |
| | | 142 | PCI_PRODUCT(pa->pa_id)); |
| | | 143 | |
119 | /* Map I/O registers */ | | 144 | /* Map I/O registers */ |
120 | if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, | | 145 | if (pci_mapreg_map(pa, PCI_CBMEM, PCI_MAPREG_TYPE_MEM, 0, |
121 | &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) { | | 146 | &sc->sc.iot, &sc->sc.ioh, NULL, &sc->sc.sc_size)) { |
122 | aprint_error("%s: can't map memory space\n", devname); | | 147 | aprint_error("%s: can't map memory space\n", devname); |
123 | return; | | 148 | return; |
124 | } | | 149 | } |
125 | | | 150 | |
126 | sc->sc_pc = pc; | | 151 | sc->sc_pc = pc; |
127 | sc->sc_tag = tag; | | 152 | sc->sc_tag = tag; |
128 | sc->sc.sc_bus.dmatag = pa->pa_dmat; | | 153 | sc->sc.sc_bus.dmatag = pa->pa_dmat; |
129 | | | 154 | |
| | | 155 | /* Handle quirks */ |
| | | 156 | switch (quirk) { |
| | | 157 | case EHCI_PCI_QUIRK_AMD_SB600: |
| | | 158 | ehci_apply_amd_quirks(sc); |
| | | 159 | break; |
| | | 160 | case EHCI_PCI_QUIRK_AMD_SB700: |
| | | 161 | if (pci_find_device(NULL, ehci_sb700_match)) |
| | | 162 | ehci_apply_amd_quirks(sc); |
| | | 163 | break; |
| | | 164 | } |
| | | 165 | |
130 | /* Enable the device. */ | | 166 | /* Enable the device. */ |
131 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 167 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
132 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, | | 168 | pci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, |
133 | csr | PCI_COMMAND_MASTER_ENABLE); | | 169 | csr | PCI_COMMAND_MASTER_ENABLE); |
134 | | | 170 | |
135 | /* Disable interrupts, so we don't get any spurious ones. */ | | 171 | /* Disable interrupts, so we don't get any spurious ones. */ |
136 | sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); | | 172 | sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); |
137 | DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs)); | | 173 | DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs)); |
138 | EOWRITE2(&sc->sc, EHCI_USBINTR, 0); | | 174 | EOWRITE2(&sc->sc, EHCI_USBINTR, 0); |
139 | | | 175 | |
140 | /* Map and establish the interrupt. */ | | 176 | /* Map and establish the interrupt. */ |
141 | if (pci_intr_map(pa, &ih)) { | | 177 | if (pci_intr_map(pa, &ih)) { |
142 | aprint_error("%s: couldn't map interrupt\n", devname); | | 178 | aprint_error("%s: couldn't map interrupt\n", devname); |
| @@ -371,13 +407,57 @@ ehci_pci_suspend(device_t dv PMF_FN_ARGS | | | @@ -371,13 +407,57 @@ ehci_pci_suspend(device_t dv PMF_FN_ARGS |
371 | ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); | | 407 | ehci_release_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); |
372 | | | 408 | |
373 | return true; | | 409 | return true; |
374 | } | | 410 | } |
375 | | | 411 | |
376 | static bool | | 412 | static bool |
377 | ehci_pci_resume(device_t dv PMF_FN_ARGS) | | 413 | ehci_pci_resume(device_t dv PMF_FN_ARGS) |
378 | { | | 414 | { |
379 | struct ehci_pci_softc *sc = device_private(dv); | | 415 | struct ehci_pci_softc *sc = device_private(dv); |
380 | | | 416 | |
381 | ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); | | 417 | ehci_get_ownership(&sc->sc, sc->sc_pc, sc->sc_tag); |
382 | return ehci_resume(dv PMF_FN_CALL); | | 418 | return ehci_resume(dv PMF_FN_CALL); |
383 | } | | 419 | } |
| | | 420 | |
| | | 421 | static int |
| | | 422 | ehci_sb700_match(struct pci_attach_args *pa) |
| | | 423 | { |
| | | 424 | if (!(PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && |
| | | 425 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_SMB)) |
| | | 426 | return 0; |
| | | 427 | |
| | | 428 | switch (PCI_REVISION(pa->pa_class)) { |
| | | 429 | case 0x3a: |
| | | 430 | case 0x3b: |
| | | 431 | return 1; |
| | | 432 | } |
| | | 433 | |
| | | 434 | return 0; |
| | | 435 | } |
| | | 436 | |
| | | 437 | static int |
| | | 438 | ehci_apply_amd_quirks(struct ehci_pci_softc *sc) |
| | | 439 | { |
| | | 440 | pcireg_t value; |
| | | 441 | |
| | | 442 | aprint_normal_dev(sc->sc.sc_dev, |
| | | 443 | "applying AMD SB600/SB700 USB freeze workaround\n"); |
| | | 444 | value = pci_conf_read(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG); |
| | | 445 | pci_conf_write(sc->sc_pc, sc->sc_tag, EHCI_SBx00_WORKAROUND_REG, |
| | | 446 | value | EHCI_SBx00_WORKAROUND_ENABLE); |
| | | 447 | |
| | | 448 | return 0; |
| | | 449 | } |
| | | 450 | |
| | | 451 | enum ehci_pci_quirk_flags |
| | | 452 | ehci_pci_lookup_quirkdata(pci_vendor_id_t vendor, pci_product_id_t product) |
| | | 453 | { |
| | | 454 | int i; |
| | | 455 | |
| | | 456 | for (i = 0; i < __arraycount(ehci_pci_quirks); i++) { |
| | | 457 | if (vendor == ehci_pci_quirks[i].vendor && |
| | | 458 | product == ehci_pci_quirks[i].product) |
| | | 459 | return ehci_pci_quirks[i].quirks; |
| | | 460 | } |
| | | 461 | return 0; |
| | | 462 | } |
| | | 463 | |