agp_ali.c revision 244926
1204076Spjd/*- 2217964Spjd * Copyright (c) 2000 Doug Rabson 3217964Spjd * All rights reserved. 4204076Spjd * 5204076Spjd * Redistribution and use in source and binary forms, with or without 6204076Spjd * modification, are permitted provided that the following conditions 7204076Spjd * are met: 8204076Spjd * 1. Redistributions of source code must retain the above copyright 9204076Spjd * notice, this list of conditions and the following disclaimer. 10204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 11204076Spjd * notice, this list of conditions and the following disclaimer in the 12204076Spjd * documentation and/or other materials provided with the distribution. 13204076Spjd * 14204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24204076Spjd * SUCH DAMAGE. 25204076Spjd */ 26204076Spjd 27204076Spjd#include <sys/cdefs.h> 28204076Spjd__FBSDID("$FreeBSD: head/sys/dev/agp/agp_ali.c 244926 2013-01-01 18:16:49Z antoine $"); 29204076Spjd 30204076Spjd#include <sys/param.h> 31204076Spjd#include <sys/systm.h> 32204076Spjd#include <sys/malloc.h> 33204076Spjd#include <sys/kernel.h> 34219370Spjd#include <sys/module.h> 35219370Spjd#include <sys/bus.h> 36219370Spjd#include <sys/lock.h> 37204076Spjd#include <sys/mutex.h> 38204076Spjd#include <sys/proc.h> 39219370Spjd 40219370Spjd#include <dev/agp/agppriv.h> 41204076Spjd#include <dev/agp/agpreg.h> 42219370Spjd#include <dev/pci/pcivar.h> 43204076Spjd#include <dev/pci/pcireg.h> 44204076Spjd 45204076Spjd#include <vm/vm.h> 46204076Spjd#include <vm/vm_object.h> 47204076Spjd#include <vm/pmap.h> 48204076Spjd 49204076Spjdstruct agp_ali_softc { 50219369Spjd struct agp_softc agp; 51219369Spjd u_int32_t initial_aperture; /* aperture size at startup */ 52219369Spjd struct agp_gatt *gatt; 53219369Spjd}; 54219369Spjd 55218040Spjdstatic const char* 56204076Spjdagp_ali_match(device_t dev) 57204076Spjd{ 58219370Spjd if (pci_get_class(dev) != PCIC_BRIDGE 59219370Spjd || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 60219370Spjd return NULL; 61219370Spjd 62219370Spjd if (agp_find_caps(dev) == 0) 63219370Spjd return NULL; 64219370Spjd 65219370Spjd switch (pci_get_devid(dev)) { 66219370Spjd case 0x167110b9: 67219370Spjd return ("Ali M1671 host to AGP bridge"); 68219370Spjd case 0x154110b9: 69219370Spjd return ("Ali M1541 host to AGP bridge"); 70219370Spjd case 0x162110b9: 71219370Spjd return ("Ali M1621 host to AGP bridge"); 72219370Spjd } 73219370Spjd 74219370Spjd return NULL; 75219370Spjd} 76219370Spjd 77219370Spjdstatic int 78219370Spjdagp_ali_probe(device_t dev) 79219370Spjd{ 80219370Spjd const char *desc; 81219370Spjd 82219370Spjd if (resource_disabled("agp", device_get_unit(dev))) 83219370Spjd return (ENXIO); 84219370Spjd desc = agp_ali_match(dev); 85219370Spjd if (desc) { 86219370Spjd device_set_desc(dev, desc); 87219370Spjd return BUS_PROBE_DEFAULT; 88219370Spjd } 89219370Spjd 90219370Spjd return ENXIO; 91219370Spjd} 92219370Spjd 93219370Spjdstatic int 94219370Spjdagp_ali_attach(device_t dev) 95219370Spjd{ 96219370Spjd struct agp_ali_softc *sc = device_get_softc(dev); 97219370Spjd struct agp_gatt *gatt; 98219385Spjd int error; 99219370Spjd u_int32_t attbase; 100219370Spjd 101219370Spjd error = agp_generic_attach(dev); 102219385Spjd if (error) 103219385Spjd return error; 104219370Spjd 105219370Spjd sc->initial_aperture = AGP_GET_APERTURE(dev); 106219370Spjd if (sc->initial_aperture == 0) { 107219370Spjd device_printf(dev, "bad initial aperture size, disabling\n"); 108219370Spjd return ENXIO; 109219370Spjd } 110219385Spjd 111219370Spjd for (;;) { 112219370Spjd gatt = agp_alloc_gatt(dev); 113219370Spjd if (gatt) 114219370Spjd break; 115219370Spjd 116219370Spjd /* 117219370Spjd * Probably contigmalloc failure. Try reducing the 118219370Spjd * aperture so that the gatt size reduces. 119219370Spjd */ 120219370Spjd if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 121219385Spjd agp_generic_detach(dev); 122219370Spjd return ENOMEM; 123219370Spjd } 124219370Spjd } 125219370Spjd sc->gatt = gatt; 126219370Spjd 127219370Spjd /* Install the gatt. */ 128219370Spjd attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 129217965Spjd pci_write_config(dev, AGP_ALI_ATTBASE, gatt->ag_physical | 130217965Spjd (attbase & 0xfff), 4); 131217965Spjd 132217965Spjd /* Enable the TLB. */ 133219369Spjd pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1); 134219369Spjd 135217965Spjd return 0; 136217965Spjd} 137219370Spjd 138219370Spjdstatic int 139219370Spjdagp_ali_detach(device_t dev) 140219370Spjd{ 141219370Spjd struct agp_ali_softc *sc = device_get_softc(dev); 142219370Spjd u_int32_t attbase; 143219370Spjd 144219370Spjd agp_free_cdev(dev); 145219370Spjd 146219370Spjd /* Disable the TLB.. */ 147219370Spjd pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1); 148217965Spjd 149217965Spjd /* Put the aperture back the way it started. */ 150217965Spjd AGP_SET_APERTURE(dev, sc->initial_aperture); 151218040Spjd attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 152218040Spjd pci_write_config(dev, AGP_ALI_ATTBASE, attbase & 0xfff, 4); 153217965Spjd 154219369Spjd agp_free_gatt(sc->gatt); 155217965Spjd agp_free_res(dev); 156217965Spjd return 0; 157217965Spjd} 158217965Spjd 159217965Spjd#define M 1024*1024 160217965Spjd 161219369Spjdstatic u_int32_t agp_ali_table[] = { 162217965Spjd 0, /* 0 - invalid */ 163217965Spjd 1, /* 1 - invalid */ 164217965Spjd 2, /* 2 - invalid */ 165217965Spjd 4*M, /* 3 - invalid */ 166219369Spjd 8*M, /* 4 - invalid */ 167217965Spjd 0, /* 5 - invalid */ 168217965Spjd 16*M, /* 6 - invalid */ 169204076Spjd 32*M, /* 7 - invalid */ 170204076Spjd 64*M, /* 8 - invalid */ 171204076Spjd 128*M, /* 9 - invalid */ 172204076Spjd 256*M, /* 10 - invalid */ 173204076Spjd}; 174204076Spjd#define agp_ali_table_size (sizeof(agp_ali_table) / sizeof(agp_ali_table[0])) 175204076Spjd 176204076Spjdstatic u_int32_t 177204076Spjdagp_ali_get_aperture(device_t dev) 178204076Spjd{ 179219369Spjd /* 180204076Spjd * The aperture size is derived from the low bits of attbase. 181204076Spjd * I'm not sure this is correct.. 182217965Spjd */ 183217965Spjd int i = pci_read_config(dev, AGP_ALI_ATTBASE, 4) & 0xf; 184212052Spjd if (i >= agp_ali_table_size) 185212052Spjd return 0; 186217962Spjd return agp_ali_table[i]; 187217965Spjd} 188217965Spjd 189217965Spjdstatic int 190217965Spjdagp_ali_set_aperture(device_t dev, u_int32_t aperture) 191204076Spjd{ 192204076Spjd int i; 193204076Spjd u_int32_t attbase; 194204076Spjd 195204076Spjd for (i = 0; i < agp_ali_table_size; i++) 196204076Spjd if (agp_ali_table[i] == aperture) 197204076Spjd break; 198204076Spjd if (i == agp_ali_table_size) 199204076Spjd return EINVAL; 200219369Spjd 201217965Spjd attbase = pci_read_config(dev, AGP_ALI_ATTBASE, 4); 202204076Spjd pci_write_config(dev, AGP_ALI_ATTBASE, (attbase & ~0xf) | i, 4); 203204076Spjd return 0; 204204076Spjd} 205204076Spjd 206204076Spjdstatic int 207204076Spjdagp_ali_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical) 208204076Spjd{ 209204076Spjd struct agp_ali_softc *sc = device_get_softc(dev); 210204076Spjd 211204076Spjd if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 212204076Spjd return EINVAL; 213219369Spjd 214204076Spjd sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 215204076Spjd return 0; 216204076Spjd} 217204076Spjd 218204076Spjdstatic int 219204076Spjdagp_ali_unbind_page(device_t dev, vm_offset_t offset) 220204076Spjd{ 221204076Spjd struct agp_ali_softc *sc = device_get_softc(dev); 222204076Spjd 223204076Spjd if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 224204076Spjd return EINVAL; 225204076Spjd 226219369Spjd sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 227217965Spjd return 0; 228204076Spjd} 229204076Spjd 230204076Spjdstatic void 231204076Spjdagp_ali_flush_tlb(device_t dev) 232204076Spjd{ 233204076Spjd pci_write_config(dev, AGP_ALI_TLBCTRL, 0x90, 1); 234204076Spjd pci_write_config(dev, AGP_ALI_TLBCTRL, 0x10, 1); 235204076Spjd} 236204076Spjd 237204076Spjdstatic device_method_t agp_ali_methods[] = { 238204076Spjd /* Device interface */ 239204076Spjd DEVMETHOD(device_probe, agp_ali_probe), 240219369Spjd DEVMETHOD(device_attach, agp_ali_attach), 241217965Spjd DEVMETHOD(device_detach, agp_ali_detach), 242204076Spjd DEVMETHOD(device_shutdown, bus_generic_shutdown), 243217731Spjd DEVMETHOD(device_suspend, bus_generic_suspend), 244204076Spjd DEVMETHOD(device_resume, bus_generic_resume), 245204076Spjd 246204076Spjd /* AGP interface */ 247204076Spjd DEVMETHOD(agp_get_aperture, agp_ali_get_aperture), 248204076Spjd DEVMETHOD(agp_set_aperture, agp_ali_set_aperture), 249204076Spjd DEVMETHOD(agp_bind_page, agp_ali_bind_page), 250204076Spjd DEVMETHOD(agp_unbind_page, agp_ali_unbind_page), 251204076Spjd DEVMETHOD(agp_flush_tlb, agp_ali_flush_tlb), 252217731Spjd DEVMETHOD(agp_enable, agp_generic_enable), 253204076Spjd DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 254204076Spjd DEVMETHOD(agp_free_memory, agp_generic_free_memory), 255219369Spjd DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 256204076Spjd DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 257204076Spjd 258204076Spjd { 0, 0 } 259204076Spjd}; 260204076Spjd 261204076Spjdstatic driver_t agp_ali_driver = { 262204076Spjd "agp", 263204076Spjd agp_ali_methods, 264204076Spjd sizeof(struct agp_ali_softc), 265204076Spjd}; 266204076Spjd 267204076Spjdstatic devclass_t agp_devclass; 268204076Spjd 269204076SpjdDRIVER_MODULE(agp_ali, hostb, agp_ali_driver, agp_devclass, 0, 0); 270204076SpjdMODULE_DEPEND(agp_ali, agp, 1, 1, 1); 271204076SpjdMODULE_DEPEND(agp_ali, pci, 1, 1, 1); 272204076Spjd