diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2009-06-25 01:01:45 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2009-06-25 01:01:45 +0000 |
commit | 25e506ec40306291fd04e2b1fdb6ad0df65babd9 (patch) | |
tree | 6b4db2d6b3c96d52713e8e91d4e6f49932be5cad /sys | |
parent | 4d31aa53053448c672c3826ea93679b53409f525 (diff) |
Workaround a stupid problem ATI SB600 revisions and ATI SB700 south
bridge revisions A12 and A13. We really don't know what it does,
but then noone else does.
From NetBSD and Linux, via brad
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/ehci_pci.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/sys/dev/pci/ehci_pci.c b/sys/dev/pci/ehci_pci.c index 56d804fbd84..a2637ea4cba 100644 --- a/sys/dev/pci/ehci_pci.c +++ b/sys/dev/pci/ehci_pci.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ehci_pci.c,v 1.15 2009/03/29 21:53:52 sthen Exp $ */ +/* $OpenBSD: ehci_pci.c,v 1.16 2009/06/25 01:01:44 deraadt Exp $ */ /* $NetBSD: ehci_pci.c,v 1.15 2004/04/23 21:13:06 itojun Exp $ */ /* @@ -65,6 +65,11 @@ struct ehci_pci_softc { void *sc_ih; /* interrupt vectoring */ }; +int ehci_sb700_match(struct pci_attach_args *pa); + +#define EHCI_SBx00_WORKAROUND_REG 0x50 +#define EHCI_SBx00_WORKAROUND_ENABLE (1 << 3) + int ehci_pci_match(struct device *, void *, void *); void ehci_pci_attach(struct device *, struct device *, void *); int ehci_pci_detach(struct device *, int); @@ -77,7 +82,6 @@ struct cfattach ehci_pci_ca = { ehci_pci_detach, ehci_activate }; - int ehci_pci_match(struct device *parent, void *match, void *aux) { @@ -122,6 +126,21 @@ ehci_pci_attach(struct device *parent, struct device *self, void *aux) DPRINTF(("%s: offs=%d\n", devname, sc->sc.sc_offs)); EOWRITE2(&sc->sc, EHCI_USBINTR, 0); + /* Handle quirks */ + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && + ((PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB600_EHCI || + (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SB700_EHCI && + pci_find_device(NULL, ehci_sb700_match))))) { + pcireg_t value; + + /* apply the ATI SB600/SB700 workaround */ + value = pci_conf_read(sc->sc_pc, sc->sc_tag, + EHCI_SBx00_WORKAROUND_REG); + pci_conf_write(sc->sc_pc, sc->sc_tag, + EHCI_SBx00_WORKAROUND_REG, value | + EHCI_SBx00_WORKAROUND_ENABLE); + } + /* Map and establish the interrupt. */ if (pci_intr_map(pa, &ih)) { printf(": couldn't map interrupt\n"); @@ -271,3 +290,15 @@ ehci_pci_shutdown(void *v) ehci_pci_givecontroller(sc); #endif } + +int +ehci_sb700_match(struct pci_attach_args *pa) +{ + if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_ATI && + PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_ATI_SBX00_SMB && + (PCI_REVISION(pa->pa_class) == 0x3a || + PCI_REVISION(pa->pa_class) == 0x3b)) + return (1); + + return (0); +} |