agp_via.c revision 79339
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_via.c 79339 2001-07-05 21:28:47Z jhb $ 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> 3876827Salfred#include <sys/mutex.h> 3979339Sjhb#include <sys/proc.h> 4061452Sdfr 4161452Sdfr#include <pci/pcivar.h> 4261452Sdfr#include <pci/pcireg.h> 4361452Sdfr#include <pci/agppriv.h> 4461452Sdfr#include <pci/agpreg.h> 4561452Sdfr 4661452Sdfr#include <vm/vm.h> 4761452Sdfr#include <vm/vm_object.h> 4861452Sdfr#include <vm/pmap.h> 4961452Sdfr 5061452Sdfrstruct agp_via_softc { 5161452Sdfr struct agp_softc agp; 5261452Sdfr u_int32_t initial_aperture; /* aperture size at startup */ 5361452Sdfr struct agp_gatt *gatt; 5461452Sdfr}; 5561452Sdfr 5661452Sdfrstatic const char* 5761452Sdfragp_via_match(device_t dev) 5861452Sdfr{ 5961452Sdfr if (pci_get_class(dev) != PCIC_BRIDGE 6061452Sdfr || pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 6161452Sdfr return NULL; 6261452Sdfr 6361452Sdfr if (agp_find_caps(dev) == 0) 6461452Sdfr return NULL; 6561452Sdfr 6661452Sdfr switch (pci_get_devid(dev)) { 6761452Sdfr case 0x05011106: 6861452Sdfr return ("VIA 8501 (Apollo MVP4) host to PCI bridge"); 6961452Sdfr case 0x05971106: 7061452Sdfr return ("VIA 82C597 (Apollo VP3) host to PCI bridge"); 7161452Sdfr case 0x05981106: 7261452Sdfr return ("VIA 82C598 (Apollo MVP3) host to PCI bridge"); 7361452Sdfr case 0x06911106: 7461452Sdfr return ("VIA 82C691 (Apollo Pro) host to PCI bridge"); 7561452Sdfr }; 7661452Sdfr 7761452Sdfr if (pci_get_vendor(dev) == 0x1106) 7861452Sdfr return ("VIA Generic host to PCI bridge"); 7961452Sdfr 8061452Sdfr return NULL; 8161452Sdfr} 8261452Sdfr 8361452Sdfrstatic int 8461452Sdfragp_via_probe(device_t dev) 8561452Sdfr{ 8661452Sdfr const char *desc; 8761452Sdfr 8861452Sdfr desc = agp_via_match(dev); 8961452Sdfr if (desc) { 9061452Sdfr device_verbose(dev); 9161452Sdfr device_set_desc(dev, desc); 9261452Sdfr return 0; 9361452Sdfr } 9461452Sdfr 9561452Sdfr return ENXIO; 9661452Sdfr} 9761452Sdfr 9861452Sdfrstatic int 9961452Sdfragp_via_attach(device_t dev) 10061452Sdfr{ 10161452Sdfr struct agp_via_softc *sc = device_get_softc(dev); 10261452Sdfr struct agp_gatt *gatt; 10361452Sdfr int error; 10461452Sdfr 10561452Sdfr error = agp_generic_attach(dev); 10661452Sdfr if (error) 10761452Sdfr return error; 10861452Sdfr 10961452Sdfr sc->initial_aperture = AGP_GET_APERTURE(dev); 11061452Sdfr 11161452Sdfr for (;;) { 11261452Sdfr gatt = agp_alloc_gatt(dev); 11361452Sdfr if (gatt) 11461452Sdfr break; 11561452Sdfr 11661452Sdfr /* 11761452Sdfr * Probably contigmalloc failure. Try reducing the 11861452Sdfr * aperture so that the gatt size reduces. 11961452Sdfr */ 12061452Sdfr if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 12161452Sdfr agp_generic_detach(dev); 12261452Sdfr return ENOMEM; 12361452Sdfr } 12461452Sdfr } 12561452Sdfr sc->gatt = gatt; 12661452Sdfr 12761452Sdfr /* Install the gatt. */ 12861452Sdfr pci_write_config(dev, AGP_VIA_ATTBASE, gatt->ag_physical | 3, 4); 12961452Sdfr 13061452Sdfr /* Enable the aperture. */ 13161452Sdfr pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4); 13261452Sdfr 13361452Sdfr return 0; 13461452Sdfr} 13561452Sdfr 13661452Sdfrstatic int 13761452Sdfragp_via_detach(device_t dev) 13861452Sdfr{ 13961452Sdfr struct agp_via_softc *sc = device_get_softc(dev); 14061452Sdfr int error; 14161452Sdfr 14261452Sdfr error = agp_generic_detach(dev); 14361452Sdfr if (error) 14461452Sdfr return error; 14561452Sdfr 14661452Sdfr pci_write_config(dev, AGP_VIA_GARTCTRL, 0, 4); 14761452Sdfr pci_write_config(dev, AGP_VIA_ATTBASE, 0, 4); 14861452Sdfr AGP_SET_APERTURE(dev, sc->initial_aperture); 14961452Sdfr agp_free_gatt(sc->gatt); 15061452Sdfr 15161452Sdfr return 0; 15261452Sdfr} 15361452Sdfr 15461452Sdfrstatic u_int32_t 15561452Sdfragp_via_get_aperture(device_t dev) 15661452Sdfr{ 15761452Sdfr u_int32_t apsize; 15861452Sdfr 15961452Sdfr apsize = pci_read_config(dev, AGP_VIA_APSIZE, 1) & 0x1f; 16061452Sdfr 16161452Sdfr /* 16261452Sdfr * The size is determined by the number of low bits of 16361452Sdfr * register APBASE which are forced to zero. The low 20 bits 16461452Sdfr * are always forced to zero and each zero bit in the apsize 16561452Sdfr * field just read forces the corresponding bit in the 27:20 16661452Sdfr * to be zero. We calculate the aperture size accordingly. 16761452Sdfr */ 16861452Sdfr return (((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1; 16961452Sdfr} 17061452Sdfr 17161452Sdfrstatic int 17261452Sdfragp_via_set_aperture(device_t dev, u_int32_t aperture) 17361452Sdfr{ 17461452Sdfr u_int32_t apsize; 17561452Sdfr 17661452Sdfr /* 17761452Sdfr * Reverse the magic from get_aperture. 17861452Sdfr */ 17961452Sdfr apsize = ((aperture - 1) >> 20) ^ 0xff; 18061452Sdfr 18161452Sdfr /* 18261452Sdfr * Double check for sanity. 18361452Sdfr */ 18461452Sdfr if ((((apsize ^ 0xff) << 20) | ((1 << 20) - 1)) + 1 != aperture) 18561452Sdfr return EINVAL; 18661452Sdfr 18761452Sdfr pci_write_config(dev, AGP_VIA_APSIZE, apsize, 1); 18861452Sdfr 18961452Sdfr return 0; 19061452Sdfr} 19161452Sdfr 19261452Sdfrstatic int 19361452Sdfragp_via_bind_page(device_t dev, int offset, vm_offset_t physical) 19461452Sdfr{ 19561452Sdfr struct agp_via_softc *sc = device_get_softc(dev); 19661452Sdfr 19761452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 19861452Sdfr return EINVAL; 19961452Sdfr 20061452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical; 20161452Sdfr return 0; 20261452Sdfr} 20361452Sdfr 20461452Sdfrstatic int 20561452Sdfragp_via_unbind_page(device_t dev, int offset) 20661452Sdfr{ 20761452Sdfr struct agp_via_softc *sc = device_get_softc(dev); 20861452Sdfr 20961452Sdfr if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 21061452Sdfr return EINVAL; 21161452Sdfr 21261452Sdfr sc->gatt->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 21361452Sdfr return 0; 21461452Sdfr} 21561452Sdfr 21661452Sdfrstatic void 21761452Sdfragp_via_flush_tlb(device_t dev) 21861452Sdfr{ 21961452Sdfr pci_write_config(dev, AGP_VIA_GARTCTRL, 0x8f, 4); 22061452Sdfr pci_write_config(dev, AGP_VIA_GARTCTRL, 0x0f, 4); 22161452Sdfr} 22261452Sdfr 22361452Sdfrstatic device_method_t agp_via_methods[] = { 22461452Sdfr /* Device interface */ 22561452Sdfr DEVMETHOD(device_probe, agp_via_probe), 22661452Sdfr DEVMETHOD(device_attach, agp_via_attach), 22761452Sdfr DEVMETHOD(device_detach, agp_via_detach), 22861452Sdfr DEVMETHOD(device_shutdown, bus_generic_shutdown), 22961452Sdfr DEVMETHOD(device_suspend, bus_generic_suspend), 23061452Sdfr DEVMETHOD(device_resume, bus_generic_resume), 23161452Sdfr 23261452Sdfr /* AGP interface */ 23361452Sdfr DEVMETHOD(agp_get_aperture, agp_via_get_aperture), 23461452Sdfr DEVMETHOD(agp_set_aperture, agp_via_set_aperture), 23561452Sdfr DEVMETHOD(agp_bind_page, agp_via_bind_page), 23661452Sdfr DEVMETHOD(agp_unbind_page, agp_via_unbind_page), 23761452Sdfr DEVMETHOD(agp_flush_tlb, agp_via_flush_tlb), 23861452Sdfr DEVMETHOD(agp_enable, agp_generic_enable), 23961452Sdfr DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 24061452Sdfr DEVMETHOD(agp_free_memory, agp_generic_free_memory), 24161452Sdfr DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 24261452Sdfr DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 24361452Sdfr 24461452Sdfr { 0, 0 } 24561452Sdfr}; 24661452Sdfr 24761452Sdfrstatic driver_t agp_via_driver = { 24861452Sdfr "agp", 24961452Sdfr agp_via_methods, 25061452Sdfr sizeof(struct agp_via_softc), 25161452Sdfr}; 25261452Sdfr 25361452Sdfrstatic devclass_t agp_devclass; 25461452Sdfr 25561452SdfrDRIVER_MODULE(agp_via, pci, agp_via_driver, agp_devclass, 0, 0); 256