agp_sis.c revision 173203
1234285Sdim/*- 2234285Sdim * Copyright (c) 2000 Doug Rabson 3234285Sdim * All rights reserved. 4234285Sdim * 5234285Sdim * Redistribution and use in source and binary forms, with or without 6234285Sdim * modification, are permitted provided that the following conditions 7234285Sdim * are met: 8234285Sdim * 1. Redistributions of source code must retain the above copyright 9234285Sdim * notice, this list of conditions and the following disclaimer. 10239462Sdim * 2. Redistributions in binary form must reproduce the above copyright 11239462Sdim * notice, this list of conditions and the following disclaimer in the 12239462Sdim * documentation and/or other materials provided with the distribution. 13234285Sdim * 14234285Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15234285Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16234285Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17234285Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18234285Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19234285Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20249423Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22249423Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23234285Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24234285Sdim * SUCH DAMAGE. 25234285Sdim */ 26234285Sdim 27234285Sdim#include <sys/cdefs.h> 28234285Sdim__FBSDID("$FreeBSD: head/sys/dev/agp/agp_sis.c 173203 2007-10-30 22:09:16Z jhb $"); 29234285Sdim 30234285Sdim#include "opt_bus.h" 31234285Sdim 32234285Sdim#include <sys/param.h> 33234285Sdim#include <sys/systm.h> 34234285Sdim#include <sys/malloc.h> 35234285Sdim#include <sys/kernel.h> 36249423Sdim#include <sys/module.h> 37249423Sdim#include <sys/bus.h> 38249423Sdim#include <sys/lock.h> 39234285Sdim#include <sys/mutex.h> 40234285Sdim#include <sys/proc.h> 41234285Sdim 42234285Sdim#include <dev/pci/pcivar.h> 43251662Sdim#include <dev/pci/pcireg.h> 44288943Sdim#include <pci/agppriv.h> 45251662Sdim#include <pci/agpreg.h> 46251662Sdim 47251662Sdim#include <vm/vm.h> 48251662Sdim#include <vm/vm_object.h> 49234285Sdim#include <vm/pmap.h> 50234285Sdim 51234285Sdimstruct agp_sis_softc { 52234285Sdim struct agp_softc agp; 53234285Sdim u_int32_t initial_aperture; /* aperture size at startup */ 54288943Sdim struct agp_gatt *gatt; 55251662Sdim}; 56251662Sdim 57251662Sdimstatic const char* 58234285Sdimagp_sis_match(device_t dev) 59276479Sdim{ 60234285Sdim if (pci_get_class(dev) != PCIC_BRIDGE 61234285Sdim || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 62276479Sdim return NULL; 63234285Sdim 64234285Sdim if (agp_find_caps(dev) == 0) 65234285Sdim return NULL; 66234285Sdim 67234285Sdim switch (pci_get_devid(dev)) { 68234285Sdim case 0x00011039: 69234285Sdim return ("SiS 5591 host to AGP bridge"); 70234285Sdim case 0x05301039: 71288943Sdim return ("SiS 530 host to AGP bridge"); 72288943Sdim case 0x05401039: 73234285Sdim return ("SiS 540 host to AGP bridge"); 74234285Sdim case 0x05501039: 75234285Sdim return ("SiS 550 host to AGP bridge"); 76234285Sdim case 0x06201039: 77296417Sdim return ("SiS 620 host to AGP bridge"); 78234285Sdim case 0x06301039: 79234285Sdim return ("SiS 630 host to AGP bridge"); 80234285Sdim case 0x06451039: 81234285Sdim return ("SiS 645 host to AGP bridge"); 82234285Sdim case 0x06461039: 83288943Sdim return ("SiS 645DX host to AGP bridge"); 84288943Sdim case 0x06481039: 85288943Sdim return ("SiS 648 host to AGP bridge"); 86288943Sdim case 0x06501039: 87288943Sdim return ("SiS 650 host to AGP bridge"); 88288943Sdim case 0x06511039: 89288943Sdim return ("SiS 651 host to AGP bridge"); 90288943Sdim case 0x06551039: 91288943Sdim return ("SiS 655 host to AGP bridge"); 92288943Sdim case 0x06611039: 93288943Sdim return ("SiS 661 host to AGP bridge"); 94288943Sdim case 0x07301039: 95288943Sdim return ("SiS 730 host to AGP bridge"); 96288943Sdim case 0x07351039: 97288943Sdim return ("SiS 735 host to AGP bridge"); 98288943Sdim case 0x07401039: 99288943Sdim return ("SiS 740 host to AGP bridge"); 100288943Sdim case 0x07411039: 101288943Sdim return ("SiS 741 host to AGP bridge"); 102288943Sdim case 0x07451039: 103288943Sdim return ("SiS 745 host to AGP bridge"); 104288943Sdim case 0x07461039: 105288943Sdim return ("SiS 746 host to AGP bridge"); 106288943Sdim }; 107288943Sdim 108288943Sdim return NULL; 109288943Sdim} 110288943Sdim 111288943Sdimstatic int 112288943Sdimagp_sis_probe(device_t dev) 113288943Sdim{ 114288943Sdim const char *desc; 115288943Sdim 116288943Sdim if (resource_disabled("agp", device_get_unit(dev))) 117288943Sdim return (ENXIO); 118288943Sdim desc = agp_sis_match(dev); 119288943Sdim if (desc) { 120288943Sdim device_set_desc(dev, desc); 121288943Sdim return BUS_PROBE_DEFAULT; 122288943Sdim } 123288943Sdim 124288943Sdim return ENXIO; 125288943Sdim} 126288943Sdim 127288943Sdimstatic int 128288943Sdimagp_sis_attach(device_t dev) 129288943Sdim{ 130288943Sdim struct agp_sis_softc *sc = device_get_softc(dev); 131288943Sdim struct agp_gatt *gatt; 132288943Sdim int error; 133288943Sdim 134288943Sdim error = agp_generic_attach(dev); 135288943Sdim if (error) 136288943Sdim return error; 137288943Sdim 138288943Sdim sc->initial_aperture = AGP_GET_APERTURE(dev); 139288943Sdim 140288943Sdim for (;;) { 141288943Sdim gatt = agp_alloc_gatt(dev); 142288943Sdim if (gatt) 143288943Sdim break; 144288943Sdim 145288943Sdim /* 146288943Sdim * Probably contigmalloc failure. Try reducing the 147288943Sdim * aperture so that the gatt size reduces. 148288943Sdim */ 149288943Sdim if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 150288943Sdim agp_generic_detach(dev); 151288943Sdim return ENOMEM; 152288943Sdim } 153288943Sdim } 154288943Sdim sc->gatt = gatt; 155288943Sdim 156288943Sdim /* Install the gatt. */ 157288943Sdim pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4); 158288943Sdim 159288943Sdim /* Enable the aperture. */ 160288943Sdim pci_write_config(dev, AGP_SIS_WINCTRL, 161288943Sdim pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1); 162288943Sdim 163288943Sdim /* 164288943Sdim * Enable the TLB and make it automatically invalidate entries 165288943Sdim * when the GATT is written. 166288943Sdim */ 167288943Sdim pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1); 168288943Sdim 169288943Sdim return 0; 170288943Sdim} 171288943Sdim 172288943Sdimstatic int 173288943Sdimagp_sis_detach(device_t dev) 174288943Sdim{ 175288943Sdim struct agp_sis_softc *sc = device_get_softc(dev); 176288943Sdim 177288943Sdim agp_free_cdev(dev); 178288943Sdim 179288943Sdim /* Disable the aperture.. */ 180288943Sdim pci_write_config(dev, AGP_SIS_WINCTRL, 181288943Sdim pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1); 182288943Sdim 183288943Sdim /* and the TLB. */ 184288943Sdim pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1); 185288943Sdim 186288943Sdim /* Put the aperture back the way it started. */ 187288943Sdim AGP_SET_APERTURE(dev, sc->initial_aperture); 188288943Sdim 189288943Sdim agp_free_gatt(sc->gatt); 190288943Sdim agp_free_res(dev); 191288943Sdim return 0; 192288943Sdim} 193288943Sdim 194288943Sdimstatic u_int32_t 195288943Sdimagp_sis_get_aperture(device_t dev) 196288943Sdim{ 197288943Sdim int gws; 198288943Sdim 199288943Sdim /* 200288943Sdim * The aperture size is equal to 4M<<gws. 201288943Sdim */ 202288943Sdim gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4; 203288943Sdim return (4*1024*1024) << gws; 204288943Sdim} 205288943Sdim 206288943Sdimstatic int 207288943Sdimagp_sis_set_aperture(device_t dev, u_int32_t aperture) 208288943Sdim{ 209288943Sdim int gws; 210288943Sdim 211288943Sdim /* 212288943Sdim * Check for a power of two and make sure its within the 213288943Sdim * programmable range. 214288943Sdim */ 215288943Sdim if (aperture & (aperture - 1) 216288943Sdim || aperture < 4*1024*1024 217288943Sdim || aperture > 256*1024*1024) 218288943Sdim return EINVAL; 219288943Sdim 220288943Sdim gws = ffs(aperture / 4*1024*1024) - 1; 221288943Sdim 222288943Sdim pci_write_config(dev, AGP_SIS_WINCTRL, 223288943Sdim ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70) 224288943Sdim | gws << 4), 1); 225288943Sdim 226288943Sdim return 0; 227288943Sdim} 228288943Sdim 229288943Sdimstatic int 230288943Sdimagp_sis_bind_page(device_t dev, int offset, vm_offset_t physical) 231288943Sdim{ 232288943Sdim struct agp_sis_softc *sc = device_get_softc(dev); 233288943Sdim 234288943Sdim if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 235288943Sdim return EINVAL; 236288943Sdim 237288943Sdim sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 238288943Sdim return 0; 239288943Sdim} 240288943Sdim 241288943Sdimstatic int 242288943Sdimagp_sis_unbind_page(device_t dev, int offset) 243234285Sdim{ 244234285Sdim struct agp_sis_softc *sc = device_get_softc(dev); 245288943Sdim 246288943Sdim if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 247234285Sdim return EINVAL; 248234285Sdim 249234285Sdim sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 250234285Sdim return 0; 251234285Sdim} 252280031Sdim 253288943Sdimstatic void 254234285Sdimagp_sis_flush_tlb(device_t dev) 255234285Sdim{ 256234285Sdim pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1); 257280031Sdim} 258234285Sdim 259234285Sdimstatic device_method_t agp_sis_methods[] = { 260280031Sdim /* Device interface */ 261234285Sdim DEVMETHOD(device_probe, agp_sis_probe), 262234285Sdim DEVMETHOD(device_attach, agp_sis_attach), 263280031Sdim DEVMETHOD(device_detach, agp_sis_detach), 264234285Sdim DEVMETHOD(device_shutdown, bus_generic_shutdown), 265234285Sdim DEVMETHOD(device_suspend, bus_generic_suspend), 266234285Sdim DEVMETHOD(device_resume, bus_generic_resume), 267288943Sdim 268234285Sdim /* AGP interface */ 269280031Sdim DEVMETHOD(agp_get_aperture, agp_sis_get_aperture), 270234285Sdim DEVMETHOD(agp_set_aperture, agp_sis_set_aperture), 271239462Sdim DEVMETHOD(agp_bind_page, agp_sis_bind_page), 272280031Sdim DEVMETHOD(agp_unbind_page, agp_sis_unbind_page), 273234285Sdim DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb), 274234285Sdim DEVMETHOD(agp_enable, agp_generic_enable), 275234285Sdim DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 276234285Sdim DEVMETHOD(agp_free_memory, agp_generic_free_memory), 277234285Sdim DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 278280031Sdim DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 279234285Sdim 280239462Sdim { 0, 0 } 281280031Sdim}; 282234285Sdim 283234285Sdimstatic driver_t agp_sis_driver = { 284234285Sdim "agp", 285234285Sdim agp_sis_methods, 286234285Sdim sizeof(struct agp_sis_softc), 287234285Sdim}; 288234285Sdim 289234285Sdimstatic devclass_t agp_devclass; 290234285Sdim 291234285SdimDRIVER_MODULE(agp_sis, hostb, agp_sis_driver, agp_devclass, 0, 0); 292288943SdimMODULE_DEPEND(agp_sis, agp, 1, 1, 1); 293288943SdimMODULE_DEPEND(agp_sis, pci, 1, 1, 1); 294234285Sdim