diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-07-12 20:17:04 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 2002-07-12 20:17:04 +0000 |
commit | 5865d6a998391648e294e7a7d4670166fb810364 (patch) | |
tree | f676c2582d4801871f0dcc11309adaa318343ddc | |
parent | b7951dd4c58d1d7d1cbd884949af928addaa1330 (diff) |
support for the agp gart on various agp chipsets.
only i810 driver was tested though.
based on the netbsd's lkm, initially ported
by hunter@dg.net.ua and later made into shape by mickey.
testing by art@ and millert@ .
-rw-r--r-- | sys/arch/i386/conf/files.i386 | 7 | ||||
-rw-r--r-- | sys/arch/i386/pci/agp_machdep.c | 57 | ||||
-rw-r--r-- | sys/arch/i386/pci/pchb.c | 26 | ||||
-rw-r--r-- | sys/dev/ic/i82810reg.h | 82 | ||||
-rw-r--r-- | sys/dev/ic/vga.c | 14 | ||||
-rw-r--r-- | sys/dev/ic/vgavar.h | 12 | ||||
-rw-r--r-- | sys/dev/pci/agp_ali.c | 247 | ||||
-rw-r--r-- | sys/dev/pci/agp_amd.c | 326 | ||||
-rw-r--r-- | sys/dev/pci/agp_i810.c | 375 | ||||
-rw-r--r-- | sys/dev/pci/agp_intel.c | 236 | ||||
-rw-r--r-- | sys/dev/pci/agp_sis.c | 224 | ||||
-rw-r--r-- | sys/dev/pci/agp_via.c | 219 | ||||
-rw-r--r-- | sys/dev/pci/agpreg.h | 157 | ||||
-rw-r--r-- | sys/dev/pci/agpvar.h | 138 | ||||
-rw-r--r-- | sys/dev/pci/files.pci | 8 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 13 | ||||
-rw-r--r-- | sys/dev/pci/vga_pci.c | 779 | ||||
-rw-r--r-- | sys/dev/pci/vga_pcivar.h | 72 | ||||
-rw-r--r-- | sys/sys/agpio.h | 132 |
19 files changed, 3066 insertions, 58 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index dfdf42c9ff1..934ae13d5fd 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.97 2002/06/26 17:11:50 tdeval Exp $ +# $OpenBSD: files.i386,v 1.98 2002/07/12 20:17:03 mickey Exp $ # $NetBSD: files.i386,v 1.73 1996/05/07 00:58:36 thorpej Exp $ # # new style config file for i386 architecture @@ -89,8 +89,9 @@ file arch/i386/i386/mainbus.c mainbus # include "../../../dev/pci/files.pci" -file arch/i386/pci/pci_machdep.c pci -file arch/i386/pci/pciide_machdep.c pciide +file arch/i386/pci/pci_machdep.c pci +file arch/i386/pci/agp_machdep.c pciagp +file arch/i386/pci/pciide_machdep.c pciide file arch/i386/pci/pcic_pci_machdep.c pcic_pci # PCI-Host bridge chipsets diff --git a/sys/arch/i386/pci/agp_machdep.c b/sys/arch/i386/pci/agp_machdep.c new file mode 100644 index 00000000000..4f6f7780e0c --- /dev/null +++ b/sys/arch/i386/pci/agp_machdep.c @@ -0,0 +1,57 @@ +/* $OpenBSD: agp_machdep.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ + +/* + * Copyright (c) 2002 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/device.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcidevs.h> +#include <dev/pci/agpvar.h> + +#include <machine/cpufunc.h> + +const struct agp_product agp_products[] = { + { PCI_VENDOR_ALI, -1, agp_ali_attach }, + { PCI_VENDOR_AMD, -1, agp_amd_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_GC, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810_DC100_GC, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82810E_GC, agp_i810_attach }, + { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82815_FULL_GRAPH, agp_i810_attach }, +/* { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_82830MP_IV, agp_i810_attach }, */ + { PCI_VENDOR_INTEL, -1, agp_intel_attach }, + { PCI_VENDOR_SIS, -1, agp_sis_attach }, + { PCI_VENDOR_VIATECH, -1, agp_via_attach }, + { 0, 0, NULL } +}; + +void +agp_flush_cache(void) +{ + wbinvd(); +} diff --git a/sys/arch/i386/pci/pchb.c b/sys/arch/i386/pci/pchb.c index 8be6bbd297e..f7c6d5aca1f 100644 --- a/sys/arch/i386/pci/pchb.c +++ b/sys/arch/i386/pci/pchb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pchb.c,v 1.34 2002/06/12 15:52:54 mickey Exp $ */ +/* $OpenBSD: pchb.c,v 1.35 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: pchb.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */ /* @@ -165,6 +165,21 @@ pchbattach(parent, self, aux) */ switch (PCI_VENDOR(pa->pa_id)) { +#ifdef PCIAGP + case PCI_VENDOR_ALI: + case PCI_VENDOR_SIS: + case PCI_VENDOR_VIATECH: + pciagp_set_pchb(pa); + break; + case PCI_VENDOR_AMD: + switch (PCI_PRODUCT(pa->pa_id)) { + case PCI_PRODUCT_AMD_SC751_SC: + case PCI_PRODUCT_AMD_762_PCHB: + pciagp_set_pchb(pa); + break; + } + break; +#endif case PCI_VENDOR_RCC: switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_RCC_CNB20HE: @@ -195,6 +210,9 @@ pchbattach(parent, self, aux) } break; case PCI_VENDOR_INTEL: +#ifdef PCIAGP + pciagp_set_pchb(pa); +#endif switch (PCI_PRODUCT(pa->pa_id)) { case PCI_PRODUCT_INTEL_82443BX_AGP: /* 82443BX AGP (PAC) */ case PCI_PRODUCT_INTEL_82443BX_NOAGP: /* 82443BX Host-PCI (no AGP) */ @@ -286,13 +304,13 @@ pchbattach(parent, self, aux) printf(": disabled CPU-PCI write posting"); } break; - case PCI_PRODUCT_INTEL_82810E_MCH: - case PCI_PRODUCT_INTEL_82810_DC100_MCH: case PCI_PRODUCT_INTEL_82810_MCH: + case PCI_PRODUCT_INTEL_82810_DC100_MCH: + case PCI_PRODUCT_INTEL_82810E_MCH: case PCI_PRODUCT_INTEL_82815_DC100_HUB: - case PCI_PRODUCT_INTEL_82815_NOAGP_HUB: case PCI_PRODUCT_INTEL_82815_NOGRAPH_HUB: case PCI_PRODUCT_INTEL_82815_FULL_HUB: + case PCI_PRODUCT_INTEL_82815_NOAGP_HUB: case PCI_PRODUCT_INTEL_82820_MCH: case PCI_PRODUCT_INTEL_82840_HB: case PCI_PRODUCT_INTEL_82850_HB: diff --git a/sys/dev/ic/i82810reg.h b/sys/dev/ic/i82810reg.h new file mode 100644 index 00000000000..b20f4e6a137 --- /dev/null +++ b/sys/dev/ic/i82810reg.h @@ -0,0 +1,82 @@ +/* $OpenBSD: i82810reg.h,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ + +/* + * Copyright (c) 2000 Michael Shalayeff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Michael Shalayeff. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/* + * Intel i82810/810E memory and graphics controller + * http:// + */ + +/* Host-Hub Interface Bridge/DRAM Controller Device Registers (Device 0) */ +#define I82810_SMRAM 0x70 +#define I82810_SMRAM_GMS_DIS 0x00 +#define I82810_SMRAM_GMS_RSRVD 0x40 +#define I82810_SMRAM_GMS_512 0x80 +#define I82810_SMRAM_GMS_1024 0xc0 +#define I82810_SMRAM_USMM_DIS 0x00 +#define I82810_SMRAM_USMM_TDHE 0x10 +#define I82810_SMRAM_USMM_T5HE 0x20 +#define I82810_SMRAM_USMM_T1HE 0x30 +#define I82810_SMRAM_LSMM_DIS 0x00 +#define I82810_SMRAM_LSMM_GSM 0x04 +#define I82810_SMRAM_LSMM_CRSH 0x08 +#define I82810_SMRAM_D_LCK 0x02 +#define I82810_SMRAM_E_SMERR 0x01 +#define I82810_MISCC 0x72 +#define I82810_MISCC_GDCWS 0x0001 +#define I82810_MISCC_P_LCK 0x0008 +#define I82810_MISCC_WPTHC_NO 0x0000 +#define I82810_MISCC_WPTHC_625 0x0010 +#define I82810_MISCC_WPTHC_500 0x0020 +#define I82810_MISCC_WPTHC_375 0x0030 +#define I82810_MISCC_RPTHC_NO 0x0000 +#define I82810_MISCC_RPTHC_625 0x0040 +#define I82810_MISCC_RPTHC_500 0x0080 +#define I82810_MISCC_RPTHC_375 0x00c0 + +/* Graphics Device Registers (Device 1) */ +#define I82810_GMADR 0x10 +#define I82810_MMADR 0x14 + +#define I82810_DRT 0x3000 +#define I82810_DRT_DP 0x01 +#define I82810_DRAMCL 0x3001 +#define I82810_DRAMCL_RPT 0x01 +#define I82810_DRAMCL_RT 0x02 +#define I82810_DRAMCL_CL 0x04 +#define I82810_DRAMCL_RCO 0x08 +#define I82810_DRAMCL_PMC 0x10 +#define I82810_DRAMCH 0x3002 +#define I82810_DRAMCH_SMS 0x07 +#define I82810_DRAMCH_DRR 0x18 +#define I82810_GTT 0x10000 diff --git a/sys/dev/ic/vga.c b/sys/dev/ic/vga.c index 1dc3f035154..373226c8d09 100644 --- a/sys/dev/ic/vga.c +++ b/sys/dev/ic/vga.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vga.c,v 1.29 2002/03/14 03:16:05 millert Exp $ */ +/* $OpenBSD: vga.c,v 1.30 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: vga.c,v 1.28.2.1 2000/06/30 16:27:47 simonb Exp $ */ /* @@ -497,7 +497,6 @@ vga_common_attach(self, iot, memt, type) bus_space_tag_t iot, memt; int type; { -#ifdef arc vga_extended_attach(self, iot, memt, type, NULL); } @@ -506,9 +505,8 @@ vga_extended_attach(self, iot, memt, type, map) struct device *self; bus_space_tag_t iot, memt; int type; - int (*map)(void *, vaddr_t, int); + paddr_t (*map)(void *, off_t, int); { -#endif /* arc */ int console; struct vga_config *vc; struct wsemuldisplaydev_attach_args aa; @@ -528,9 +526,7 @@ vga_extended_attach(self, iot, memt, type, map) vc->vc_softc = self; vc->vc_type = type; -#ifdef arc vc->vc_mmap = map; -#endif aa.console = console; aa.scrdata = (vc->hdl.vh_mono ? &vga_screenlist_mono : &vga_screenlist); @@ -628,15 +624,11 @@ vga_mmap(v, offset, prot) off_t offset; int prot; { - -#ifdef arc struct vga_config *vc = v; if (vc->vc_mmap != NULL) return (*vc->vc_mmap)(v, offset, prot); -#else - /* XXX */ -#endif + return -1; } diff --git a/sys/dev/ic/vgavar.h b/sys/dev/ic/vgavar.h index 5a5db102d10..7bac3e67bbc 100644 --- a/sys/dev/ic/vgavar.h +++ b/sys/dev/ic/vgavar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vgavar.h,v 1.7 2002/03/14 03:16:05 millert Exp $ */ +/* $OpenBSD: vgavar.h,v 1.8 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: vgavar.h,v 1.4 2000/06/17 07:11:50 soda Exp $ */ /* @@ -57,9 +57,7 @@ struct vga_config { void (*switchcb)(void *, int, int); void *switchcbarg; -#ifdef arc paddr_t (*vc_mmap)(void *, off_t, int); -#endif struct timeout vc_switch_timeout; }; @@ -164,14 +162,10 @@ static inline void _vga_gdc_write(vh, reg, val) int vga_common_probe(bus_space_tag_t, bus_space_tag_t); void vga_common_attach(struct device *, bus_space_tag_t, - bus_space_tag_t, int); -#ifdef arc + bus_space_tag_t, int); void vga_extended_attach(struct device *, bus_space_tag_t, - bus_space_tag_t, int, - int (*)(void *, off_t, int)); -#endif + bus_space_tag_t, int, paddr_t (*)(void *, off_t, int)); int vga_is_console(bus_space_tag_t, int); - int vga_cnattach(bus_space_tag_t, bus_space_tag_t, int, int); struct wsscreen_descr; diff --git a/sys/dev/pci/agp_ali.c b/sys/dev/pci/agp_ali.c new file mode 100644 index 00000000000..58cec9ee1c3 --- /dev/null +++ b/sys/dev/pci/agp_ali.c @@ -0,0 +1,247 @@ +/* $OpenBSD: agp_ali.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agp_ali.c,v 1.2 2001/09/15 00:25:00 thorpej Exp $ */ + + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_ali.c,v 1.3 2001/07/05 21:28:46 jhb Exp $ + */ + + + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/lock.h> +#include <sys/agpio.h> + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/vga_pcivar.h> +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> + +#include <machine/bus.h> + +struct agp_ali_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_gatt *gatt; +}; + +u_int32_t agp_ali_get_aperture(struct vga_pci_softc *); +int agp_ali_set_aperture(struct vga_pci_softc *sc, u_int32_t); +int agp_ali_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +int agp_ali_unbind_page(struct vga_pci_softc *, off_t); +void agp_ali_flush_tlb(struct vga_pci_softc *); + +struct agp_methods agp_ali_methods = { + agp_ali_get_aperture, + agp_ali_set_aperture, + agp_ali_bind_page, + agp_ali_unbind_page, + agp_ali_flush_tlb, + agp_generic_enable, + agp_generic_alloc_memory, + agp_generic_free_memory, + agp_generic_bind_memory, + agp_generic_unbind_memory, +}; + +int +agp_ali_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_ali_softc *asc; + struct agp_gatt *gatt; + pcireg_t reg; + + asc = malloc(sizeof *asc, M_DEVBUF, M_NOWAIT); + if (asc == NULL) { + printf(": failed to allocate softc\n"); + return ENOMEM; + } + sc->sc_chipc = asc; + sc->sc_methods = &agp_ali_methods; + + if (agp_map_aperture(sc) != 0) { + printf(": failed to map aperture\n"); + free(asc, M_DEVBUF); + return ENXIO; + } + + asc->initial_aperture = agp_ali_get_aperture(sc); + + for (;;) { + gatt = agp_alloc_gatt(sc); + if (gatt != NULL) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + agp_generic_detach(sc); + printf(": failed to set aperture\n"); + return ENOMEM; + } + } + asc->gatt = gatt; + + /* Install the gatt. */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE); + reg = (reg & 0xff) | gatt->ag_physical; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg); + + /* Enable the TLB. */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL); + reg = (reg & ~0xff) | 0x10; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg); + + return 0; +} + +#if 0 +int +agp_ali_detach(struct vga_pci_softc *sc) +{ + int error; + pcireg_t reg; + struct agp_ali_softc *asc = sc->sc_chipc; + + error = agp_generic_detach(sc); + if (error) + return error; + + /* Disable the TLB.. */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL); + reg &= ~0xff; + reg |= 0x90; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg); + + /* Put the aperture back the way it started. */ + AGP_SET_APERTURE(sc, asc->initial_aperture); + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE); + reg &= 0xff; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg); + + agp_free_gatt(sc, asc->gatt); + return 0; +} +#endif + +#define M 1024*1024 + +static const u_int32_t agp_ali_table[] = { + 0, /* 0 - invalid */ + 1, /* 1 - invalid */ + 2, /* 2 - invalid */ + 4*M, /* 3 - invalid */ + 8*M, /* 4 - invalid */ + 0, /* 5 - invalid */ + 16*M, /* 6 - invalid */ + 32*M, /* 7 - invalid */ + 64*M, /* 8 - invalid */ + 128*M, /* 9 - invalid */ + 256*M, /* 10 - invalid */ +}; +#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0])) + +u_int32_t +agp_ali_get_aperture(struct vga_pci_softc *sc) +{ + int i; + + /* + * The aperture size is derived from the low bits of attbase. + * I'm not sure this is correct.. + */ + i = (int)pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE) & 0xff; + if (i >= agp_ali_table_size) + return 0; + return agp_ali_table[i]; +} + +int +agp_ali_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + int i; + pcireg_t reg; + + for (i = 0; i < agp_ali_table_size; i++) + if (agp_ali_table[i] == aperture) + break; + if (i == agp_ali_table_size) + return EINVAL; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE); + reg &= ~0xff; + reg |= i; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_ATTBASE, reg); + return 0; +} + +int +agp_ali_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical) +{ + struct agp_ali_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; + return 0; +} + +int +agp_ali_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_ali_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; + return 0; +} + +void +agp_ali_flush_tlb(struct vga_pci_softc *sc) +{ + pcireg_t reg; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL); + reg &= ~0xff; + reg |= 0x90; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg); + reg &= ~0xff; + reg |= 0x10; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_ALI_TLBCTRL, reg); +} + diff --git a/sys/dev/pci/agp_amd.c b/sys/dev/pci/agp_amd.c new file mode 100644 index 00000000000..c17a49f045b --- /dev/null +++ b/sys/dev/pci/agp_amd.c @@ -0,0 +1,326 @@ +/* $OpenBSD: agp_amd.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agp_amd.c,v 1.6 2001/10/06 02:48:50 thorpej Exp $ */ + + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_amd.c,v 1.6 2001/07/05 21:28:46 jhb Exp $ + */ + + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/proc.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/vga_pcivar.h> +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> + +#include <dev/pci/pcidevs.h> + +#define READ2(off) bus_space_read_2(asc->iot, asc->ioh, off) +#define READ4(off) bus_space_read_4(asc->iot, asc->ioh, off) +#define WRITE2(off,v) bus_space_write_2(asc->iot, asc->ioh, off, v) +#define WRITE4(off,v) bus_space_write_4(asc->iot, asc->ioh, off, v) + +struct agp_amd_gatt { + bus_dmamap_t ag_dmamap; + bus_dma_segment_t ag_dmaseg; + int ag_nseg; + u_int32_t ag_entries; + u_int32_t *ag_vdir; /* virtual address of page dir */ + bus_addr_t ag_pdir; /* bus address of page dir */ + u_int32_t *ag_virtual; /* virtual address of gatt */ + bus_addr_t ag_physical; /* bus address of gatt */ + size_t ag_size; +}; + +struct agp_amd_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_amd_gatt *gatt; + bus_space_handle_t ioh; + bus_space_tag_t iot; +}; + +static u_int32_t agp_amd_get_aperture(struct vga_pci_softc *); +static int agp_amd_set_aperture(struct vga_pci_softc *, u_int32_t); +static int agp_amd_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +static int agp_amd_unbind_page(struct vga_pci_softc *, off_t); +static void agp_amd_flush_tlb(struct vga_pci_softc *); + + +struct agp_methods agp_amd_methods = { + agp_amd_get_aperture, + agp_amd_set_aperture, + agp_amd_bind_page, + agp_amd_unbind_page, + agp_amd_flush_tlb, + agp_generic_enable, + agp_generic_alloc_memory, + agp_generic_free_memory, + agp_generic_bind_memory, + agp_generic_unbind_memory, +}; + + +static struct agp_amd_gatt * +agp_amd_alloc_gatt(struct vga_pci_softc *sc) +{ + u_int32_t apsize = AGP_GET_APERTURE(sc); + u_int32_t entries = apsize >> AGP_PAGE_SHIFT; + struct agp_amd_gatt *gatt; + int i, npages; + caddr_t vdir; + + gatt = malloc(sizeof(struct agp_amd_gatt), M_DEVBUF, M_NOWAIT); + if (!gatt) + return 0; + + if (agp_alloc_dmamem(sc->sc_dmat, + AGP_PAGE_SIZE + entries * sizeof(u_int32_t), 0, + &gatt->ag_dmamap, &vdir, &gatt->ag_pdir, + &gatt->ag_dmaseg, 1, &gatt->ag_nseg) != 0) { + printf("failed to allocate GATT\n"); + free(gatt, M_DEVBUF); + return NULL; + } + + gatt->ag_vdir = (u_int32_t *)vdir; + gatt->ag_entries = entries; + gatt->ag_virtual = (u_int32_t *)(vdir + AGP_PAGE_SIZE); + gatt->ag_physical = gatt->ag_pdir + AGP_PAGE_SIZE; + gatt->ag_size = AGP_PAGE_SIZE + entries * sizeof(u_int32_t); + + memset(gatt->ag_vdir, 0, AGP_PAGE_SIZE); + memset(gatt->ag_virtual, 0, entries * sizeof(u_int32_t)); + + /* + * Map the pages of the GATT into the page directory. + */ + npages = ((entries * sizeof(u_int32_t) + AGP_PAGE_SIZE - 1) + >> AGP_PAGE_SHIFT); + + for (i = 0; i < npages; i++) + gatt->ag_vdir[i] = (gatt->ag_physical + i * AGP_PAGE_SIZE) | 1; + + /* + * Make sure the chipset can see everything. + */ + agp_flush_cache(); + + return gatt; +} + +#if 0 +static void +agp_amd_free_gatt(struct vga_pci_softc *sc, struct agp_amd_gatt *gatt) +{ + agp_free_dmamem(sc->sc_dmat, gatt->ag_size, + gatt->ag_dmamap, (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, + gatt->ag_nseg); + free(gatt, M_DEVBUF); +} +#endif + +int +agp_amd_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_amd_softc *asc; + struct agp_amd_gatt *gatt; + pcireg_t reg; + int error; + + asc = malloc(sizeof *asc, M_DEVBUF, M_NOWAIT); + if (asc == NULL) { + printf(": can't allocate softc\n"); + /* agp_generic_detach(sc) */ + return ENOMEM; + } + memset(asc, 0, sizeof *asc); + + error = pci_mapreg_map(pchb_pa, AGP_AMD751_REGISTERS, + PCI_MAPREG_TYPE_MEM,0, &asc->iot, &asc->ioh, NULL, NULL, 0); + if (error != 0) { + printf(": can't map AGP registers\n"); + agp_generic_detach(sc); + return error; + } + + if (agp_map_aperture(sc) != 0) { + printf(": can't map aperture\n"); + agp_generic_detach(sc); + free(asc, M_DEVBUF); + return ENXIO; + } + sc->sc_methods = &agp_amd_methods; + sc->sc_chipc = asc; + asc->initial_aperture = AGP_GET_APERTURE(sc); + + for (;;) { + gatt = agp_amd_alloc_gatt(sc); + if (gatt) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + printf(": can't set aperture\n"); + return ENOMEM; + } + } + asc->gatt = gatt; + + /* Install the gatt. */ + WRITE4(AGP_AMD751_ATTBASE, gatt->ag_physical); + + /* Enable synchronisation between host and agp. */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL); + reg &= ~0x00ff00ff; + reg |= (AGP_AMD751_MODECTRL_SYNEN) | (AGP_AMD751_MODECTRL2_GPDCE << 16); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL, reg); + /* Enable the TLB and flush */ + WRITE2(AGP_AMD751_STATUS, + READ2(AGP_AMD751_STATUS) | AGP_AMD751_STATUS_GCE); + AGP_FLUSH_TLB(sc); + + return 0; +} + +#if 0 +static int +agp_amd_detach(struct vga_pci_softc *sc) +{ + pcireg_t reg; + struct agp_amd_softc *asc = sc->sc_chipc; + + /* Disable the TLB.. */ + WRITE2(AGP_AMD751_STATUS, + READ2(AGP_AMD751_STATUS) & ~AGP_AMD751_STATUS_GCE); + + /* Disable host-agp sync */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL); + reg &= 0xffffff00; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_MODECTRL, reg); + + /* Clear the GATT base */ + WRITE4(AGP_AMD751_ATTBASE, 0); + + /* Put the aperture back the way it started. */ + AGP_SET_APERTURE(sc, asc->initial_aperture); + + agp_amd_free_gatt(sc, asc->gatt); + + /* XXXfvdl no pci_mapreg_unmap */ + + return 0; +} +#endif + +static u_int32_t +agp_amd_get_aperture(struct vga_pci_softc *sc) +{ + int vas; + + vas = (pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_APCTRL) & 0x06); + vas >>= 1; + /* + * The aperture size is equal to 32M<<vas. + */ + return (32*1024*1024) << vas; +} + +static int +agp_amd_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + int vas; + pcireg_t reg; + + /* + * Check for a power of two and make sure its within the + * programmable range. + */ + if (aperture & (aperture - 1) + || aperture < 32*1024*1024 + || aperture > 2U*1024*1024*1024) + return EINVAL; + + vas = ffs(aperture / 32*1024*1024) - 1; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_APCTRL); + reg = (reg & ~0x06) | (vas << 1); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_AMD751_APCTRL, reg); + + return 0; +} + +static int +agp_amd_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical) +{ + struct agp_amd_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1; + return 0; +} + +static int +agp_amd_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_amd_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; + return 0; +} + +static void +agp_amd_flush_tlb(struct vga_pci_softc *sc) +{ + struct agp_amd_softc *asc = sc->sc_chipc; + + /* Set the cache invalidate bit and wait for the chipset to clear */ + WRITE4(AGP_AMD751_TLBCTRL, 1); + do { + DELAY(1); + } while (READ4(AGP_AMD751_TLBCTRL)); +} + + diff --git a/sys/dev/pci/agp_i810.c b/sys/dev/pci/agp_i810.c new file mode 100644 index 00000000000..db623c5f6fb --- /dev/null +++ b/sys/dev/pci/agp_i810.c @@ -0,0 +1,375 @@ +/* $OpenBSD: agp_i810.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agp_i810.c,v 1.8 2001/09/20 20:00:16 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * Copyright (c) 2000 Ruslan Ermilov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_i810.c,v 1.4 2001/07/05 21:28:47 jhb Exp $ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.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 <dev/pci/vga_pcivar.h> + +#include <machine/bus.h> + +#define READ1(off) bus_space_read_1(isc->bst, isc->bsh, off) +#define WRITE4(off,v) bus_space_write_4(isc->bst, isc->bsh, off, v) + +struct agp_i810_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_gatt *gatt; + u_int32_t dcache_size; + bus_space_tag_t bst; /* bus_space tag */ + bus_space_handle_t bsh; /* bus_space handle */ +}; + +u_int32_t agp_i810_get_aperture(struct vga_pci_softc *); +int agp_i810_set_aperture(struct vga_pci_softc *, u_int32_t); +int agp_i810_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +int agp_i810_unbind_page(struct vga_pci_softc *, off_t); +void agp_i810_flush_tlb(struct vga_pci_softc *); +int agp_i810_enable(struct vga_pci_softc *, u_int32_t mode); +struct agp_memory *agp_i810_alloc_memory(struct vga_pci_softc *, int, vsize_t); +int agp_i810_free_memory(struct vga_pci_softc *, struct agp_memory *); +int agp_i810_bind_memory(struct vga_pci_softc *, struct agp_memory *, off_t); +int agp_i810_unbind_memory(struct vga_pci_softc *, struct agp_memory *); + +struct agp_methods agp_i810_methods = { + agp_i810_get_aperture, + agp_i810_set_aperture, + agp_i810_bind_page, + agp_i810_unbind_page, + agp_i810_flush_tlb, + agp_i810_enable, + agp_i810_alloc_memory, + agp_i810_free_memory, + agp_i810_bind_memory, + agp_i810_unbind_memory, +}; + + +int +agp_i810_attach(struct vga_pci_softc* sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_i810_softc *isc; + struct agp_gatt *gatt; + int error; + + isc = malloc(sizeof *isc, M_DEVBUF, M_NOWAIT); + if (isc == NULL) { + printf(": can't allocate chipset-specific softc\n"); + return ENOMEM; + } + memset(isc, 0, sizeof *isc); + sc->sc_chipc = isc; + sc->sc_methods = &agp_i810_methods; + sc->sc_dmat = pa->pa_dmat; /* XXX fvdl */ + + if ((error = agp_map_aperture(sc))) { + printf(": can't map aperture\n"); + free(isc, M_DEVBUF); + return error; + } + + error = pci_mapreg_map(pa, AGP_I810_MMADR, + PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL, 0); + if (error != 0) { + printf(": can't map mmadr registers\n"); + return error; + } + + isc->initial_aperture = AGP_GET_APERTURE(sc); + + if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) + isc->dcache_size = 4 * 1024 * 1024; + else + isc->dcache_size = 0; + + for (;;) { + gatt = agp_alloc_gatt(sc); + if (gatt) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + agp_generic_detach(sc); + return ENOMEM; + } + } + isc->gatt = gatt; + + /* Install the GATT. */ + WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); + + /* + * Make sure the chipset can see everything. + */ + agp_flush_cache(); + + return 0; +} + +u_int32_t +agp_i810_get_aperture(struct vga_pci_softc *sc) +{ + u_int16_t miscc; + + miscc = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_I810_SMRAM) >> 16; + if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32) + return 32 * 1024 * 1024; + else + return 64 * 1024 * 1024; +} + +int +agp_i810_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + pcireg_t reg, miscc; + + /* + * Double check for sanity. + */ + if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) { + printf("AGP: bad aperture size %d\n", aperture); + return EINVAL; + } + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_I810_SMRAM); + miscc = reg >> 16; + miscc &= ~AGP_I810_MISCC_WINSIZE; + if (aperture == 32 * 1024 * 1024) + miscc |= AGP_I810_MISCC_WINSIZE_32; + else + miscc |= AGP_I810_MISCC_WINSIZE_64; + + reg &= 0x0000ffff; + reg |= (miscc << 16); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_I810_SMRAM, miscc); + + return 0; +} + +int +agp_i810_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t pa) +{ + struct agp_i810_softc *isc = sc->sc_chipc; + + if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, + pa | 1); + + return 0; +} + +int +agp_i810_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_i810_softc *isc = sc->sc_chipc; + + if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 0); + return 0; +} + +/* + * Writing via memory mapped registers already flushes all TLBs. + */ +void +agp_i810_flush_tlb(struct vga_pci_softc *sc) +{ +} + +int +agp_i810_enable(struct vga_pci_softc *sc, u_int32_t mode) +{ + + return 0; +} + +struct agp_memory * +agp_i810_alloc_memory(struct vga_pci_softc *sc, int type, vsize_t size) +{ + struct agp_i810_softc *isc = sc->sc_chipc; + struct agp_memory *mem; + int error; + + if (type == 1) { + /* + * Mapping local DRAM into GATT. + */ + if (size != isc->dcache_size) +{ printf("agp: size(%d) != isc->dcache_size(%d)\n", size, isc->dcache_size); + return NULL; +} + } else if (type == 2) { + /* + * Bogus mapping of a single page for the hardware cursor. + */ + if (size != AGP_PAGE_SIZE) +{ printf("agp: size(%d) != AGP_PAGE_SIZE(%d)\n", size, AGP_PAGE_SIZE); + return NULL; +} + } + + if ((mem = malloc(sizeof *mem, M_DEVBUF, M_WAITOK)) == NULL) + return NULL; + bzero(mem, sizeof *mem); + mem->am_id = sc->sc_nextid++; + mem->am_size = size; + mem->am_type = type; + + if (type == 2) { + mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_DEVBUF, M_WAITOK); + if (mem->am_dmaseg == NULL) { + free(mem, M_DEVBUF); +printf("agp: no memory for the segments\n"); + return NULL; + } + if ((error = agp_alloc_dmamem(sc->sc_dmat, size, 0, + &mem->am_dmamap, &mem->am_virtual, &mem->am_physical, + mem->am_dmaseg, 1, &mem->am_nseg)) != 0) { + free(mem, M_DEVBUF); + free(mem->am_dmaseg, M_DEVBUF); +printf("agp: agp_alloc_dmamem(%d)\n", error); + return NULL; + } + } else if (type != 1) { + if ((error = bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1, + size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap)) != 0) { + free(mem, M_DEVBUF); +printf("agp: bus_dmamap_create(%d)\n", error); + return NULL; + } + } + + TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link); + sc->sc_allocated += size; + + return mem; +} + +int +agp_i810_free_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +{ + if (mem->am_is_bound) + return EBUSY; + + if (mem->am_type == 2) { + agp_free_dmamem(sc->sc_dmat, mem->am_size, mem->am_dmamap, + mem->am_virtual, mem->am_dmaseg, mem->am_nseg); + free(mem->am_dmaseg, M_DEVBUF); + } + + sc->sc_allocated -= mem->am_size; + TAILQ_REMOVE(&sc->sc_memory, mem, am_link); + free(mem, M_DEVBUF); + return 0; +} + +int +agp_i810_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, + off_t offset) +{ + struct agp_i810_softc *isc = sc->sc_chipc; + u_int32_t regval, i; + + /* + * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the + * X server for mysterious reasons which leads to crashes if we write + * to the GTT through the MMIO window. + * Until the issue is solved, simply restore it. + */ + regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL); + if (regval != (isc->gatt->ag_physical | 1)) { + printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n", + regval); + bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL, + isc->gatt->ag_physical | 1); + } + + if (mem->am_type == 2) { + WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, + mem->am_physical | 1); + mem->am_offset = offset; + mem->am_is_bound = 1; + return 0; + } + + if (mem->am_type != 1) + return agp_generic_bind_memory(sc, mem, offset); + + for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) + WRITE4(AGP_I810_GTT + + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, i | 3); + + return 0; +} + +int +agp_i810_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +{ + struct agp_i810_softc *isc = sc->sc_chipc; + u_int32_t i; + + if (mem->am_type == 2) { + WRITE4(AGP_I810_GTT + + (u_int32_t)(mem->am_offset >> AGP_PAGE_SHIFT) * 4, 0); + mem->am_offset = 0; + mem->am_is_bound = 0; + return 0; + } + + if (mem->am_type != 1) + return agp_generic_unbind_memory(sc, mem); + + for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) + WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0); + + return 0; +} diff --git a/sys/dev/pci/agp_intel.c b/sys/dev/pci/agp_intel.c new file mode 100644 index 00000000000..653adaf4c9e --- /dev/null +++ b/sys/dev/pci/agp_intel.c @@ -0,0 +1,236 @@ +/* $OpentBSD: agp_intel.c,v 1.1 2001/10/25 21:44:00 thorpej Exp $ */ +/* $NetBSD: agp_intel.c,v 1.3 2001/09/15 00:25:00 thorpej Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_intel.c,v 1.4 2001/07/05 21:28:47 jhb Exp $ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/proc.h> +#include <sys/agpio.h> +#include <sys/device.h> +#include <sys/agpio.h> + + +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/vga_pcivar.h> +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> + +#include <machine/bus.h> + +struct agp_intel_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_gatt *gatt; +}; + + +static u_int32_t agp_intel_get_aperture(struct vga_pci_softc *); +static int agp_intel_set_aperture(struct vga_pci_softc *, u_int32_t); +static int agp_intel_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +static int agp_intel_unbind_page(struct vga_pci_softc *, off_t); +static void agp_intel_flush_tlb(struct vga_pci_softc *); + +struct agp_methods agp_intel_methods = { + agp_intel_get_aperture, + agp_intel_set_aperture, + agp_intel_bind_page, + agp_intel_unbind_page, + agp_intel_flush_tlb, + agp_generic_enable, + agp_generic_alloc_memory, + agp_generic_free_memory, + agp_generic_bind_memory, + agp_generic_unbind_memory, +}; + +int +agp_intel_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_intel_softc *isc; + struct agp_gatt *gatt; + pcireg_t reg; + + isc = malloc(sizeof *isc, M_DEVBUF, M_NOWAIT); + if (isc == NULL) { + printf(": can't allocate chipset-specific softc\n"); + return ENOMEM; + } + memset(isc, 0, sizeof *isc); + + sc->sc_methods = &agp_intel_methods; + sc->sc_chipc = isc; + + if (agp_map_aperture(sc) != 0) { + printf(": can't map aperture\n"); + free(isc, M_DEVBUF); + sc->sc_chipc = NULL; + return ENXIO; + } + + isc->initial_aperture = AGP_GET_APERTURE(sc); + + for (;;) { + gatt = agp_alloc_gatt(sc); + if (gatt) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + agp_generic_detach(sc); + printf(": failed to set aperture\n"); + return ENOMEM; + } + } + isc->gatt = gatt; + + /* Install the gatt. */ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE, + gatt->ag_physical); + + /* Enable things, clear errors etc. */ + /* XXXfvdl get rid of the magic constants */ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2280); + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG); + reg &= ~(1 << 10); + reg |= (1 << 9); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg); + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_STS); + reg &= ~0x00ff0000; + reg |= (7 << 16); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_STS, reg); + + return 0; +} + +#if 0 +static int +agp_intel_detach(struct vga_pci_softc *sc) +{ + int error; + pcireg_t reg; + struct agp_intel_softc *isc = sc->sc_chipc; + + error = agp_generic_detach(sc); + if (error) + return error; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG); + reg &= ~(1 << 9); + printf("%s: set NBXCFG to %x\n", __FUNCTION__, reg); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_NBXCFG, reg); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_ATTBASE, 0); + AGP_SET_APERTURE(sc, isc->initial_aperture); + agp_free_gatt(sc, isc->gatt); + + return 0; +} +#endif + +static u_int32_t +agp_intel_get_aperture(struct vga_pci_softc *sc) +{ + u_int32_t apsize; + + apsize = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE) & 0x1f; + + /* + * The size is determined by the number of low bits of + * register APBASE which are forced to zero. The low 22 bits + * are always forced to zero and each zero bit in the apsize + * field just read forces the corresponding bit in the 27:22 + * to be zero. We calculate the aperture size accordingly. + */ + return (((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1; +} + +static int +agp_intel_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + u_int32_t apsize; + pcireg_t reg; + + /* + * Reverse the magic from get_aperture. + */ + apsize = ((aperture - 1) >> 22) ^ 0x1f; + + /* + * Double check for sanity. + */ + if ((((apsize ^ 0x1f) << 22) | ((1 << 22) - 1)) + 1 != aperture) + return EINVAL; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE); + reg = (reg & 0xffffff00) | apsize; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_APSIZE, reg); + + return 0; +} + +static int +agp_intel_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical) +{ + struct agp_intel_softc *isc = sc->sc_chipc; + + if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 0x17; + return 0; +} + +static int +agp_intel_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_intel_softc *isc = sc->sc_chipc; + + if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + isc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; + return 0; +} + +static void +agp_intel_flush_tlb(struct vga_pci_softc *sc) +{ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2200); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_INTEL_AGPCTRL, 0x2280); +} + + diff --git a/sys/dev/pci/agp_sis.c b/sys/dev/pci/agp_sis.c new file mode 100644 index 00000000000..bf510cffd9f --- /dev/null +++ b/sys/dev/pci/agp_sis.c @@ -0,0 +1,224 @@ +/* $OpenBSD: agp_sis.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agp_sis.c,v 1.2 2001/09/15 00:25:00 thorpej Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_sis.c,v 1.3 2001/07/05 21:28:47 jhb Exp $ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/proc.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/vga_pcivar.h> +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> + +#include <machine/bus.h> + +struct agp_sis_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_gatt *gatt; +}; + +static u_int32_t agp_sis_get_aperture(struct vga_pci_softc *); +static int agp_sis_set_aperture(struct vga_pci_softc *, u_int32_t); +static int agp_sis_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +static int agp_sis_unbind_page(struct vga_pci_softc *, off_t); +static void agp_sis_flush_tlb(struct vga_pci_softc *); + +struct agp_methods agp_sis_methods = { + agp_sis_get_aperture, + agp_sis_set_aperture, + agp_sis_bind_page, + agp_sis_unbind_page, + agp_sis_flush_tlb, + agp_generic_enable, + agp_generic_alloc_memory, + agp_generic_free_memory, + agp_generic_bind_memory, + agp_generic_unbind_memory, +}; + + +int +agp_sis_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_sis_softc *ssc; + struct agp_gatt *gatt; + pcireg_t reg; + + ssc = malloc(sizeof *ssc, M_DEVBUF, M_NOWAIT); + if (ssc == NULL) { + printf(": can't allocate chipset-specific softc\n"); + return ENOMEM; + } + sc->sc_methods = &agp_sis_methods; + sc->sc_chipc = ssc; + + if (agp_map_aperture(sc) != 0) { + printf(": can't map aperture\n"); + free(ssc, M_DEVBUF); + return ENXIO; + } + + ssc->initial_aperture = AGP_GET_APERTURE(sc); + + for (;;) { + gatt = agp_alloc_gatt(sc); + if (gatt) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + agp_generic_detach(sc); + printf(": failed to set aperture\n"); + return ENOMEM; + } + } + ssc->gatt = gatt; + + /* Install the gatt. */ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_ATTBASE, + gatt->ag_physical); + + /* Enable the aperture and auto-tlb-inval */ + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL); + reg |= (0x05 << 24) | 3; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL, reg); + + return 0; +} + +#if 0 +static int +agp_sis_detach(struct vga_pci_softc *sc) +{ + struct agp_sis_softc *ssc = sc->sc_chipc; + pcireg_t reg; + int error; + + error = agp_generic_detach(sc); + if (error) + return error; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL); + reg &= ~3; + reg &= 0x00ffffff; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL, reg); + + /* Put the aperture back the way it started. */ + AGP_SET_APERTURE(sc, ssc->initial_aperture); + + agp_free_gatt(sc, ssc->gatt); + return 0; +} +#endif + +static u_int32_t +agp_sis_get_aperture(struct vga_pci_softc *sc) +{ + int gws; + + /* + * The aperture size is equal to 4M<<gws. + */ + gws = (pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL)&0x70) >> 4; + return (4*1024*1024) << gws; +} + +static int +agp_sis_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + int gws; + pcireg_t reg; + + /* + * Check for a power of two and make sure its within the + * programmable range. + */ + if (aperture & (aperture - 1) + || aperture < 4*1024*1024 + || aperture > 256*1024*1024) + return EINVAL; + + gws = ffs(aperture / 4*1024*1024) - 1; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL); + reg &= ~0x00000070; + reg |= gws << 4; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_WINCTRL, reg); + + return 0; +} + +static int +agp_sis_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical) +{ + struct agp_sis_softc *ssc = sc->sc_chipc; + + if (offset < 0 || offset >= (ssc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + ssc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; + return 0; +} + +static int +agp_sis_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_sis_softc *ssc = sc->sc_chipc; + + if (offset < 0 || offset >= (ssc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + ssc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; + return 0; +} + +static void +agp_sis_flush_tlb(struct vga_pci_softc *sc) +{ + pcireg_t reg; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_SIS_TLBFLUSH); + reg &= 0xffffff00; + reg |= 0x02; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_SIS_TLBFLUSH, reg); +} + diff --git a/sys/dev/pci/agp_via.c b/sys/dev/pci/agp_via.c new file mode 100644 index 00000000000..dd5e7dc4cf1 --- /dev/null +++ b/sys/dev/pci/agp_via.c @@ -0,0 +1,219 @@ +/* $OpenBSD: agp_via.c,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agp_via.c,v 1.2 2001/09/15 00:25:00 thorpej Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp_via.c,v 1.3 2001/07/05 21:28:47 jhb Exp $ + */ + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/proc.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/vga_pcivar.h> +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> + +#include <machine/bus.h> + +static u_int32_t agp_via_get_aperture(struct vga_pci_softc *); +static int agp_via_set_aperture(struct vga_pci_softc *, u_int32_t); +static int agp_via_bind_page(struct vga_pci_softc *, off_t, bus_addr_t); +static int agp_via_unbind_page(struct vga_pci_softc *, off_t); +static void agp_via_flush_tlb(struct vga_pci_softc *); + +struct agp_methods agp_via_methods = { + agp_via_get_aperture, + agp_via_set_aperture, + agp_via_bind_page, + agp_via_unbind_page, + agp_via_flush_tlb, + agp_generic_enable, + agp_generic_alloc_memory, + agp_generic_free_memory, + agp_generic_bind_memory, + agp_generic_unbind_memory, +}; + +struct agp_via_softc { + u_int32_t initial_aperture; /* aperture size at startup */ + struct agp_gatt *gatt; +}; + + +int +agp_via_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *pchb_pa) +{ + struct agp_via_softc *asc; + struct agp_gatt *gatt; + + asc = malloc(sizeof *asc, M_DEVBUF, M_NOWAIT); + if (asc == NULL) { + printf(": can't allocate chipset-specific softc\n"); + return ENOMEM; + } + memset(asc, 0, sizeof *asc); + sc->sc_chipc = asc; + sc->sc_methods = &agp_via_methods; + + if (agp_map_aperture(sc) != 0) { + printf(": can't map aperture\n"); + free(asc, M_DEVBUF); + return ENXIO; + } + + asc->initial_aperture = AGP_GET_APERTURE(sc); + + for (;;) { + gatt = agp_alloc_gatt(sc); + if (gatt) + break; + + /* + * Probably contigmalloc failure. Try reducing the + * aperture so that the gatt size reduces. + */ + if (AGP_SET_APERTURE(sc, AGP_GET_APERTURE(sc) / 2)) { + agp_generic_detach(sc); + printf(": can't set aperture size\n"); + return ENOMEM; + } + } + asc->gatt = gatt; + + /* Install the gatt. */ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_ATTBASE, + gatt->ag_physical | 3); + + /* Enable the aperture. */ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x0000000f); + + return 0; +} + +#if 0 +static int +agp_via_detach(struct vga_pci_softc *sc) +{ + struct agp_via_softc *asc = sc->sc_chipc; + int error; + + error = agp_generic_detach(sc); + if (error) + return error; + + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_ATTBASE, 0); + AGP_SET_APERTURE(sc, asc->initial_aperture); + agp_free_gatt(sc, asc->gatt); + + return 0; +} +#endif + +static u_int32_t +agp_via_get_aperture(struct vga_pci_softc *sc) +{ + u_int32_t apsize; + + apsize = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_VIA_APSIZE) & 0x1f; + + /* + * The size is determined by the number of low bits of + * register APBASE which are forced to zero. The low 20 bits + * are always forced to zero and each zero bit in the apsize + * field just read forces the corresponding bit in the 27:20 + * to be zero. We calculate the aperture size accordingly. + */ + return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1; +} + +static int +agp_via_set_aperture(struct vga_pci_softc *sc, u_int32_t aperture) +{ + u_int32_t apsize; + pcireg_t reg; + + /* + * Reverse the magic from get_aperture. + */ + apsize = ((aperture - 1) >> 20) ^ 0xff; + + /* + * Double check for sanity. + */ + if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture) + return EINVAL; + + reg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, AGP_VIA_APSIZE); + reg &= ~0xff; + reg |= apsize; + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_APSIZE, reg); + + return 0; +} + +static int +agp_via_bind_page(struct vga_pci_softc *sc, off_t offset, bus_addr_t physical) +{ + struct agp_via_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; + return 0; +} + +static int +agp_via_unbind_page(struct vga_pci_softc *sc, off_t offset) +{ + struct agp_via_softc *asc = sc->sc_chipc; + + if (offset < 0 || offset >= (asc->gatt->ag_entries << AGP_PAGE_SHIFT)) + return EINVAL; + + asc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; + return 0; +} + +static void +agp_via_flush_tlb(struct vga_pci_softc *sc) +{ + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x8f); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, AGP_VIA_GARTCTRL, 0x0f); +} + + diff --git a/sys/dev/pci/agpreg.h b/sys/dev/pci/agpreg.h new file mode 100644 index 00000000000..df3dd955be0 --- /dev/null +++ b/sys/dev/pci/agpreg.h @@ -0,0 +1,157 @@ +/* $OpenBSD: agpreg.h,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agpreg.h,v 1.1 2001/09/10 10:01:02 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agpreg.h,v 1.3 2000/07/12 10:13:04 dfr Exp $ + */ + +#ifndef _PCI_AGPREG_H_ +#define _PCI_AGPREG_H_ + +/* + * Offsets for various AGP configuration registers. + */ +#define AGP_APBASE 0x10 + +/* + * Offsets from the AGP Capability pointer. + */ +#define AGP_CAPID 0x02 +#define AGP_CAPID_GET_MAJOR(x) (((x) & 0x00f00000U) >> 20) +#define AGP_CAPID_GET_MINOR(x) (((x) & 0x000f0000U) >> 16) +#define AGP_CAPID_GET_NEXT_PTR(x) (((x) & 0x0000ff00U) >> 8) +#define AGP_CAPID_GET_CAP_ID(x) (((x) & 0x000000ffU) >> 0) + +#define AGP_STATUS 0x4 +#define AGP_COMMAND 0x8 + +/* + * Config offsets for Intel AGP chipsets. + */ +#define AGP_INTEL_NBXCFG 0x50 +#define AGP_INTEL_STS 0x90 +#define AGP_INTEL_AGPCTRL 0xb0 +#define AGP_INTEL_APSIZE 0xb4 +#define AGP_INTEL_ATTBASE 0xb8 + +/* + * Config offsets for VIA AGP chipsets. + */ +#define AGP_VIA_GARTCTRL 0x80 +#define AGP_VIA_APSIZE 0x84 +#define AGP_VIA_ATTBASE 0x88 + +/* + * Config offsets for SiS AGP chipsets. + */ +#define AGP_SIS_ATTBASE 0x90 +#define AGP_SIS_WINCTRL 0x94 +#define AGP_SIS_TLBCTRL 0x97 +#define AGP_SIS_TLBFLUSH 0x98 + +/* + * Config offsets for Ali AGP chipsets. + */ +#define AGP_ALI_AGPCTRL 0xb8 +#define AGP_ALI_ATTBASE 0xbc +#define AGP_ALI_TLBCTRL 0xc0 + +/* + * Config offsets for the AMD 751 chipset. + */ +#define AGP_AMD751_REGISTERS 0x14 +#define AGP_AMD751_APCTRL 0xac +#define AGP_AMD751_MODECTRL 0xb0 +#define AGP_AMD751_MODECTRL_SYNEN 0x80 +#define AGP_AMD751_MODECTRL2 0xb2 +#define AGP_AMD751_MODECTRL2_G1LM 0x01 +#define AGP_AMD751_MODECTRL2_GPDCE 0x02 +#define AGP_AMD751_MODECTRL2_NGSE 0x08 + +/* + * Memory mapped register offsets for AMD 751 chipset. + */ +#define AGP_AMD751_CAPS 0x00 +#define AGP_AMD751_CAPS_EHI 0x0800 +#define AGP_AMD751_CAPS_P2P 0x0400 +#define AGP_AMD751_CAPS_MPC 0x0200 +#define AGP_AMD751_CAPS_VBE 0x0100 +#define AGP_AMD751_CAPS_REV 0x00ff +#define AGP_AMD751_STATUS 0x02 +#define AGP_AMD751_STATUS_P2PS 0x0800 +#define AGP_AMD751_STATUS_GCS 0x0400 +#define AGP_AMD751_STATUS_MPS 0x0200 +#define AGP_AMD751_STATUS_VBES 0x0100 +#define AGP_AMD751_STATUS_P2PE 0x0008 +#define AGP_AMD751_STATUS_GCE 0x0004 +#define AGP_AMD751_STATUS_VBEE 0x0001 +#define AGP_AMD751_ATTBASE 0x04 +#define AGP_AMD751_TLBCTRL 0x0c + +/* + * Config registers for i810 device 0 + */ +#define AGP_I810_SMRAM 0x70 +#define AGP_I810_SMRAM_GMS 0xc0 +#define AGP_I810_SMRAM_GMS_DISABLED 0x00 +#define AGP_I810_SMRAM_GMS_ENABLED_0 0x40 +#define AGP_I810_SMRAM_GMS_ENABLED_512 0x80 +#define AGP_I810_SMRAM_GMS_ENABLED_1024 0xc0 +#define AGP_I810_MISCC 0x72 +#define AGP_I810_MISCC_WINSIZE 0x0001 +#define AGP_I810_MISCC_WINSIZE_64 0x0000 +#define AGP_I810_MISCC_WINSIZE_32 0x0001 +#define AGP_I810_MISCC_PLCK 0x0008 +#define AGP_I810_MISCC_PLCK_UNLOCKED 0x0000 +#define AGP_I810_MISCC_PLCK_LOCKED 0x0008 +#define AGP_I810_MISCC_WPTC 0x0030 +#define AGP_I810_MISCC_WPTC_NOLIMIT 0x0000 +#define AGP_I810_MISCC_WPTC_62 0x0010 +#define AGP_I810_MISCC_WPTC_50 0x0020 +#define AGP_I810_MISCC_WPTC_37 0x0030 +#define AGP_I810_MISCC_RPTC 0x00c0 +#define AGP_I810_MISCC_RPTC_NOLIMIT 0x0000 +#define AGP_I810_MISCC_RPTC_62 0x0040 +#define AGP_I810_MISCC_RPTC_50 0x0080 +#define AGP_I810_MISCC_RPTC_37 0x00c0 + +/* + * Config registers for i810 device 1 + */ +#define AGP_I810_GMADR 0x10 +#define AGP_I810_MMADR 0x14 + +/* + * Memory mapped register offsets for i810 chipset. + */ +#define AGP_I810_PGTBL_CTL 0x2020 +#define AGP_I810_DRT 0x3000 +#define AGP_I810_DRT_UNPOPULATED 0x00 +#define AGP_I810_DRT_POPULATED 0x01 +#define AGP_I810_GTT 0x10000 + +#endif /* !_PCI_AGPREG_H_ */ diff --git a/sys/dev/pci/agpvar.h b/sys/dev/pci/agpvar.h new file mode 100644 index 00000000000..4bad2ff97da --- /dev/null +++ b/sys/dev/pci/agpvar.h @@ -0,0 +1,138 @@ +/* $OpenBSD: agpvar.h,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ +/* $NetBSD: agpvar.h,v 1.4 2001/10/01 21:54:48 fvdl Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agppriv.h,v 1.3 2000/07/12 10:13:04 dfr Exp $ + */ + +#ifndef _PCI_AGPVAR_H_ +#define _PCI_AGPVAR_H_ + +#include <sys/lock.h> +#include <dev/pci/vga_pcivar.h> + +/* + * This structure is used to query the state of the AGP system. + */ +struct agp_info { + u_int32_t ai_mode; + bus_addr_t ai_aperture_base; + bus_size_t ai_aperture_size; + vsize_t ai_memory_allowed; + vsize_t ai_memory_used; + u_int32_t ai_devid; +}; + +struct agp_memory_info { + vsize_t ami_size; /* size in bytes */ + bus_addr_t ami_physical; /* bogus hack for i810 */ + off_t ami_offset; /* page offset if bound */ + int ami_is_bound; /* non-zero if bound */ +}; + +#define AGP_DEBUG +#ifdef AGP_DEBUG +#define AGP_DPF(x...) do { \ + printf("agp: "); \ + printf(##x); \ +} while (0) +#else +#define AGP_DPF(x...) do {} while (0) +#endif + +#define AGPUNIT(x) minor(x) + +struct agp_methods { + u_int32_t (*get_aperture)(struct vga_pci_softc *); + int (*set_aperture)(struct vga_pci_softc *, u_int32_t); + int (*bind_page)(struct vga_pci_softc *, off_t, bus_addr_t); + int (*unbind_page)(struct vga_pci_softc *, off_t); + void (*flush_tlb)(struct vga_pci_softc *); + int (*enable)(struct vga_pci_softc *, u_int32_t mode); + struct agp_memory *(*alloc_memory)(struct vga_pci_softc *, int, vsize_t); + int (*free_memory)(struct vga_pci_softc *, struct agp_memory *); + int (*bind_memory)(struct vga_pci_softc *, struct agp_memory *, off_t); + int (*unbind_memory)(struct vga_pci_softc *, struct agp_memory *); +}; + +#define AGP_GET_APERTURE(sc) ((sc)->sc_methods->get_aperture(sc)) +#define AGP_SET_APERTURE(sc,a) ((sc)->sc_methods->set_aperture((sc),(a))) +#define AGP_BIND_PAGE(sc,o,p) ((sc)->sc_methods->bind_page((sc),(o),(p))) +#define AGP_UNBIND_PAGE(sc,o) ((sc)->sc_methods->unbind_page((sc), (o))) +#define AGP_FLUSH_TLB(sc) ((sc)->sc_methods->flush_tlb(sc)) +#define AGP_ENABLE(sc,m) ((sc)->sc_methods->enable((sc),(m))) +#define AGP_ALLOC_MEMORY(sc,t,s) ((sc)->sc_methods->alloc_memory((sc),(t),(s))) +#define AGP_FREE_MEMORY(sc,m) ((sc)->sc_methods->free_memory((sc),(m))) +#define AGP_BIND_MEMORY(sc,m,o) ((sc)->sc_methods->bind_memory((sc),(m),(o))) +#define AGP_UNBIND_MEMORY(sc,m) ((sc)->sc_methods->unbind_memory((sc),(m))) + +/* + * All chipset drivers must have this at the start of their softc. + */ + +struct agp_gatt { + u_int32_t ag_entries; + u_int32_t *ag_virtual; + bus_addr_t ag_physical; + bus_dmamap_t ag_dmamap; + bus_dma_segment_t ag_dmaseg; + size_t ag_size; +}; + + +/* + * Functions private to the AGP code. + */ + +int agp_find_caps(pci_chipset_tag_t pct, pcitag_t pt); +int agp_map_aperture(struct vga_pci_softc *sc); +struct agp_gatt *agp_alloc_gatt(struct vga_pci_softc *sc); +void agp_free_gatt(struct vga_pci_softc *sc, struct agp_gatt *gatt); +void agp_flush_cache(void); +int agp_generic_attach(struct vga_pci_softc *sc); +int agp_generic_detach(struct vga_pci_softc *sc); +int agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode); +struct agp_memory *agp_generic_alloc_memory(struct vga_pci_softc *sc, int type, + vsize_t size); +int agp_generic_free_memory(struct vga_pci_softc *sc, struct agp_memory *mem); +int agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, + off_t offset); +int agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem); + +int agp_ali_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); +int agp_amd_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); +int agp_i810_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); +int agp_intel_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); +int agp_via_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); +int agp_sis_attach(struct vga_pci_softc *sc, struct pci_attach_args *pa, struct pci_attach_args *p); + +int agp_alloc_dmamem(bus_dma_tag_t, size_t, int, bus_dmamap_t *, caddr_t *, + bus_addr_t *, bus_dma_segment_t *, int, int *); +void agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, + caddr_t vaddr, bus_dma_segment_t *seg, int nseg) ; + +#endif /* !_PCI_AGPVAR_H_ */ diff --git a/sys/dev/pci/files.pci b/sys/dev/pci/files.pci index 3bb790bb290..ed700af7c2e 100644 --- a/sys/dev/pci/files.pci +++ b/sys/dev/pci/files.pci @@ -1,4 +1,4 @@ -# $OpenBSD: files.pci,v 1.140 2002/06/26 00:18:03 itojun Exp $ +# $OpenBSD: files.pci,v 1.141 2002/07/12 20:17:03 mickey Exp $ # $NetBSD: files.pci,v 1.20 1996/09/24 17:47:15 christos Exp $ # # Config file and device description for machine-independent PCI code. @@ -15,6 +15,12 @@ file dev/pci/pci_subr.c pci # Generic VGA attach vga at pci with vga_pci file dev/pci/vga_pci.c vga_pci +file dev/pci/agp_ali.c pciagp +file dev/pci/agp_amd.c pciagp +file dev/pci/agp_i810.c pciagp +file dev/pci/agp_intel.c pciagp +file dev/pci/agp_sis.c pciagp +file dev/pci/agp_via.c pciagp device tga: wsemuldisplaydev, rasops8, rasops32 attach tga at pci diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h index c9419191ede..dc68945d121 100644 --- a/sys/dev/pci/pcivar.h +++ b/sys/dev/pci/pcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcivar.h,v 1.24 2002/03/14 03:16:06 millert Exp $ */ +/* $OpenBSD: pcivar.h,v 1.25 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: pcivar.h,v 1.23 1997/06/06 23:48:05 thorpej Exp $ */ /* @@ -185,14 +185,11 @@ int pci_get_capability(pci_chipset_tag_t, pcitag_t, int, /* * Helper functions for autoconfiguration. */ +const char *pci_findvendor(pcireg_t); void pci_devinfo(pcireg_t, pcireg_t, int, char *); void set_pci_isa_bridge_callback(void (*)(void *), void *); -const struct pci_quirkdata *pci_lookup_quirkdata(pci_vendor_id_t, - pci_product_id_t); - -/* - * Misc. - */ -const char *pci_findvendor(pcireg_t); +const struct pci_quirkdata * + pci_lookup_quirkdata(pci_vendor_id_t, pci_product_id_t); +void pciagp_set_pchb(struct pci_attach_args *); #endif /* _DEV_PCI_PCIVAR_H_ */ diff --git a/sys/dev/pci/vga_pci.c b/sys/dev/pci/vga_pci.c index dc1b323da24..e087c24748c 100644 --- a/sys/dev/pci/vga_pci.c +++ b/sys/dev/pci/vga_pci.c @@ -1,22 +1,83 @@ -/* $OpenBSD: vga_pci.c,v 1.11 2002/03/14 01:27:00 millert Exp $ */ +/* $OpenBSD: vga_pci.c,v 1.12 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: vga_pci.c,v 1.3 1998/06/08 06:55:58 thorpej Exp $ */ +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/pci/agp.c,v 1.12 2001/05/19 01:28:07 alfred Exp $ + */ +/* + * Copyright (c) 2001 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Frank van der Linden for Wasabi Systems, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed for the NetBSD Project by + * Wasabi Systems, Inc. + * 4. The name of Wasabi Systems, Inc. may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ /* * Copyright (c) 1995, 1996 Carnegie-Mellon University. * All rights reserved. * * Author: Chris G. Demetriou - * + * * Permission to use, copy, modify and distribute this software and * its documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU @@ -35,6 +96,11 @@ #include <sys/kernel.h> #include <sys/device.h> #include <sys/malloc.h> +#include <sys/agpio.h> + +#include <uvm/uvm.h> + +#include <machine/bus.h> #include <dev/pci/pcireg.h> #include <dev/pci/pcivar.h> @@ -46,25 +112,32 @@ #include <dev/ic/vgavar.h> #include <dev/pci/vga_pcivar.h> -#include <dev/wscons/wsconsio.h> -#include <dev/wscons/wsdisplayvar.h> +#ifdef PCIAGP +#include <sys/fcntl.h> -struct vga_pci_softc { - struct device sc_dev; - - pcitag_t sc_pcitag; /* PCI tag, in case we need it. */ -#if 0 - struct vga_config *sc_vc; /* VGA configuration */ +#include <dev/pci/agpvar.h> +#include <dev/pci/agpreg.h> #endif -}; + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> int vga_pci_match(struct device *, void *, void *); void vga_pci_attach(struct device *, struct device *, void *); +paddr_t vga_pci_mmap(void* v, off_t off, int prot); struct cfattach vga_pci_ca = { sizeof(struct vga_pci_softc), vga_pci_match, vga_pci_attach, }; +#ifdef PCIAGP +struct agp_memory *agp_find_memory(struct vga_pci_softc *sc, int id); +const struct agp_product *agp_lookup(struct pci_attach_args *pa); + +struct pci_attach_args agp_pchb_pa; +int agp_pchb_pa_set = 0; +#endif + int vga_pci_match(parent, match, aux) struct device *parent; @@ -115,16 +188,92 @@ vga_pci_attach(parent, self, aux) void *aux; { struct pci_attach_args *pa = aux; +#ifdef PCIAGP struct vga_pci_softc *sc = (struct vga_pci_softc *)self; - char devinfo[256]; + const struct agp_product *ap; + u_int memsize; + int i, ret; +#endif - sc->sc_pcitag = pa->pa_tag; +#ifdef PCIAGP + ap = agp_lookup(pa); + if (ap) { + static const int agp_max[][2] = { + {0, 0}, + {32, 4}, + {64, 28}, + {128, 96}, + {256, 204}, + {512, 440}, + {1024, 942}, + {2048, 1920}, + {4096, 3932} + }; +#define agp_max_size (sizeof(agp_max)/sizeof(agp_max[0])) - pci_devinfo(pa->pa_id, pa->pa_class, 0, devinfo); - printf("\n"); + /* + * Work out an upper bound for agp memory allocation. This + * uses a heurisitc table from the Linux driver. + */ + memsize = ptoa(physmem) >> 20; + + for (i = 0; i < agp_max_size && memsize > agp_max[i][0]; i++) + ; + if (i == agp_max_size) + i = agp_max_size - 1; + sc->sc_maxmem = agp_max[i][1] << 20; + + /* + * The lock is used to prevent re-entry to + * agp_generic_bind_memory() since that function can sleep. + */ + lockinit(&sc->sc_lock, PZERO|PCATCH, "agplk", 0, 0); + + TAILQ_INIT(&sc->sc_memory); + + sc->sc_pcitag = pa->pa_tag; + sc->sc_pc = pa->pa_pc; + sc->sc_id = pa->pa_id; + sc->sc_dmat = pa->pa_dmat; + + pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, + &sc->sc_capoff, NULL); + + ret = (*ap->ap_attach)(sc, pa, &agp_pchb_pa); + if (ret == 0) + printf(": aperture at 0x%lx, size 0x%lx", + (u_long)sc->sc_apaddr, + (u_long)AGP_GET_APERTURE(sc)); + else { + sc->sc_chipc = NULL; + printf(": AGP GART"); + } + } +#endif + printf("\n"); vga_common_attach(self, pa->pa_iot, pa->pa_memt, - WSDISPLAY_TYPE_PCIVGA); + WSDISPLAY_TYPE_PCIVGA); +} + +paddr_t +vga_pci_mmap(void *v, off_t off, int prot) +{ +#ifdef PCIAGP + struct vga_config* vs = (struct vga_config*) v; + struct vga_pci_softc* sc = (struct vga_pci_softc *)vs->vc_softc; + + if (sc->sc_apaddr) { + + if (off > AGP_GET_APERTURE(sc)) + return (-1); + +#ifdef __i386__ + return i386_btop(sc->sc_apaddr + off); +#endif + } +#endif + return -1; } int @@ -144,5 +293,593 @@ vga_pci_ioctl(v, cmd, addr, flag, p) int flag; struct proc *p; { - return (ENOTTY); + int error = 0; +#ifdef PCIAGP + struct vga_config *vc = v; + struct vga_pci_softc *sc = (struct vga_pci_softc *)vc->vc_softc; + struct agp_memory *mem; + agp_info *info; + agp_setup *setup; + agp_allocate *alloc; + agp_bind *bind; + agp_unbind *unbind; + vsize_t size; + + switch (cmd) { + case AGPIOC_INFO: + case AGPIOC_ACQUIRE: + case AGPIOC_RELEASE: + case AGPIOC_SETUP: + case AGPIOC_ALLOCATE: + case AGPIOC_DEALLOCATE: + case AGPIOC_BIND: + case AGPIOC_UNBIND: + if (!sc->sc_chipc) + return (ENXIO); + } + + if (cmd != AGPIOC_INFO && !(flag & FWRITE)) + return (EPERM); +#endif + + switch (cmd) { +#ifdef PCIAGP + case AGPIOC_INFO: + info = (agp_info *)addr; + bzero(info, sizeof *info); + info->bridge_id = sc->sc_id; + if (sc->sc_capoff != 0) + info->agp_mode = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + AGP_STATUS + sc->sc_capoff); + else + info->agp_mode = 0; /* i810 doesn't have real AGP */ + info->aper_base = sc->sc_apaddr; + info->aper_size = AGP_GET_APERTURE(sc) >> 20; + info->pg_total = + info->pg_system = sc->sc_maxmem >> AGP_PAGE_SHIFT; + info->pg_used = sc->sc_allocated >> AGP_PAGE_SHIFT; + break; + + case AGPIOC_ACQUIRE: + if (sc->sc_state != AGP_ACQUIRE_FREE) + error = EBUSY; + else + sc->sc_state = AGP_ACQUIRE_USER; + break; + + case AGPIOC_RELEASE: + if (sc->sc_state == AGP_ACQUIRE_FREE) + break; + + if (sc->sc_state != AGP_ACQUIRE_USER) { + error = EBUSY; + break; + } + + /* + * Clear out the aperture and free any + * outstanding memory blocks. + */ + TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { + if (mem->am_is_bound) { + printf("agp_release_helper: mem %d is bound\n", + mem->am_id); + AGP_UNBIND_MEMORY(sc, mem); + } + } + sc->sc_state = AGP_ACQUIRE_FREE; + break; + + case AGPIOC_SETUP: + setup = (agp_setup *)addr; + error = AGP_ENABLE(sc, setup->agp_mode); + break; + + case AGPIOC_ALLOCATE: + alloc = (agp_allocate *)addr; + size = alloc->pg_count << AGP_PAGE_SHIFT; + if (sc->sc_allocated + size > sc->sc_maxmem) + error = EINVAL; + else { + mem = AGP_ALLOC_MEMORY(sc, alloc->type, size); + if (mem) { + alloc->key = mem->am_id; + alloc->physical = mem->am_physical; + } else + error = ENOMEM; + } + break; + + case AGPIOC_DEALLOCATE: + mem = agp_find_memory(sc, *(int *)addr); + if (mem) + AGP_FREE_MEMORY(sc, mem); + else + error = ENOENT; + break; + + case AGPIOC_BIND: + bind = (agp_bind *)addr; + mem = agp_find_memory(sc, bind->key); + if (!mem) + error = ENOENT; + else + error = AGP_BIND_MEMORY(sc, mem, + bind->pg_start << AGP_PAGE_SHIFT); + break; + + case AGPIOC_UNBIND: + unbind = (agp_unbind *)addr; + mem = agp_find_memory(sc, unbind->key); + if (!mem) + error = ENOENT; + else + error = AGP_UNBIND_MEMORY(sc, mem); + break; +#endif /* PCIAGP */ + + default: + error = ENOTTY; + } + + return (error); } + +#ifdef PCIAGP +struct agp_memory * +agp_find_memory(struct vga_pci_softc *sc, int id) +{ + struct agp_memory *mem; + + AGP_DPF("searching for memory block %d\n", id); + TAILQ_FOREACH(mem, &sc->sc_memory, am_link) { + AGP_DPF("considering memory block %d\n", mem->am_id); + if (mem->am_id == id) + return (mem); + } + return 0; +} + +const struct agp_product * +agp_lookup(struct pci_attach_args *pa) +{ + const struct agp_product *ap; + + if (!agp_pchb_pa_set) + return (NULL); + agp_pchb_pa_set = 0; + + /* First find the vendor. */ + for (ap = agp_products; ap->ap_attach != NULL; ap++) + if (ap->ap_vendor == PCI_VENDOR(pa->pa_id)) + break; + + if (ap->ap_attach == NULL) + return (NULL); + + /* Now find the product within the vendor's domain. */ + for (; ap->ap_attach != NULL; ap++) { + /* Ran out of this vendor's section of the table. */ + if (ap->ap_vendor != PCI_VENDOR(pa->pa_id)) + return (NULL); + + if (ap->ap_product == PCI_PRODUCT(pa->pa_id)) + break; /* Exact match. */ + if (ap->ap_product == (u_int32_t) -1) + break; /* Wildcard match. */ + } + + if (ap->ap_attach == NULL) + ap = NULL; + + return (ap); +} + +void +pciagp_set_pchb(struct pci_attach_args *pa) +{ + if (!agp_pchb_pa_set) { + memcpy(&agp_pchb_pa, pa, sizeof *pa); + agp_pchb_pa_set++; + } +} + +int +agp_map_aperture(struct vga_pci_softc *sc) +{ + /* + * Find and the aperture. Don't map it (yet), this would + * eat KVA. + */ + if (pci_mapreg_info(sc->sc_pc, sc->sc_pcitag, AGP_APBASE, + PCI_MAPREG_TYPE_MEM, &sc->sc_apaddr, &sc->sc_apsize, + &sc->sc_apflags) != 0) + return ENXIO; + + return 0; +} + +struct agp_gatt * +agp_alloc_gatt(struct vga_pci_softc *sc) +{ + u_int32_t apsize = AGP_GET_APERTURE(sc); + u_int32_t entries = apsize >> AGP_PAGE_SHIFT; + struct agp_gatt *gatt; + int nseg; + + gatt = malloc(sizeof(*gatt), M_DEVBUF, M_NOWAIT); + if (!gatt) + return (NULL); + bzero(gatt, sizeof(*gatt)); + gatt->ag_entries = entries; + + if (agp_alloc_dmamem(sc->sc_dmat, entries * sizeof(u_int32_t), + 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, + &gatt->ag_physical, &gatt->ag_dmaseg, 1, &nseg) != 0) + return NULL; + + gatt->ag_size = entries * sizeof(u_int32_t); + memset(gatt->ag_virtual, 0, gatt->ag_size); + agp_flush_cache(); + + return gatt; +} + +void +agp_free_gatt(struct vga_pci_softc *sc, struct agp_gatt *gatt) +{ + agp_free_dmamem(sc->sc_dmat, gatt->ag_size, gatt->ag_dmamap, + (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); + free(gatt, M_DEVBUF); +} + +int +agp_generic_detach(struct vga_pci_softc *sc) +{ + lockmgr(&sc->sc_lock, LK_DRAIN, NULL, curproc); + agp_flush_cache(); + return 0; +} + +int +agp_generic_enable(struct vga_pci_softc *sc, u_int32_t mode) +{ + pcireg_t tstatus, mstatus; + pcireg_t command; + int rq, sba, fw, rate, capoff; + + if (pci_get_capability(sc->sc_pc, sc->sc_pcitag, PCI_CAP_AGP, + &capoff, NULL) == 0) { + printf("agp_generic_enable: not an AGP capable device\n"); + return -1; + } + + tstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + sc->sc_capoff + AGP_STATUS); + mstatus = pci_conf_read(sc->sc_pc, sc->sc_pcitag, + capoff + AGP_STATUS); + + /* Set RQ to the min of mode, tstatus and mstatus */ + rq = AGP_MODE_GET_RQ(mode); + if (AGP_MODE_GET_RQ(tstatus) < rq) + rq = AGP_MODE_GET_RQ(tstatus); + if (AGP_MODE_GET_RQ(mstatus) < rq) + rq = AGP_MODE_GET_RQ(mstatus); + + /* Set SBA if all three can deal with SBA */ + sba = (AGP_MODE_GET_SBA(tstatus) + & AGP_MODE_GET_SBA(mstatus) + & AGP_MODE_GET_SBA(mode)); + + /* Similar for FW */ + fw = (AGP_MODE_GET_FW(tstatus) + & AGP_MODE_GET_FW(mstatus) + & AGP_MODE_GET_FW(mode)); + + /* Figure out the max rate */ + rate = (AGP_MODE_GET_RATE(tstatus) + & AGP_MODE_GET_RATE(mstatus) + & AGP_MODE_GET_RATE(mode)); + if (rate & AGP_MODE_RATE_4x) + rate = AGP_MODE_RATE_4x; + else if (rate & AGP_MODE_RATE_2x) + rate = AGP_MODE_RATE_2x; + else + rate = AGP_MODE_RATE_1x; + + /* Construct the new mode word and tell the hardware */ + command = AGP_MODE_SET_RQ(0, rq); + command = AGP_MODE_SET_SBA(command, sba); + command = AGP_MODE_SET_FW(command, fw); + command = AGP_MODE_SET_RATE(command, rate); + command = AGP_MODE_SET_AGP(command, 1); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, + sc->sc_capoff + AGP_COMMAND, command); + pci_conf_write(sc->sc_pc, sc->sc_pcitag, capoff + AGP_COMMAND, command); + return 0; +} + +struct agp_memory * +agp_generic_alloc_memory(struct vga_pci_softc *sc, int type, vsize_t size) +{ + struct agp_memory *mem; + + if (type != 0) { + printf("agp_generic_alloc_memory: unsupported type %d\n", type); + return 0; + } + + mem = malloc(sizeof *mem, M_DEVBUF, M_WAITOK); + if (mem == NULL) + return NULL; + + if (bus_dmamap_create(sc->sc_dmat, size, size / PAGE_SIZE + 1, + size, 0, BUS_DMA_NOWAIT, &mem->am_dmamap) != 0) { + free(mem, M_DEVBUF); + return NULL; + } + + mem->am_id = sc->sc_nextid++; + mem->am_size = size; + mem->am_type = 0; + mem->am_physical = 0; + mem->am_offset = 0; + mem->am_is_bound = 0; + TAILQ_INSERT_TAIL(&sc->sc_memory, mem, am_link); + sc->sc_allocated += size; + + return mem; +} + +int +agp_generic_free_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +{ + if (mem->am_is_bound) + return EBUSY; + + sc->sc_allocated -= mem->am_size; + TAILQ_REMOVE(&sc->sc_memory, mem, am_link); + bus_dmamap_destroy(sc->sc_dmat, mem->am_dmamap); + free(mem, M_DEVBUF); + return 0; +} + +int +agp_generic_bind_memory(struct vga_pci_softc *sc, struct agp_memory *mem, + off_t offset) +{ + bus_dma_segment_t *segs, *seg; + bus_size_t done, j; + bus_addr_t pa; + off_t i, k; + int contigpages, nseg, error; + + lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL, curproc); + + if (mem->am_is_bound) { + printf("AGP: memory already bound\n"); + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + return EINVAL; + } + + if (offset < 0 + || (offset & (AGP_PAGE_SIZE - 1)) != 0 + || offset + mem->am_size > AGP_GET_APERTURE(sc)) { + printf("AGP: binding memory at bad offset %#lx\n", + (unsigned long) offset); + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + return EINVAL; + } + + /* + * XXXfvdl + * The memory here needs to be directly accessable from the + * AGP video card, so it should be allocated using bus_dma. + * However, it need not be contiguous, since individual pages + * are translated using the GATT. + * + * Using a large chunk of contiguous memory may get in the way + * of other subsystems that may need one, so we try to be friendly + * and ask for allocation in chunks of a minimum of 8 pages + * of contiguous memory on average, falling back to 4, 2 and 1 + * if really needed. Larger chunks are preferred, since allocating + * a bus_dma_segment per page would be overkill. + */ + + for (contigpages = 32; contigpages > 0; contigpages >>= 1) { + nseg = (mem->am_size / (contigpages * PAGE_SIZE)) + 1; +printf("nsegs=%d\n", nseg); + segs = malloc(nseg * sizeof *segs, M_DEVBUF, M_WAITOK); + if (segs == NULL) +{ printf("malloc(%d) failed\n", nseg * sizeof *segs); + return ENOMEM; +} + if ((error = bus_dmamem_alloc(sc->sc_dmat, mem->am_size, PAGE_SIZE, 0, + segs, nseg, &mem->am_nseg, BUS_DMA_WAITOK)) != 0) { + free(segs, M_DEVBUF); + AGP_DPF("bus_dmamem_alloc failed %d\n", error); + continue; + } + if ((error = bus_dmamem_map(sc->sc_dmat, segs, mem->am_nseg, + mem->am_size, &mem->am_virtual, BUS_DMA_WAITOK)) != 0) { + bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); + free(segs, M_DEVBUF); + AGP_DPF("bus_dmamem_map failed %d\n", error); + continue; + } + if ((error = bus_dmamap_load(sc->sc_dmat, mem->am_dmamap, + mem->am_virtual, mem->am_size, NULL, + BUS_DMA_WAITOK)) != 0) { + bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, + mem->am_size); + bus_dmamem_free(sc->sc_dmat, segs, mem->am_nseg); + free(segs, M_DEVBUF); + AGP_DPF("bus_dmamap_load failed %d\n", error); + continue; + } + mem->am_dmaseg = segs; + break; + } + + if (contigpages == 0) { + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + return ENOMEM; + } + + /* + * Bind the individual pages and flush the chipset's + * TLB. + */ + done = 0; + for (i = 0; i < mem->am_dmamap->dm_nsegs; i++) { + seg = &mem->am_dmamap->dm_segs[i]; + /* + * Install entries in the GATT, making sure that if + * AGP_PAGE_SIZE < PAGE_SIZE and mem->am_size is not + * aligned to PAGE_SIZE, we don't modify too many GATT + * entries. + */ + for (j = 0; j < seg->ds_len && (done + j) < mem->am_size; + j += AGP_PAGE_SIZE) { + pa = seg->ds_addr + j; + AGP_DPF("binding offset %#lx to pa %#lx\n", + (unsigned long)(offset + done + j), + (unsigned long)pa); + error = AGP_BIND_PAGE(sc, offset + done + j, pa); + if (error) { + /* + * Bail out. Reverse all the mappings + * and unwire the pages. + */ + for (k = 0; k < done + j; k += AGP_PAGE_SIZE) + AGP_UNBIND_PAGE(sc, offset + k); + + bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap); + bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, + mem->am_size); + bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, + mem->am_nseg); + free(mem->am_dmaseg, M_DEVBUF); + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + return error; + } + } + done += seg->ds_len; + } + + /* + * Flush the cpu cache since we are providing a new mapping + * for these pages. + */ + agp_flush_cache(); + + /* + * Make sure the chipset gets the new mappings. + */ + AGP_FLUSH_TLB(sc); + + mem->am_offset = offset; + mem->am_is_bound = 1; + + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + + return 0; +} + +int +agp_generic_unbind_memory(struct vga_pci_softc *sc, struct agp_memory *mem) +{ + int i; + + lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL, curproc); + + if (!mem->am_is_bound) { + printf("AGP: memory is not bound\n"); + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + return EINVAL; + } + + + /* + * Unbind the individual pages and flush the chipset's + * TLB. Unwire the pages so they can be swapped. + */ + for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) + AGP_UNBIND_PAGE(sc, mem->am_offset + i); + + agp_flush_cache(); + AGP_FLUSH_TLB(sc); + + bus_dmamap_unload(sc->sc_dmat, mem->am_dmamap); + bus_dmamem_unmap(sc->sc_dmat, mem->am_virtual, mem->am_size); + bus_dmamem_free(sc->sc_dmat, mem->am_dmaseg, mem->am_nseg); + + free(mem->am_dmaseg, M_DEVBUF); + + mem->am_offset = 0; + mem->am_is_bound = 0; + + lockmgr(&sc->sc_lock, LK_RELEASE, NULL, curproc); + + return 0; +} + +int +agp_alloc_dmamem(bus_dma_tag_t tag, size_t size, int flags, + bus_dmamap_t *mapp, caddr_t *vaddr, bus_addr_t *baddr, + bus_dma_segment_t *seg, int nseg, int *rseg) + +{ + int error, level = 0; + + if ((error = bus_dmamem_alloc(tag, size, PAGE_SIZE, 0, + seg, nseg, rseg, BUS_DMA_NOWAIT)) != 0) + goto out; + level++; + + if ((error = bus_dmamem_map(tag, seg, *rseg, size, vaddr, + BUS_DMA_NOWAIT | flags)) != 0) + goto out; + level++; + + if ((error = bus_dmamap_create(tag, size, *rseg, size, 0, + BUS_DMA_NOWAIT, mapp)) != 0) + goto out; + level++; + + if ((error = bus_dmamap_load(tag, *mapp, *vaddr, size, NULL, + BUS_DMA_NOWAIT)) != 0) + goto out; + + *baddr = (*mapp)->dm_segs[0].ds_addr; + + return 0; +out: + switch (level) { + case 3: + bus_dmamap_destroy(tag, *mapp); + /* FALLTHROUGH */ + case 2: + bus_dmamem_unmap(tag, *vaddr, size); + /* FALLTHROUGH */ + case 1: + bus_dmamem_free(tag, seg, *rseg); + break; + default: + break; + } + + return error; +} + +void +agp_free_dmamem(bus_dma_tag_t tag, size_t size, bus_dmamap_t map, + caddr_t vaddr, bus_dma_segment_t *seg, int nseg) +{ + + bus_dmamap_unload(tag, map); + bus_dmamap_destroy(tag, map); + bus_dmamem_unmap(tag, vaddr, size); + bus_dmamem_free(tag, seg, nseg); +} +#endif diff --git a/sys/dev/pci/vga_pcivar.h b/sys/dev/pci/vga_pcivar.h index 58b934d5169..4a297cd86d3 100644 --- a/sys/dev/pci/vga_pcivar.h +++ b/sys/dev/pci/vga_pcivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: vga_pcivar.h,v 1.4 2002/03/14 01:27:00 millert Exp $ */ +/* $OpenBSD: vga_pcivar.h,v 1.5 2002/07/12 20:17:03 mickey Exp $ */ /* $NetBSD: vga_pcivar.h,v 1.1 1998/03/22 15:16:19 drochner Exp $ */ /* @@ -28,11 +28,81 @@ * rights to redistribute these changes. */ +#ifndef _PCI_VGA_PCIVAR_H_ +#define _PCI_VGA_PCIVAR_H_ + #define DEVICE_IS_VGA_PCI(class, id) \ (((PCI_CLASS(class) == PCI_CLASS_DISPLAY && \ PCI_SUBCLASS(class) == PCI_SUBCLASS_DISPLAY_VGA) || \ (PCI_CLASS(class) == PCI_CLASS_PREHISTORIC && \ PCI_SUBCLASS(class) == PCI_SUBCLASS_PREHISTORIC_VGA)) ? 1 : 0) +enum agp_acquire_state { + AGP_ACQUIRE_FREE, + AGP_ACQUIRE_USER, + AGP_ACQUIRE_KERNEL +}; + +/* + * Data structure to describe an AGP memory allocation. + */ +TAILQ_HEAD(agp_memory_list, agp_memory); +struct agp_memory { + TAILQ_ENTRY(agp_memory) am_link; /* wiring for the tailq */ + int am_id; /* unique id for block */ + vsize_t am_size; /* number of bytes allocated */ + int am_type; /* chipset specific type */ + off_t am_offset; /* page offset if bound */ + int am_is_bound; /* non-zero if bound */ + bus_addr_t am_physical; + caddr_t am_virtual; + bus_dmamap_t am_dmamap; + int am_nseg; + bus_dma_segment_t *am_dmaseg; +}; + +struct vga_pci_softc { + struct device sc_dev; + +#if 0 + struct vga_config *sc_vc; /* VGA configuration */ +#endif + + /* agp stuff */ + bus_space_tag_t sc_bt, sc_memt; + bus_space_handle_t sc_bh; + bus_addr_t sc_apaddr; + bus_size_t sc_apsize; + bus_dma_tag_t sc_dmat; + struct lock sc_lock; /* lock for access to GATT */ + pcitag_t sc_pcitag; /* PCI tag, in case we need it. */ + pcireg_t sc_id; + pci_chipset_tag_t sc_pc; + + struct agp_methods *sc_methods; + void *sc_chipc; /* chipset-dependent state */ + + int sc_opened; + int sc_capoff; + int sc_apflags; + int sc_nextid; /* next memory block id */ + + u_int32_t sc_maxmem; /* allocation upper bound */ + u_int32_t sc_allocated; /* amount allocated */ + enum agp_acquire_state sc_state; + struct agp_memory_list sc_memory; /* list of allocated memory */ +}; + +struct agp_product { + int ap_vendor; + int ap_product; + int (*ap_attach)(struct vga_pci_softc *, + struct pci_attach_args *, struct pci_attach_args *); +}; +/* MD-defined */ +extern const struct agp_product agp_products[]; + int vga_pci_cnattach(bus_space_tag_t, bus_space_tag_t, pci_chipset_tag_t, int, int, int); + +#endif /* _PCI_VGA_PCIVAR_H_ */ diff --git a/sys/sys/agpio.h b/sys/sys/agpio.h new file mode 100644 index 00000000000..02c92dffdea --- /dev/null +++ b/sys/sys/agpio.h @@ -0,0 +1,132 @@ +/* $OpenBSD: agpio.h,v 1.1 2002/07/12 20:17:03 mickey Exp $ */ + +/*- + * Copyright (c) 2000 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/sys/sys/agpio.h,v 1.1 2000/06/09 16:04:30 dfr Exp $ + */ + +#ifndef _SYS_AGPIO_H_ +#define _SYS_AGPIO_H_ + +#define AGP_DEVICE "/dev/ttyC0" + +/* + * The AGP gatt uses 4k pages irrespective of the host page size. + */ +#define AGP_PAGE_SIZE 4096 +#define AGP_PAGE_SHIFT 12 + +/* + * Macros to manipulate AGP mode words. + */ +#define AGP_MODE_GET_RQ(x) (((x) & 0xff000000U) >> 24) +#define AGP_MODE_GET_SBA(x) (((x) & 0x00000200U) >> 9) +#define AGP_MODE_GET_AGP(x) (((x) & 0x00000100U) >> 8) +#define AGP_MODE_GET_4G(x) (((x) & 0x00000020U) >> 5) +#define AGP_MODE_GET_FW(x) (((x) & 0x00000010U) >> 4) +#define AGP_MODE_GET_RATE(x) ((x) & 0x00000003U) +#define AGP_MODE_SET_RQ(x,v) (((x) & ~0xff000000U) | ((v) << 24)) +#define AGP_MODE_SET_SBA(x,v) (((x) & ~0x00000200U) | ((v) << 9)) +#define AGP_MODE_SET_AGP(x,v) (((x) & ~0x00000100U) | ((v) << 8)) +#define AGP_MODE_SET_4G(x,v) (((x) & ~0x00000020U) | ((v) << 5)) +#define AGP_MODE_SET_FW(x,v) (((x) & ~0x00000010U) | ((v) << 4)) +#define AGP_MODE_SET_RATE(x,v) (((x) & ~0x00000003U) | (v)) +#define AGP_MODE_RATE_1x 0x00000001 +#define AGP_MODE_RATE_2x 0x00000002 +#define AGP_MODE_RATE_4x 0x00000004 + +#define AGPIOC_BASE 'A' +#define AGPIOC_INFO _IOR (AGPIOC_BASE, 0, agp_info) +#define AGPIOC_ACQUIRE _IO (AGPIOC_BASE, 1) +#define AGPIOC_RELEASE _IO (AGPIOC_BASE, 2) +#define AGPIOC_SETUP _IOW (AGPIOC_BASE, 3, agp_setup) +#if 0 +#define AGPIOC_RESERVE _IOW (AGPIOC_BASE, 4, agp_region) +#define AGPIOC_PROTECT _IOW (AGPIOC_BASE, 5, agp_region) +#endif +#define AGPIOC_ALLOCATE _IOWR(AGPIOC_BASE, 6, agp_allocate) +#define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int) +#define AGPIOC_BIND _IOW (AGPIOC_BASE, 8, agp_bind) +#define AGPIOC_UNBIND _IOW (AGPIOC_BASE, 9, agp_unbind) + +typedef struct _agp_version { + u_int16_t major; + u_int16_t minor; +} agp_version; + +typedef struct _agp_info { + agp_version version; /* version of the driver */ + u_int32_t bridge_id; /* bridge vendor/device */ + u_int32_t agp_mode; /* mode info of bridge */ + off_t aper_base; /* base of aperture */ + size_t aper_size; /* size of aperture */ + size_t pg_total; /* max pages (swap + system) */ + size_t pg_system; /* max pages (system) */ + size_t pg_used; /* current pages used */ +} agp_info; + +typedef struct _agp_setup { + u_int32_t agp_mode; /* mode info of bridge */ +} agp_setup; + +#if 0 +/* + * The "prot" down below needs still a "sleep" flag somehow ... + */ +typedef struct _agp_segment { + off_t pg_start; /* starting page to populate */ + size_t pg_count; /* number of pages */ + int prot; /* prot flags for mmap */ +} agp_segment; + +typedef struct _agp_region { + pid_t pid; /* pid of process */ + size_t seg_count; /* number of segments */ + struct _agp_segment *seg_list; +} agp_region; +#endif + +typedef struct _agp_allocate { + int key; /* tag of allocation */ + size_t pg_count; /* number of pages */ + u_int32_t type; /* 0 == normal, other devspec */ + u_int32_t physical; /* device specific (some devices + * need a phys address of the + * actual page behind the gatt + * table) */ +} agp_allocate; + +typedef struct _agp_bind { + int key; /* tag of allocation */ + off_t pg_start; /* starting page to populate */ +} agp_bind; + +typedef struct _agp_unbind { + int key; /* tag of allocation */ + u_int32_t priority; /* priority for paging out */ +} agp_unbind; + +#endif /* !_SYS_AGPIO_H_ */ |