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 <sys/param.h> 3159747216SDoug Rabson #include <sys/systm.h> 3259747216SDoug Rabson #include <sys/malloc.h> 3359747216SDoug Rabson #include <sys/kernel.h> 34f11d01c3SPoul-Henning Kamp #include <sys/module.h> 3559747216SDoug Rabson #include <sys/bus.h> 3659747216SDoug Rabson #include <sys/lock.h> 3723955314SAlfred Perlstein #include <sys/mutex.h> 3852b3919dSJohn Baldwin #include <sys/proc.h> 3959747216SDoug Rabson 40dbac8ff4SJohn Baldwin #include <dev/agp/agppriv.h> 41dbac8ff4SJohn Baldwin #include <dev/agp/agpreg.h> 4219b7ffd1SWarner Losh #include <dev/pci/pcivar.h> 4319b7ffd1SWarner Losh #include <dev/pci/pcireg.h> 4459747216SDoug Rabson 4559747216SDoug Rabson #include <vm/vm.h> 4659747216SDoug Rabson #include <vm/vm_object.h> 4759747216SDoug Rabson #include <vm/pmap.h> 4859747216SDoug Rabson 4959747216SDoug Rabson struct agp_sis_softc { 5059747216SDoug Rabson struct agp_softc agp; 5159747216SDoug Rabson u_int32_t initial_aperture; /* aperture size at startup */ 5259747216SDoug Rabson struct agp_gatt *gatt; 5359747216SDoug Rabson }; 5459747216SDoug Rabson 5559747216SDoug Rabson static const char* 5659747216SDoug Rabson agp_sis_match(device_t dev) 5759747216SDoug Rabson { 5859747216SDoug Rabson if (pci_get_class(dev) != PCIC_BRIDGE 5959747216SDoug Rabson || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 6059747216SDoug Rabson return NULL; 6159747216SDoug Rabson 6259747216SDoug Rabson if (agp_find_caps(dev) == 0) 6359747216SDoug Rabson return NULL; 6459747216SDoug Rabson 6559747216SDoug Rabson switch (pci_get_devid(dev)) { 6659747216SDoug Rabson case 0x00011039: 6759747216SDoug Rabson return ("SiS 5591 host to AGP bridge"); 68f4078c52SEric Anholt case 0x05301039: 69f4078c52SEric Anholt return ("SiS 530 host to AGP bridge"); 70f4078c52SEric Anholt case 0x05401039: 71f4078c52SEric Anholt return ("SiS 540 host to AGP bridge"); 72f4078c52SEric Anholt case 0x05501039: 73f4078c52SEric Anholt return ("SiS 550 host to AGP bridge"); 74f4078c52SEric Anholt case 0x06201039: 75f4078c52SEric Anholt return ("SiS 620 host to AGP bridge"); 76f4078c52SEric Anholt case 0x06301039: 77f4078c52SEric Anholt return ("SiS 630 host to AGP bridge"); 78f4078c52SEric Anholt case 0x06451039: 79f4078c52SEric Anholt return ("SiS 645 host to AGP bridge"); 80f4078c52SEric Anholt case 0x06461039: 81f4078c52SEric Anholt return ("SiS 645DX host to AGP bridge"); 8264eca1e1SSøren Schmidt case 0x06481039: 8364eca1e1SSøren Schmidt return ("SiS 648 host to AGP bridge"); 84f4078c52SEric Anholt case 0x06501039: 85f4078c52SEric Anholt return ("SiS 650 host to AGP bridge"); 86f4078c52SEric Anholt case 0x06511039: 87f4078c52SEric Anholt return ("SiS 651 host to AGP bridge"); 88f4078c52SEric Anholt case 0x06551039: 89f4078c52SEric Anholt return ("SiS 655 host to AGP bridge"); 90f4078c52SEric Anholt case 0x06611039: 91f4078c52SEric Anholt return ("SiS 661 host to AGP bridge"); 92f4078c52SEric Anholt case 0x07301039: 93f4078c52SEric Anholt return ("SiS 730 host to AGP bridge"); 94f4078c52SEric Anholt case 0x07351039: 95f4078c52SEric Anholt return ("SiS 735 host to AGP bridge"); 96f4078c52SEric Anholt case 0x07401039: 97f4078c52SEric Anholt return ("SiS 740 host to AGP bridge"); 98f4078c52SEric Anholt case 0x07411039: 99f4078c52SEric Anholt return ("SiS 741 host to AGP bridge"); 100f4078c52SEric Anholt case 0x07451039: 101f4078c52SEric Anholt return ("SiS 745 host to AGP bridge"); 102f4078c52SEric Anholt case 0x07461039: 103f4078c52SEric Anholt return ("SiS 746 host to AGP bridge"); 104*dfa4d7fdSAntoine Brodin } 10559747216SDoug Rabson 10659747216SDoug Rabson return NULL; 10759747216SDoug Rabson } 10859747216SDoug Rabson 10959747216SDoug Rabson static int 11059747216SDoug Rabson agp_sis_probe(device_t dev) 11159747216SDoug Rabson { 11259747216SDoug Rabson const char *desc; 11359747216SDoug Rabson 114a8de37b0SEitan Adler if (resource_disabled("agp", device_get_unit(dev))) 115a8de37b0SEitan Adler return (ENXIO); 11659747216SDoug Rabson desc = agp_sis_match(dev); 11759747216SDoug Rabson if (desc) { 11859747216SDoug Rabson device_set_desc(dev, desc); 119d701c913SWarner Losh return BUS_PROBE_DEFAULT; 12059747216SDoug Rabson } 12159747216SDoug Rabson 12259747216SDoug Rabson return ENXIO; 12359747216SDoug Rabson } 12459747216SDoug Rabson 12559747216SDoug Rabson static int 12659747216SDoug Rabson agp_sis_attach(device_t dev) 12759747216SDoug Rabson { 12859747216SDoug Rabson struct agp_sis_softc *sc = device_get_softc(dev); 12959747216SDoug Rabson struct agp_gatt *gatt; 13059747216SDoug Rabson int error; 13159747216SDoug Rabson 13259747216SDoug Rabson error = agp_generic_attach(dev); 13359747216SDoug Rabson if (error) 13459747216SDoug Rabson return error; 13559747216SDoug Rabson 13659747216SDoug Rabson sc->initial_aperture = AGP_GET_APERTURE(dev); 13759747216SDoug Rabson 13859747216SDoug Rabson for (;;) { 13959747216SDoug Rabson gatt = agp_alloc_gatt(dev); 14059747216SDoug Rabson if (gatt) 14159747216SDoug Rabson break; 14259747216SDoug Rabson 14359747216SDoug Rabson /* 14459747216SDoug Rabson * Probably contigmalloc failure. Try reducing the 14559747216SDoug Rabson * aperture so that the gatt size reduces. 14659747216SDoug Rabson */ 14759747216SDoug Rabson if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 14859747216SDoug Rabson agp_generic_detach(dev); 14959747216SDoug Rabson return ENOMEM; 15059747216SDoug Rabson } 15159747216SDoug Rabson } 15259747216SDoug Rabson sc->gatt = gatt; 15359747216SDoug Rabson 15459747216SDoug Rabson /* Install the gatt. */ 15559747216SDoug Rabson pci_write_config(dev, AGP_SIS_ATTBASE, gatt->ag_physical, 4); 15659747216SDoug Rabson 15759747216SDoug Rabson /* Enable the aperture. */ 15859747216SDoug Rabson pci_write_config(dev, AGP_SIS_WINCTRL, 15959747216SDoug Rabson pci_read_config(dev, AGP_SIS_WINCTRL, 1) | 3, 1); 16059747216SDoug Rabson 16159747216SDoug Rabson /* 16259747216SDoug Rabson * Enable the TLB and make it automatically invalidate entries 16359747216SDoug Rabson * when the GATT is written. 16459747216SDoug Rabson */ 16559747216SDoug Rabson pci_write_config(dev, AGP_SIS_TLBCTRL, 0x05, 1); 16659747216SDoug Rabson 16759747216SDoug Rabson return 0; 16859747216SDoug Rabson } 16959747216SDoug Rabson 17059747216SDoug Rabson static int 17159747216SDoug Rabson agp_sis_detach(device_t dev) 17259747216SDoug Rabson { 17359747216SDoug Rabson struct agp_sis_softc *sc = device_get_softc(dev); 17459747216SDoug Rabson 175f82a1d49SJohn Baldwin agp_free_cdev(dev); 17659747216SDoug Rabson 17759747216SDoug Rabson /* Disable the aperture.. */ 17859747216SDoug Rabson pci_write_config(dev, AGP_SIS_WINCTRL, 17959747216SDoug Rabson pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~3, 1); 18059747216SDoug Rabson 18159747216SDoug Rabson /* and the TLB. */ 18259747216SDoug Rabson pci_write_config(dev, AGP_SIS_TLBCTRL, 0, 1); 18359747216SDoug Rabson 18459747216SDoug Rabson /* Put the aperture back the way it started. */ 18559747216SDoug Rabson AGP_SET_APERTURE(dev, sc->initial_aperture); 18659747216SDoug Rabson 18759747216SDoug Rabson agp_free_gatt(sc->gatt); 188f82a1d49SJohn Baldwin agp_free_res(dev); 18959747216SDoug Rabson return 0; 19059747216SDoug Rabson } 19159747216SDoug Rabson 19259747216SDoug Rabson static u_int32_t 19359747216SDoug Rabson agp_sis_get_aperture(device_t dev) 19459747216SDoug Rabson { 19559747216SDoug Rabson int gws; 19659747216SDoug Rabson 19759747216SDoug Rabson /* 19859747216SDoug Rabson * The aperture size is equal to 4M<<gws. 19959747216SDoug Rabson */ 20059747216SDoug Rabson gws = (pci_read_config(dev, AGP_SIS_WINCTRL, 1) & 0x70) >> 4; 20159747216SDoug Rabson return (4*1024*1024) << gws; 20259747216SDoug Rabson } 20359747216SDoug Rabson 20459747216SDoug Rabson static int 20559747216SDoug Rabson agp_sis_set_aperture(device_t dev, u_int32_t aperture) 20659747216SDoug Rabson { 20759747216SDoug Rabson int gws; 20859747216SDoug Rabson 20959747216SDoug Rabson /* 21059747216SDoug Rabson * Check for a power of two and make sure its within the 21159747216SDoug Rabson * programmable range. 21259747216SDoug Rabson */ 21359747216SDoug Rabson if (aperture & (aperture - 1) 21459747216SDoug Rabson || aperture < 4*1024*1024 21559747216SDoug Rabson || aperture > 256*1024*1024) 21659747216SDoug Rabson return EINVAL; 21759747216SDoug Rabson 21859747216SDoug Rabson gws = ffs(aperture / 4*1024*1024) - 1; 21959747216SDoug Rabson 22059747216SDoug Rabson pci_write_config(dev, AGP_SIS_WINCTRL, 22159747216SDoug Rabson ((pci_read_config(dev, AGP_SIS_WINCTRL, 1) & ~0x70) 22259747216SDoug Rabson | gws << 4), 1); 22359747216SDoug Rabson 22459747216SDoug Rabson return 0; 22559747216SDoug Rabson } 22659747216SDoug Rabson 22759747216SDoug Rabson static int 228446188d1SAndriy Gapon agp_sis_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical) 22959747216SDoug Rabson { 23059747216SDoug Rabson struct agp_sis_softc *sc = device_get_softc(dev); 23159747216SDoug Rabson 232446188d1SAndriy Gapon if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 23359747216SDoug Rabson return EINVAL; 23459747216SDoug Rabson 23559747216SDoug Rabson sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 23659747216SDoug Rabson return 0; 23759747216SDoug Rabson } 23859747216SDoug Rabson 23959747216SDoug Rabson static int 240446188d1SAndriy Gapon agp_sis_unbind_page(device_t dev, vm_offset_t offset) 24159747216SDoug Rabson { 24259747216SDoug Rabson struct agp_sis_softc *sc = device_get_softc(dev); 24359747216SDoug Rabson 244446188d1SAndriy Gapon if (offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 24559747216SDoug Rabson return EINVAL; 24659747216SDoug Rabson 24759747216SDoug Rabson sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 24859747216SDoug Rabson return 0; 24959747216SDoug Rabson } 25059747216SDoug Rabson 25159747216SDoug Rabson static void 25259747216SDoug Rabson agp_sis_flush_tlb(device_t dev) 25359747216SDoug Rabson { 25459747216SDoug Rabson pci_write_config(dev, AGP_SIS_TLBFLUSH, 0x02, 1); 25559747216SDoug Rabson } 25659747216SDoug Rabson 25759747216SDoug Rabson static device_method_t agp_sis_methods[] = { 25859747216SDoug Rabson /* Device interface */ 25959747216SDoug Rabson DEVMETHOD(device_probe, agp_sis_probe), 26059747216SDoug Rabson DEVMETHOD(device_attach, agp_sis_attach), 26159747216SDoug Rabson DEVMETHOD(device_detach, agp_sis_detach), 26259747216SDoug Rabson DEVMETHOD(device_shutdown, bus_generic_shutdown), 26359747216SDoug Rabson DEVMETHOD(device_suspend, bus_generic_suspend), 26459747216SDoug Rabson DEVMETHOD(device_resume, bus_generic_resume), 26559747216SDoug Rabson 26659747216SDoug Rabson /* AGP interface */ 26759747216SDoug Rabson DEVMETHOD(agp_get_aperture, agp_sis_get_aperture), 26859747216SDoug Rabson DEVMETHOD(agp_set_aperture, agp_sis_set_aperture), 26959747216SDoug Rabson DEVMETHOD(agp_bind_page, agp_sis_bind_page), 27059747216SDoug Rabson DEVMETHOD(agp_unbind_page, agp_sis_unbind_page), 27159747216SDoug Rabson DEVMETHOD(agp_flush_tlb, agp_sis_flush_tlb), 27259747216SDoug Rabson DEVMETHOD(agp_enable, agp_generic_enable), 27359747216SDoug Rabson DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 27459747216SDoug Rabson DEVMETHOD(agp_free_memory, agp_generic_free_memory), 27559747216SDoug Rabson DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 27659747216SDoug Rabson DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 27759747216SDoug Rabson 27859747216SDoug Rabson { 0, 0 } 27959747216SDoug Rabson }; 28059747216SDoug Rabson 28159747216SDoug Rabson static driver_t agp_sis_driver = { 28259747216SDoug Rabson "agp", 28359747216SDoug Rabson agp_sis_methods, 28459747216SDoug Rabson sizeof(struct agp_sis_softc), 28559747216SDoug Rabson }; 28659747216SDoug Rabson 28759747216SDoug Rabson static devclass_t agp_devclass; 28859747216SDoug Rabson 289c626f1feSJohn Baldwin DRIVER_MODULE(agp_sis, hostb, agp_sis_driver, agp_devclass, 0, 0); 290f246e4a1SMatthew N. Dodd MODULE_DEPEND(agp_sis, agp, 1, 1, 1); 291f246e4a1SMatthew N. Dodd MODULE_DEPEND(agp_sis, pci, 1, 1, 1); 292