diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2012-12-04 10:42:06 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2012-12-04 10:42:06 +0000 |
commit | d6cd66921e4dc4c3a682d3fee2043db89ef05f46 (patch) | |
tree | d1e3f5da78dc4380edb832e5b73855189374619f /sys/dev | |
parent | 7b181098c490d2c366a02e6d54d29e83bc995bd2 (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.c | 214 | ||||
-rw-r--r-- | sys/dev/pci/agpreg.h | 13 | ||||
-rw-r--r-- | sys/dev/pci/files.agp | 6 |
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 |