summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2012-12-04 10:42:06 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2012-12-04 10:42:06 +0000
commitd6cd66921e4dc4c3a682d3fee2043db89ef05f46 (patch)
treed1e3f5da78dc4380edb832e5b73855189374619f /sys/dev
parent7b181098c490d2c366a02e6d54d29e83bc995bd2 (diff)
Add support for Uninorth AGP bridges found in most if not all the macppc
machines with a G3 or G4 microprocessor. It would not be difficult to add support for U3 bridges found in G5 powered macppc to this driver but I don't have such hardware.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/agp_apple.c214
-rw-r--r--sys/dev/pci/agpreg.h13
-rw-r--r--sys/dev/pci/files.agp6
3 files changed, 231 insertions, 2 deletions
diff --git a/sys/dev/pci/agp_apple.c b/sys/dev/pci/agp_apple.c
new file mode 100644
index 00000000000..10fed199f48
--- /dev/null
+++ b/sys/dev/pci/agp_apple.c
@@ -0,0 +1,214 @@
+/* $OpenBSD: agp_apple.c,v 1.1 2012/12/04 10:42:04 mpi Exp $ */
+
+/*
+ * Copyright (c) 2012 Martin Pieuchot <mpi@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/agpio.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+#include <dev/pci/pcidevs.h>
+#include <dev/pci/agpvar.h>
+#include <dev/pci/agpreg.h>
+
+#include <machine/bus.h>
+
+#define M (1024 * 1024)
+
+struct agp_apple_softc {
+ struct device dev;
+ struct agp_softc *agpdev;
+ struct agp_gatt *gatt;
+ pci_chipset_tag_t asc_pc;
+ pcitag_t asc_tag;
+ bus_addr_t asc_apaddr;
+ bus_size_t asc_apsize;
+};
+
+int agp_apple_match(struct device *, void *, void *);
+void agp_apple_attach(struct device *, struct device *, void *);
+bus_size_t agp_apple_get_aperture(void *);
+int agp_apple_set_aperture(void *sc, bus_size_t);
+void agp_apple_bind_page(void *, bus_addr_t, paddr_t, int);
+void agp_apple_unbind_page(void *, bus_addr_t);
+void agp_apple_flush_tlb(void *);
+
+const struct cfattach appleagp_ca = {
+ sizeof(struct agp_apple_softc), agp_apple_match, agp_apple_attach,
+};
+
+struct cfdriver appleagp_cd = {
+ NULL, "appleagp", DV_DULL
+};
+
+const struct agp_methods agp_apple_methods = {
+ agp_apple_bind_page,
+ agp_apple_unbind_page,
+ agp_apple_flush_tlb,
+};
+
+int
+agp_apple_match(struct device *parent, void *match, void *aux)
+{
+ struct agp_attach_args *aa = aux;
+ struct pci_attach_args *pa = aa->aa_pa;
+
+ if (agpbus_probe(aa) != 1 || PCI_VENDOR(pa->pa_id) != PCI_VENDOR_APPLE)
+ return (0);
+
+ switch (PCI_PRODUCT(pa->pa_id)) {
+ case PCI_PRODUCT_APPLE_UNINORTH_AGP:
+ case PCI_PRODUCT_APPLE_PANGEA_AGP:
+ case PCI_PRODUCT_APPLE_UNINORTH2_AGP:
+ case PCI_PRODUCT_APPLE_UNINORTH_AGP3:
+ case PCI_PRODUCT_APPLE_INTREPID2_AGP:
+ return (1);
+#if 0
+ /*
+ * XXX Do not attach U3 bridges to this driver yet.
+ *
+ * Even though they share the same register layout they
+ * use a big-endian GART and need a different set of
+ * commands for flushing their TLB. They should also
+ * support an aperture of 512M.
+ */
+ case PCI_PRODUCT_APPLE_U3_AGP:
+ case PCI_PRODUCT_APPLE_U3L_AGP:
+ case PCI_PRODUCT_APPLE_K2_AGP:
+ return (1);
+#endif
+ }
+
+ return (0);
+}
+
+void
+agp_apple_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct agp_apple_softc *asc = (struct agp_apple_softc *)self;
+ struct agp_attach_args *aa = aux;
+ struct pci_attach_args *pa = aa->aa_pa;
+ struct agp_gatt *gatt;
+
+ asc->asc_tag = pa->pa_tag;
+ asc->asc_pc = pa->pa_pc;
+
+ /*
+ * XXX It looks like UniNorth GART only accepts an aperture
+ * base address of 0x00 certainly because it does not perform
+ * any physical-to-physical address translation.
+ */
+ asc->asc_apaddr = 0x00;
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_APBASE,
+ asc->asc_apaddr);
+
+ /*
+ * There's no way to read the aperture size but all UniNorth
+ * chips seem to support an aperture of 256M.
+ */
+ asc->asc_apsize = 256 * M;
+ for (;;) {
+ gatt = agp_alloc_gatt(pa->pa_dmat, asc->asc_apsize);
+ if (gatt != NULL)
+ break;
+
+ asc->asc_apsize /= 2;
+ }
+ asc->gatt = gatt;
+
+ if (agp_apple_set_aperture(asc, asc->asc_apsize)) {
+ printf("failed to set aperture\n");
+ return;
+ }
+
+ agp_apple_flush_tlb(asc);
+
+ asc->agpdev = (struct agp_softc *)agp_attach_bus(pa, &agp_apple_methods,
+ asc->asc_apaddr, asc->asc_apsize, &asc->dev);
+}
+
+bus_size_t
+agp_apple_get_aperture(void *dev)
+{
+ struct agp_apple_softc *asc = dev;
+
+ return (asc->asc_apsize);
+}
+
+int
+agp_apple_set_aperture(void *dev, bus_size_t aperture)
+{
+ struct agp_apple_softc *asc = dev;
+
+ if (aperture % (4 * M) || aperture < (4 * M) || aperture > (256 * M))
+ return (EINVAL);
+
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_ATTBASE,
+ (asc->gatt->ag_physical & 0xfffff000) | (aperture >> 22));
+
+ return (0);
+}
+
+#define flushd(p) __asm __volatile("dcbst 0,%0; sync" ::"r"(p) : "memory")
+
+void
+agp_apple_bind_page(void *v, bus_addr_t off, paddr_t pa, int flags)
+{
+ struct agp_apple_softc *asc = v;
+
+ if (off >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return;
+
+ asc->gatt->ag_virtual[off >> AGP_PAGE_SHIFT] = htole32(pa | 0x01);
+
+ flushd(&asc->gatt->ag_virtual[off >> AGP_PAGE_SHIFT]);
+}
+
+void
+agp_apple_unbind_page(void *v, bus_size_t off)
+{
+ struct agp_apple_softc *asc = v;
+
+ if (off >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT))
+ return;
+
+ asc->gatt->ag_virtual[off >> AGP_PAGE_SHIFT] = 0;
+
+ flushd(&asc->gatt->ag_virtual[off >> AGP_PAGE_SHIFT]);
+}
+
+#undef flushd
+
+void
+agp_apple_flush_tlb(void *v)
+{
+ struct agp_apple_softc *asc = v;
+
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_GARTCTRL,
+ AGP_APPLE_GART_ENABLE | AGP_APPLE_GART_INVALIDATE);
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_GARTCTRL,
+ AGP_APPLE_GART_ENABLE);
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_GARTCTRL,
+ AGP_APPLE_GART_ENABLE | AGP_APPLE_GART_2XRESET);
+ pci_conf_write(asc->asc_pc, asc->asc_tag, AGP_APPLE_GARTCTRL,
+ AGP_APPLE_GART_ENABLE);
+}
diff --git a/sys/dev/pci/agpreg.h b/sys/dev/pci/agpreg.h
index e5d6b238d42..67f959e849e 100644
--- a/sys/dev/pci/agpreg.h
+++ b/sys/dev/pci/agpreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: agpreg.h,v 1.15 2011/10/24 15:42:33 oga Exp $ */
+/* $OpenBSD: agpreg.h,v 1.16 2012/12/04 10:42:04 mpi Exp $ */
/* $NetBSD: agpreg.h,v 1.1 2001/09/10 10:01:02 fvdl Exp $ */
/*-
@@ -111,6 +111,17 @@
#define AGP_SIS_TLBFLUSH 0x98
/*
+ * Config offsets for Apple UniNorth & U3 AGP chipsets.
+ */
+#define AGP_APPLE_ATTBASE 0x8c
+#define AGP_APPLE_APBASE 0x90
+#define AGP_APPLE_GARTCTRL 0x94
+
+#define AGP_APPLE_GART_INVALIDATE 0x00001
+#define AGP_APPLE_GART_ENABLE 0x00100
+#define AGP_APPLE_GART_2XRESET 0x10000
+
+/*
* Config offsets for Ali AGP chipsets.
*/
#define AGP_ALI_AGPCTRL 0xb8
diff --git a/sys/dev/pci/files.agp b/sys/dev/pci/files.agp
index 4c714b70c38..18486979e22 100644
--- a/sys/dev/pci/files.agp
+++ b/sys/dev/pci/files.agp
@@ -1,4 +1,4 @@
-# $OpenBSD: files.agp,v 1.4 2011/05/30 22:03:47 oga Exp $
+# $OpenBSD: files.agp,v 1.5 2012/12/04 10:42:04 mpi Exp $
define agpdev {}
@@ -15,6 +15,10 @@ device amdagp: agpdev
attach amdagp at agpbus
file dev/pci/agp_amd.c amdagp
+device appleagp: agpdev
+attach appleagp at agpbus
+file dev/pci/agp_apple.c appleagp
+
device intelagp: agpdev
attach intelagp at agpbus
file dev/pci/agp_intel.c intelagp