summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheo de Raadt <deraadt@cvs.openbsd.org>2009-06-25 01:01:45 +0000
committerTheo de Raadt <deraadt@cvs.openbsd.org>2009-06-25 01:01:45 +0000
commit25e506ec40306291fd04e2b1fdb6ad0df65babd9 (patch)
tree6b4db2d6b3c96d52713e8e91d4e6f49932be5cad
parent4d31aa53053448c672c3826ea93679b53409f525 (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
-rw-r--r--sys/dev/pci/ehci_pci.c35
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);
+}