agp_sis.c revision 61452
161452Sdfr/*- 261452Sdfr * Copyright (c) 2000 Doug Rabson 361452Sdfr * All rights reserved. 461452Sdfr * 561452Sdfr * Redistribution and use in source and binary forms, with or without 661452Sdfr * modification, are permitted provided that the following conditions 761452Sdfr * are met: 861452Sdfr * 1. Redistributions of source code must retain the above copyright 961452Sdfr * notice, this list of conditions and the following disclaimer. 1061452Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1161452Sdfr * notice, this list of conditions and the following disclaimer in the 1261452Sdfr * documentation and/or other materials provided with the distribution. 1361452Sdfr * 1461452Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1561452Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1661452Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1761452Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1861452Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1961452Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2061452Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2161452Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2261452Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2361452Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2461452Sdfr * SUCH DAMAGE. 2561452Sdfr * 2661452Sdfr * $FreeBSD: head/sys/dev/agp/agp_sis.c 61452 2000-06-09 16:04:30Z dfr $ 2761452Sdfr */ 2861452Sdfr 2961452Sdfr#include "opt_bus.h" 3061452Sdfr#include "opt_pci.h" 3161452Sdfr 3261452Sdfr#include <sys/param.h> 3361452Sdfr#include <sys/systm.h> 3461452Sdfr#include <sys/malloc.h> 3561452Sdfr#include <sys/kernel.h> 3661452Sdfr#include <sys/bus.h> 3761452Sdfr#include <sys/lock.h> 3861452Sdfr 3961452Sdfr#include <pci/pcivar.h> 4061452Sdfr#include <pci/pcireg.h> 4161452Sdfr#include <pci/agppriv.h> 4261452Sdfr#include <pci/agpreg.h> 4361452Sdfr 4461452Sdfr#include <vm/vm.h> 4561452Sdfr#include <vm/vm_object.h> 4661452Sdfr#include <vm/pmap.h> 4761452Sdfr 4861452Sdfrstruct agp_sis_softc { 4961452Sdfr struct agp_softc agp; 5061452Sdfr u_int32_t initial_aperture; /* aperture size at startup */ 5161452Sdfr struct agp_gatt *gatt; 5261452Sdfr}; 5361452Sdfr 5461452Sdfrstatic const char* 5561452Sdfragp_sis_match(device_t dev) 5661452Sdfr{ 5761452Sdfr if (pci_get_class(dev) != PCIC_BRIDGE 5861452Sdfr || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 5961452Sdfr return NULL; 6061452Sdfr 6161452Sdfr if (agp_find_caps(dev) == 0) 6261452Sdfr return NULL; 6361452Sdfr 6461452Sdfr switch (pci_get_devid(dev)) { 6561452Sdfr case 0x00011039: 6661452Sdfr return ("SiS 5591 host to AGP bridge"); 6761452Sdfr }; 6861452Sdfr 6961452Sdfr if (pci_get_vendor(dev) == 0x1039) 7061452Sdfr return ("SIS Generic host to PCI bridge"); 7161452Sdfr 7261452Sdfr return NULL; 7361452Sdfr} 7461452Sdfr 7561452Sdfrstatic int 7661452Sdfragp_sis_probe(device_t dev) 7761452Sdfr{ 7861452Sdfr const char *desc; 7961452Sdfr 8061452Sdfr desc = agp_sis_match(dev); 8161452Sdfr if (desc) { 8261452Sdfr device_verbose(dev); 8361452Sdfr device_set_desc(dev, desc); 8461452Sdfr return 0; 8561452Sdfr } 8661452Sdfr 8761452Sdfr return ENXIO; 8861452Sdfr} 8961452Sdfr 9061452Sdfrstatic int 9161452Sdfragp_sis_attach(device_t dev) 9261452Sdfr{ 9361452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 9461452Sdfr struct agp_gatt *gatt; 9561452Sdfr int error; 9661452Sdfr 9761452Sdfr error = agp_generic_attach(dev); 9861452Sdfr if (error) 9961452Sdfr return error; 10061452Sdfr 10161452Sdfr sc->initial_aperture = AGP_GET_APERTURE(dev); 10261452Sdfr 10361452Sdfr for (;;) { 10461452Sdfr gatt = agp_alloc_gatt(dev); 10561452Sdfr if (gatt) 10661452Sdfr break; 10761452Sdfr 10861452Sdfr /* 10961452Sdfr * Probably contigmalloc failure. Try reducing the 11061452Sdfr * aperture so that the gatt size reduces. 11161452Sdfr */ 11261452Sdfr if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 11361452Sdfr agp_generic_detach(dev); 11461452Sdfr return ENOMEM; 11561452Sdfr } 11661452Sdfr } 11761452Sdfr sc->gatt = gatt; 11861452Sdfr 11961452Sdfr /* Install the gatt. */ 12061452Sdfr pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4); 12161452Sdfr 12261452Sdfr /* Enable the aperture. */ 12361452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 12461452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1); 12561452Sdfr 12661452Sdfr /* 12761452Sdfr * Enable the TLB and make it automatically invalidate entries 12861452Sdfr * when the GATT is written. 12961452Sdfr */ 13061452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1); 13161452Sdfr 13261452Sdfr return 0; 13361452Sdfr} 13461452Sdfr 13561452Sdfrstatic int 13661452Sdfragp_sis_detach(device_t dev) 13761452Sdfr{ 13861452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 13961452Sdfr int error; 14061452Sdfr 14161452Sdfr error = agp_generic_detach(dev); 14261452Sdfr if (error) 14361452Sdfr return error; 14461452Sdfr 14561452Sdfr /* Disable the aperture.. */ 14661452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 14761452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1); 14861452Sdfr 14961452Sdfr /* and the TLB. */ 15061452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1); 15161452Sdfr 15261452Sdfr /* Put the aperture back the way it started. */ 15361452Sdfr AGP_SET_APERTURE(dev, sc->initial_aperture); 15461452Sdfr 15561452Sdfr agp_free_gatt(sc->gatt); 15661452Sdfr return 0; 15761452Sdfr} 15861452Sdfr 15961452Sdfrstatic u_int32_t 16061452Sdfragp_sis_get_aperture(device_t dev) 16161452Sdfr{ 16261452Sdfr int gws; 16361452Sdfr 16461452Sdfr /* 16561452Sdfr * The aperture size is equal to 4M<<gws. 16661452Sdfr */ 16761452Sdfr gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4; 16861452Sdfr return (4*1024*1024) << gws; 16961452Sdfr} 17061452Sdfr 17161452Sdfrstatic int 17261452Sdfragp_sis_set_aperture(device_t dev, u_int32_t aperture) 17361452Sdfr{ 17461452Sdfr int gws; 17561452Sdfr 17661452Sdfr /* 17761452Sdfr * Check for a power of two and make sure its within the 17861452Sdfr * programmable range. 17961452Sdfr */ 18061452Sdfr if (aperture & (aperture - 1) 18161452Sdfr || aperture < 4*1024*1024 18261452Sdfr || aperture > 256*1024*1024) 18361452Sdfr return EINVAL; 18461452Sdfr 18561452Sdfr gws = ffs(aperture / 4*1024*1024) - 1; 18661452Sdfr 18761452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 18861452Sdfr ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70) 18961452Sdfr | gws << 4), 1); 19061452Sdfr 19161452Sdfr return 0; 19261452Sdfr} 19361452Sdfr 19461452Sdfrstatic int 19561452Sdfragp_sis_bind_page(device_t dev, int offset, vm_offset_t physical) 19661452Sdfr{ 19761452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 19861452Sdfr 19961452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 20061452Sdfr return EINVAL; 20161452Sdfr 20261452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 20361452Sdfr return 0; 20461452Sdfr} 20561452Sdfr 20661452Sdfrstatic int 20761452Sdfragp_sis_unbind_page(device_t dev, int offset) 20861452Sdfr{ 20961452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 21061452Sdfr 21161452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 21261452Sdfr return EINVAL; 21361452Sdfr 21461452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 21561452Sdfr return 0; 21661452Sdfr} 21761452Sdfr 21861452Sdfrstatic void 21961452Sdfragp_sis_flush_tlb(device_t dev) 22061452Sdfr{ 22161452Sdfr pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1); 22261452Sdfr} 22361452Sdfr 22461452Sdfrstatic device_method_t agp_sis_methods[] = { 22561452Sdfr /* Device interface */ 22661452Sdfr DEVMETHOD(device_probe, agp_sis_probe), 22761452Sdfr DEVMETHOD(device_attach, agp_sis_attach), 22861452Sdfr DEVMETHOD(device_detach, agp_sis_detach), 22961452Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 23061452Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 23161452Sdfr DEVMETHOD(device_resume, bus_generic_resume), 23261452Sdfr 23361452Sdfr /* AGP interface */ 23461452Sdfr DEVMETHOD(agp_get_aperture, agp_sis_get_aperture), 23561452Sdfr DEVMETHOD(agp_set_aperture, agp_sis_set_aperture), 23661452Sdfr DEVMETHOD(agp_bind_page, agp_sis_bind_page), 23761452Sdfr DEVMETHOD(agp_unbind_page, agp_sis_unbind_page), 23861452Sdfr DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb), 23961452Sdfr DEVMETHOD(agp_enable, agp_generic_enable), 24061452Sdfr DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 24161452Sdfr DEVMETHOD(agp_free_memory, agp_generic_free_memory), 24261452Sdfr DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 24361452Sdfr DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 24461452Sdfr 24561452Sdfr { 0, 0 } 24661452Sdfr}; 24761452Sdfr 24861452Sdfrstatic driver_t agp_sis_driver = { 24961452Sdfr "agp", 25061452Sdfr agp_sis_methods, 25161452Sdfr sizeof(struct agp_sis_softc), 25261452Sdfr}; 25361452Sdfr 25461452Sdfrstatic devclass_t agp_devclass; 25561452Sdfr 25661452SdfrDRIVER_MODULE(agp_sis, pci, agp_sis_driver, agp_devclass, 0, 0); 257