159747216SDoug Rabson /*- 259747216SDoug Rabson * Copyright (c) 2000 Doug Rabson 359747216SDoug Rabson * All rights reserved. 459747216SDoug Rabson * 559747216SDoug Rabson * Redistribution and use in source and binary forms, with or without 659747216SDoug Rabson * modification, are permitted provided that the following conditions 759747216SDoug Rabson * are met: 859747216SDoug Rabson * 1. Redistributions of source code must retain the above copyright 959747216SDoug Rabson * notice, this list of conditions and the following disclaimer. 1059747216SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 1159747216SDoug Rabson * notice, this list of conditions and the following disclaimer in the 1259747216SDoug Rabson * documentation and/or other materials provided with the distribution. 1359747216SDoug Rabson * 1459747216SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1559747216SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1659747216SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1759747216SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1859747216SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1959747216SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2059747216SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2159747216SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2259747216SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2359747216SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2459747216SDoug Rabson * SUCH DAMAGE. 2559747216SDoug Rabson */ 2659747216SDoug Rabson 27f4636c59SDavid E. O'Brien #include <sys/cdefs.h> 28f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 29f4636c59SDavid E. O'Brien 3059747216SDoug Rabson #include "opt_bus.h" 3159747216SDoug Rabson 3259747216SDoug Rabson #include <sys/param.h> 3359747216SDoug Rabson #include <sys/systm.h> 3459747216SDoug Rabson #include <sys/malloc.h> 3559747216SDoug Rabson #include <sys/kernel.h> 36f11d01c3SPoul-Henning Kamp #include <sys/module.h> 3759747216SDoug Rabson #include <sys/bus.h> 3859747216SDoug Rabson #include <sys/lock.h> 3923955314SAlfred Perlstein #include <sys/mutex.h> 4052b3919dSJohn Baldwin #include <sys/proc.h> 4159747216SDoug Rabson 42dbac8ff4SJohn Baldwin #include <dev/agp/agppriv.h> 43dbac8ff4SJohn Baldwin #include <dev/agp/agpreg.h> 4419b7ffd1SWarner Losh #include <dev/pci/pcivar.h> 4519b7ffd1SWarner Losh #include <dev/pci/pcireg.h> 4659747216SDoug Rabson 4759747216SDoug Rabson #include <vm/vm.h> 4859747216SDoug Rabson #include <vm/vm_object.h> 4959747216SDoug Rabson #include <vm/pmap.h> 5059747216SDoug Rabson 5159747216SDoug Rabson struct agp_ali_softc { 5259747216SDoug Rabson struct agp_softc agp; 5359747216SDoug Rabson u_int32_t initial_aperture; /* aperture size at startup */ 5459747216SDoug Rabson struct agp_gatt *gatt; 5559747216SDoug Rabson }; 5659747216SDoug Rabson 5759747216SDoug Rabson static const char* 5859747216SDoug Rabson agp_ali_match(device_t dev) 5959747216SDoug Rabson { 6059747216SDoug Rabson if (pci_get_class(dev) != PCIC_BRIDGE 6159747216SDoug Rabson || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 6259747216SDoug Rabson return NULL; 6359747216SDoug Rabson 6459747216SDoug Rabson if (agp_find_caps(dev) == 0) 6559747216SDoug Rabson return NULL; 6659747216SDoug Rabson 6759747216SDoug Rabson switch (pci_get_devid(dev)) { 684ac78327SOlivier Houchard case 0x167110b9: 694ac78327SOlivier Houchard return ("Ali M1671 host to AGP bridge"); 7059747216SDoug Rabson case 0x154110b9: 7159747216SDoug Rabson return ("Ali M1541 host to AGP bridge"); 72124cfec0SEric Anholt case 0x162110b9: 73124cfec0SEric Anholt return ("Ali M1621 host to AGP bridge"); 7459747216SDoug Rabson }; 7559747216SDoug Rabson 7659747216SDoug Rabson return NULL; 7759747216SDoug Rabson } 7859747216SDoug Rabson 7959747216SDoug Rabson static int 8059747216SDoug Rabson agp_ali_probe(device_t dev) 8159747216SDoug Rabson { 8259747216SDoug Rabson const char *desc; 8359747216SDoug Rabson 8425128fccSNate Lawson if (resource_disabled("agp", device_get_unit(dev))) 8525128fccSNate Lawson return (ENXIO); 8659747216SDoug Rabson desc = agp_ali_match(dev); 8759747216SDoug Rabson if (desc) { 8859747216SDoug Rabson device_set_desc(dev, desc); 89d701c913SWarner Losh return BUS_PROBE_DEFAULT; 9059747216SDoug Rabson } 9159747216SDoug Rabson 9259747216SDoug Rabson return ENXIO; 9359747216SDoug Rabson } 9459747216SDoug Rabson 9559747216SDoug Rabson static int 9659747216SDoug Rabson agp_ali_attach(device_t dev) 9759747216SDoug Rabson { 9859747216SDoug Rabson struct agp_ali_softc *sc = device_get_softc(dev); 9959747216SDoug Rabson struct agp_gatt *gatt; 10059747216SDoug Rabson int error; 10174674ea7SEric Anholt u_int32_t attbase; 10259747216SDoug Rabson 10359747216SDoug Rabson error = agp_generic_attach(dev); 10459747216SDoug Rabson if (error) 10559747216SDoug Rabson return error; 10659747216SDoug Rabson 10759747216SDoug Rabson sc->initial_aperture = AGP_GET_APERTURE(dev); 108a6cb9d8eSEric Anholt if (sc->initial_aperture == 0) { 109a6cb9d8eSEric Anholt device_printf(dev, "bad initial aperture size, disabling\n"); 110a6cb9d8eSEric Anholt return ENXIO; 111a6cb9d8eSEric Anholt } 11259747216SDoug Rabson 11359747216SDoug Rabson for (;;) { 11459747216SDoug Rabson gatt = agp_alloc_gatt(dev); 11559747216SDoug Rabson if (gatt) 11659747216SDoug Rabson break; 11759747216SDoug Rabson 11859747216SDoug Rabson /* 11959747216SDoug Rabson * Probably contigmalloc failure. Try reducing the 12059747216SDoug Rabson * aperture so that the gatt size reduces. 12159747216SDoug Rabson */ 12259747216SDoug Rabson if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 12359747216SDoug Rabson agp_generic_detach(dev); 12459747216SDoug Rabson return ENOMEM; 12559747216SDoug Rabson } 12659747216SDoug Rabson } 12759747216SDoug Rabson sc->gatt = gatt; 12859747216SDoug Rabson 12959747216SDoug Rabson /* Install the gatt. */ 13074674ea7SEric Anholt attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 13174674ea7SEric Anholt pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical | 1328c9610c9SEric Anholt (attbase & 0xfff), 4); 13359747216SDoug Rabson 13459747216SDoug Rabson /* Enable the TLB. */ 13559747216SDoug Rabson pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1); 13659747216SDoug Rabson 13759747216SDoug Rabson return 0; 13859747216SDoug Rabson } 13959747216SDoug Rabson 14059747216SDoug Rabson static int 14159747216SDoug Rabson agp_ali_detach(device_t dev) 14259747216SDoug Rabson { 14359747216SDoug Rabson struct agp_ali_softc *sc = device_get_softc(dev); 14474674ea7SEric Anholt u_int32_t attbase; 14559747216SDoug Rabson 146f82a1d49SJohn Baldwin agp_free_cdev(dev); 14759747216SDoug Rabson 14859747216SDoug Rabson /* Disable the TLB.. */ 14959747216SDoug Rabson pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1); 15059747216SDoug Rabson 15159747216SDoug Rabson /* Put the aperture back the way it started. */ 15259747216SDoug Rabson AGP_SET_APERTURE(dev, sc->initial_aperture); 15374674ea7SEric Anholt attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 1548c9610c9SEric Anholt pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4); 15559747216SDoug Rabson 15659747216SDoug Rabson agp_free_gatt(sc->gatt); 157f82a1d49SJohn Baldwin agp_free_res(dev); 15859747216SDoug Rabson return 0; 15959747216SDoug Rabson } 16059747216SDoug Rabson 16159747216SDoug Rabson #define M 1024*1024 16259747216SDoug Rabson 16359747216SDoug Rabson static u_int32_t agp_ali_table[] = { 16459747216SDoug Rabson 0, /* 0 - invalid */ 16559747216SDoug Rabson 1, /* 1 - invalid */ 16659747216SDoug Rabson 2, /* 2 - invalid */ 16759747216SDoug Rabson 4*M, /* 3 - invalid */ 16859747216SDoug Rabson 8*M, /* 4 - invalid */ 16959747216SDoug Rabson 0, /* 5 - invalid */ 17059747216SDoug Rabson 16*M, /* 6 - invalid */ 17159747216SDoug Rabson 32*M, /* 7 - invalid */ 17259747216SDoug Rabson 64*M, /* 8 - invalid */ 17359747216SDoug Rabson 128*M, /* 9 - invalid */ 17459747216SDoug Rabson 256*M, /* 10 - invalid */ 17559747216SDoug Rabson }; 17659747216SDoug Rabson #define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0])) 17759747216SDoug Rabson 17859747216SDoug Rabson static u_int32_t 17959747216SDoug Rabson agp_ali_get_aperture(device_t dev) 18059747216SDoug Rabson { 18159747216SDoug Rabson /* 18259747216SDoug Rabson * The aperture size is derived from the low bits of attbase. 18359747216SDoug Rabson * I'm not sure this is correct.. 18459747216SDoug Rabson */ 1858c9610c9SEric Anholt int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf; 18659747216SDoug Rabson if (i >= agp_ali_table_size) 18759747216SDoug Rabson return 0; 18859747216SDoug Rabson return agp_ali_table[i]; 18959747216SDoug Rabson } 19059747216SDoug Rabson 19159747216SDoug Rabson static int 19259747216SDoug Rabson agp_ali_set_aperture(device_t dev, u_int32_t aperture) 19359747216SDoug Rabson { 19459747216SDoug Rabson int i; 19574674ea7SEric Anholt u_int32_t attbase; 19659747216SDoug Rabson 19759747216SDoug Rabson for (i = 0; i < agp_ali_table_size; i++) 19859747216SDoug Rabson if (agp_ali_table[i] == aperture) 19959747216SDoug Rabson break; 20059747216SDoug Rabson if (i == agp_ali_table_size) 20159747216SDoug Rabson return EINVAL; 20259747216SDoug Rabson 20374674ea7SEric Anholt attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 2048c9610c9SEric Anholt pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4); 20559747216SDoug Rabson return 0; 20659747216SDoug Rabson } 20759747216SDoug Rabson 20859747216SDoug Rabson static int 20959747216SDoug Rabson agp_ali_bind_page(device_t dev, int offset, vm_offset_t physical) 21059747216SDoug Rabson { 21159747216SDoug Rabson struct agp_ali_softc *sc = device_get_softc(dev); 21259747216SDoug Rabson 21359747216SDoug Rabson if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 21459747216SDoug Rabson return EINVAL; 21559747216SDoug Rabson 21659747216SDoug Rabson sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 21759747216SDoug Rabson return 0; 21859747216SDoug Rabson } 21959747216SDoug Rabson 22059747216SDoug Rabson static int 22159747216SDoug Rabson agp_ali_unbind_page(device_t dev, int offset) 22259747216SDoug Rabson { 22359747216SDoug Rabson struct agp_ali_softc *sc = device_get_softc(dev); 22459747216SDoug Rabson 22559747216SDoug Rabson if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 22659747216SDoug Rabson return EINVAL; 22759747216SDoug Rabson 22859747216SDoug Rabson sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 22959747216SDoug Rabson return 0; 23059747216SDoug Rabson } 23159747216SDoug Rabson 23259747216SDoug Rabson static void 23359747216SDoug Rabson agp_ali_flush_tlb(device_t dev) 23459747216SDoug Rabson { 23559747216SDoug Rabson pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1); 23659747216SDoug Rabson pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1); 23759747216SDoug Rabson } 23859747216SDoug Rabson 23959747216SDoug Rabson static device_method_t agp_ali_methods[] = { 24059747216SDoug Rabson /* Device interface */ 24159747216SDoug Rabson DEVMETHOD(device_probe, agp_ali_probe), 24259747216SDoug Rabson DEVMETHOD(device_attach, agp_ali_attach), 24359747216SDoug Rabson DEVMETHOD(device_detach, agp_ali_detach), 24459747216SDoug Rabson DEVMETHOD(device_shutdown, bus_generic_shutdown), 24559747216SDoug Rabson DEVMETHOD(device_suspend, bus_generic_suspend), 24659747216SDoug Rabson DEVMETHOD(device_resume, bus_generic_resume), 24759747216SDoug Rabson 24859747216SDoug Rabson /* AGP interface */ 24959747216SDoug Rabson DEVMETHOD(agp_get_aperture, agp_ali_get_aperture), 25059747216SDoug Rabson DEVMETHOD(agp_set_aperture, agp_ali_set_aperture), 25159747216SDoug Rabson DEVMETHOD(agp_bind_page, agp_ali_bind_page), 25259747216SDoug Rabson DEVMETHOD(agp_unbind_page, agp_ali_unbind_page), 25359747216SDoug Rabson DEVMETHOD(agp_flush_tlb, agp_ali_flush_tlb), 25459747216SDoug Rabson DEVMETHOD(agp_enable, agp_generic_enable), 25559747216SDoug Rabson DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 25659747216SDoug Rabson DEVMETHOD(agp_free_memory, agp_generic_free_memory), 25759747216SDoug Rabson DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 25859747216SDoug Rabson DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 25959747216SDoug Rabson 26059747216SDoug Rabson { 0, 0 } 26159747216SDoug Rabson }; 26259747216SDoug Rabson 26359747216SDoug Rabson static driver_t agp_ali_driver = { 26459747216SDoug Rabson "agp", 26559747216SDoug Rabson agp_ali_methods, 26659747216SDoug Rabson sizeof(struct agp_ali_softc), 26759747216SDoug Rabson }; 26859747216SDoug Rabson 26959747216SDoug Rabson static devclass_t agp_devclass; 27059747216SDoug Rabson 271c626f1feSJohn Baldwin DRIVER_MODULE(agp_ali, hostb, agp_ali_driver, agp_devclass, 0, 0); 272f246e4a1SMatthew N. Dodd MODULE_DEPEND(agp_ali, agp, 1, 1, 1); 273f246e4a1SMatthew N. Dodd MODULE_DEPEND(agp_ali, pci, 1, 1, 1); 274