agp_sis.c revision 241885
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 27116192Sobrien#include <sys/cdefs.h> 28116192Sobrien__FBSDID("$FreeBSD: head/sys/dev/agp/agp_sis.c 241885 2012-10-22 13:06:09Z eadler $"); 29116192Sobrien 3061452Sdfr#include "opt_bus.h" 3161452Sdfr 3261452Sdfr#include <sys/param.h> 3361452Sdfr#include <sys/systm.h> 3461452Sdfr#include <sys/malloc.h> 3561452Sdfr#include <sys/kernel.h> 36129878Sphk#include <sys/module.h> 3761452Sdfr#include <sys/bus.h> 3861452Sdfr#include <sys/lock.h> 3976827Salfred#include <sys/mutex.h> 4079339Sjhb#include <sys/proc.h> 4161452Sdfr 42173573Sjhb#include <dev/agp/agppriv.h> 43173573Sjhb#include <dev/agp/agpreg.h> 44119288Simp#include <dev/pci/pcivar.h> 45119288Simp#include <dev/pci/pcireg.h> 4661452Sdfr 4761452Sdfr#include <vm/vm.h> 4861452Sdfr#include <vm/vm_object.h> 4961452Sdfr#include <vm/pmap.h> 5061452Sdfr 5161452Sdfrstruct agp_sis_softc { 5261452Sdfr struct agp_softc agp; 5361452Sdfr u_int32_t initial_aperture; /* aperture size at startup */ 5461452Sdfr struct agp_gatt *gatt; 5561452Sdfr}; 5661452Sdfr 5761452Sdfrstatic const char* 5861452Sdfragp_sis_match(device_t dev) 5961452Sdfr{ 6061452Sdfr if (pci_get_class(dev) != PCIC_BRIDGE 6161452Sdfr || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 6261452Sdfr return NULL; 6361452Sdfr 6461452Sdfr if (agp_find_caps(dev) == 0) 6561452Sdfr return NULL; 6661452Sdfr 6761452Sdfr switch (pci_get_devid(dev)) { 6861452Sdfr case 0x00011039: 6961452Sdfr return ("SiS 5591 host to AGP bridge"); 70129415Sanholt case 0x05301039: 71129415Sanholt return ("SiS 530 host to AGP bridge"); 72129415Sanholt case 0x05401039: 73129415Sanholt return ("SiS 540 host to AGP bridge"); 74129415Sanholt case 0x05501039: 75129415Sanholt return ("SiS 550 host to AGP bridge"); 76129415Sanholt case 0x06201039: 77129415Sanholt return ("SiS 620 host to AGP bridge"); 78129415Sanholt case 0x06301039: 79129415Sanholt return ("SiS 630 host to AGP bridge"); 80129415Sanholt case 0x06451039: 81129415Sanholt return ("SiS 645 host to AGP bridge"); 82129415Sanholt case 0x06461039: 83129415Sanholt return ("SiS 645DX host to AGP bridge"); 84112184Ssos case 0x06481039: 85112184Ssos return ("SiS 648 host to AGP bridge"); 86129415Sanholt case 0x06501039: 87129415Sanholt return ("SiS 650 host to AGP bridge"); 88129415Sanholt case 0x06511039: 89129415Sanholt return ("SiS 651 host to AGP bridge"); 90129415Sanholt case 0x06551039: 91129415Sanholt return ("SiS 655 host to AGP bridge"); 92129415Sanholt case 0x06611039: 93129415Sanholt return ("SiS 661 host to AGP bridge"); 94129415Sanholt case 0x07301039: 95129415Sanholt return ("SiS 730 host to AGP bridge"); 96129415Sanholt case 0x07351039: 97129415Sanholt return ("SiS 735 host to AGP bridge"); 98129415Sanholt case 0x07401039: 99129415Sanholt return ("SiS 740 host to AGP bridge"); 100129415Sanholt case 0x07411039: 101129415Sanholt return ("SiS 741 host to AGP bridge"); 102129415Sanholt case 0x07451039: 103129415Sanholt return ("SiS 745 host to AGP bridge"); 104129415Sanholt case 0x07461039: 105129415Sanholt return ("SiS 746 host to AGP bridge"); 10661452Sdfr }; 10761452Sdfr 10861452Sdfr return NULL; 10961452Sdfr} 11061452Sdfr 11161452Sdfrstatic int 11261452Sdfragp_sis_probe(device_t dev) 11361452Sdfr{ 11461452Sdfr const char *desc; 11561452Sdfr 116241885Seadler if (resource_disabled("agp", device_get_unit(dev))) 117241885Seadler return (ENXIO); 11861452Sdfr desc = agp_sis_match(dev); 11961452Sdfr if (desc) { 12061452Sdfr device_set_desc(dev, desc); 121142398Simp return BUS_PROBE_DEFAULT; 12261452Sdfr } 12361452Sdfr 12461452Sdfr return ENXIO; 12561452Sdfr} 12661452Sdfr 12761452Sdfrstatic int 12861452Sdfragp_sis_attach(device_t dev) 12961452Sdfr{ 13061452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 13161452Sdfr struct agp_gatt *gatt; 13261452Sdfr int error; 13361452Sdfr 13461452Sdfr error = agp_generic_attach(dev); 13561452Sdfr if (error) 13661452Sdfr return error; 13761452Sdfr 13861452Sdfr sc->initial_aperture = AGP_GET_APERTURE(dev); 13961452Sdfr 14061452Sdfr for (;;) { 14161452Sdfr gatt = agp_alloc_gatt(dev); 14261452Sdfr if (gatt) 14361452Sdfr break; 14461452Sdfr 14561452Sdfr /* 14661452Sdfr * Probably contigmalloc failure. Try reducing the 14761452Sdfr * aperture so that the gatt size reduces. 14861452Sdfr */ 14961452Sdfr if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 15061452Sdfr agp_generic_detach(dev); 15161452Sdfr return ENOMEM; 15261452Sdfr } 15361452Sdfr } 15461452Sdfr sc->gatt = gatt; 15561452Sdfr 15661452Sdfr /* Install the gatt. */ 15761452Sdfr pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4); 15861452Sdfr 15961452Sdfr /* Enable the aperture. */ 16061452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 16161452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1); 16261452Sdfr 16361452Sdfr /* 16461452Sdfr * Enable the TLB and make it automatically invalidate entries 16561452Sdfr * when the GATT is written. 16661452Sdfr */ 16761452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1); 16861452Sdfr 16961452Sdfr return 0; 17061452Sdfr} 17161452Sdfr 17261452Sdfrstatic int 17361452Sdfragp_sis_detach(device_t dev) 17461452Sdfr{ 17561452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 17661452Sdfr 177173203Sjhb agp_free_cdev(dev); 17861452Sdfr 17961452Sdfr /* Disable the aperture.. */ 18061452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 18161452Sdfr pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1); 18261452Sdfr 18361452Sdfr /* and the TLB. */ 18461452Sdfr pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1); 18561452Sdfr 18661452Sdfr /* Put the aperture back the way it started. */ 18761452Sdfr AGP_SET_APERTURE(dev, sc->initial_aperture); 18861452Sdfr 18961452Sdfr agp_free_gatt(sc->gatt); 190173203Sjhb agp_free_res(dev); 19161452Sdfr return 0; 19261452Sdfr} 19361452Sdfr 19461452Sdfrstatic u_int32_t 19561452Sdfragp_sis_get_aperture(device_t dev) 19661452Sdfr{ 19761452Sdfr int gws; 19861452Sdfr 19961452Sdfr /* 20061452Sdfr * The aperture size is equal to 4M<<gws. 20161452Sdfr */ 20261452Sdfr gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4; 20361452Sdfr return (4*1024*1024) << gws; 20461452Sdfr} 20561452Sdfr 20661452Sdfrstatic int 20761452Sdfragp_sis_set_aperture(device_t dev, u_int32_t aperture) 20861452Sdfr{ 20961452Sdfr int gws; 21061452Sdfr 21161452Sdfr /* 21261452Sdfr * Check for a power of two and make sure its within the 21361452Sdfr * programmable range. 21461452Sdfr */ 21561452Sdfr if (aperture & (aperture - 1) 21661452Sdfr || aperture < 4*1024*1024 21761452Sdfr || aperture > 256*1024*1024) 21861452Sdfr return EINVAL; 21961452Sdfr 22061452Sdfr gws = ffs(aperture / 4*1024*1024) - 1; 22161452Sdfr 22261452Sdfr pci_write_config(dev, AGP_SIS_WINCTRL, 22361452Sdfr ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70) 22461452Sdfr | gws << 4), 1); 22561452Sdfr 22661452Sdfr return 0; 22761452Sdfr} 22861452Sdfr 22961452Sdfrstatic int 230194017Savgagp_sis_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical) 23161452Sdfr{ 23261452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 23361452Sdfr 234194017Savg if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 23561452Sdfr return EINVAL; 23661452Sdfr 23761452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 23861452Sdfr return 0; 23961452Sdfr} 24061452Sdfr 24161452Sdfrstatic int 242194017Savgagp_sis_unbind_page(device_t dev, vm_offset_t offset) 24361452Sdfr{ 24461452Sdfr struct agp_sis_softc *sc = device_get_softc(dev); 24561452Sdfr 246194017Savg if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 24761452Sdfr return EINVAL; 24861452Sdfr 24961452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 25061452Sdfr return 0; 25161452Sdfr} 25261452Sdfr 25361452Sdfrstatic void 25461452Sdfragp_sis_flush_tlb(device_t dev) 25561452Sdfr{ 25661452Sdfr pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1); 25761452Sdfr} 25861452Sdfr 25961452Sdfrstatic device_method_t agp_sis_methods[] = { 26061452Sdfr /* Device interface */ 26161452Sdfr DEVMETHOD(device_probe, agp_sis_probe), 26261452Sdfr DEVMETHOD(device_attach, agp_sis_attach), 26361452Sdfr DEVMETHOD(device_detach, agp_sis_detach), 26461452Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 26561452Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 26661452Sdfr DEVMETHOD(device_resume, bus_generic_resume), 26761452Sdfr 26861452Sdfr /* AGP interface */ 26961452Sdfr DEVMETHOD(agp_get_aperture, agp_sis_get_aperture), 27061452Sdfr DEVMETHOD(agp_set_aperture, agp_sis_set_aperture), 27161452Sdfr DEVMETHOD(agp_bind_page, agp_sis_bind_page), 27261452Sdfr DEVMETHOD(agp_unbind_page, agp_sis_unbind_page), 27361452Sdfr DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb), 27461452Sdfr DEVMETHOD(agp_enable, agp_generic_enable), 27561452Sdfr DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 27661452Sdfr DEVMETHOD(agp_free_memory, agp_generic_free_memory), 27761452Sdfr DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 27861452Sdfr DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 27961452Sdfr 28061452Sdfr { 0, 0 } 28161452Sdfr}; 28261452Sdfr 28361452Sdfrstatic driver_t agp_sis_driver = { 28461452Sdfr "agp", 28561452Sdfr agp_sis_methods, 28661452Sdfr sizeof(struct agp_sis_softc), 28761452Sdfr}; 28861452Sdfr 28961452Sdfrstatic devclass_t agp_devclass; 29061452Sdfr 291153572SjhbDRIVER_MODULE(agp_sis, hostb, agp_sis_driver, agp_devclass, 0, 0); 292113506SmdoddMODULE_DEPEND(agp_sis, agp, 1, 1, 1); 293113506SmdoddMODULE_DEPEND(agp_sis, pci, 1, 1, 1); 294