1150236Sanholt/*- 2150236Sanholt * Copyright (c) 2005 Eric Anholt 3150236Sanholt * All rights reserved. 4150236Sanholt * 5150236Sanholt * Redistribution and use in source and binary forms, with or without 6150236Sanholt * modification, are permitted provided that the following conditions 7150236Sanholt * are met: 8150236Sanholt * 1. Redistributions of source code must retain the above copyright 9150236Sanholt * notice, this list of conditions and the following disclaimer. 10150236Sanholt * 2. Redistributions in binary form must reproduce the above copyright 11150236Sanholt * notice, this list of conditions and the following disclaimer in the 12150236Sanholt * documentation and/or other materials provided with the distribution. 13150236Sanholt * 14150236Sanholt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15150236Sanholt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16150236Sanholt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17150236Sanholt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18150236Sanholt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19150236Sanholt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20150236Sanholt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21150236Sanholt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22150236Sanholt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23150236Sanholt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24150236Sanholt * SUCH DAMAGE. 25150236Sanholt * 26150236Sanholt * Based on reading the Linux 2.6.8.1 driver by Dave Jones. 27150236Sanholt */ 28150236Sanholt 29150236Sanholt#include <sys/cdefs.h> 30150236Sanholt__FBSDID("$FreeBSD$"); 31150236Sanholt 32150236Sanholt#include "opt_bus.h" 33150236Sanholt 34150236Sanholt#include <sys/param.h> 35150236Sanholt#include <sys/systm.h> 36150236Sanholt#include <sys/malloc.h> 37150236Sanholt#include <sys/kernel.h> 38150236Sanholt#include <sys/module.h> 39150236Sanholt#include <sys/bus.h> 40150236Sanholt#include <sys/lock.h> 41150236Sanholt#include <sys/mutex.h> 42150236Sanholt#include <sys/proc.h> 43150236Sanholt 44173573Sjhb#include <dev/agp/agppriv.h> 45173573Sjhb#include <dev/agp/agpreg.h> 46150236Sanholt#include <dev/pci/pcivar.h> 47150236Sanholt#include <dev/pci/pcireg.h> 48150236Sanholt 49150236Sanholt#include <vm/vm.h> 50150236Sanholt#include <vm/vm_object.h> 51150236Sanholt#include <vm/pmap.h> 52150236Sanholt#include <machine/bus.h> 53150236Sanholt#include <machine/resource.h> 54150236Sanholt#include <sys/rman.h> 55150236Sanholt 56150236SanholtMALLOC_DECLARE(M_AGP); 57150236Sanholt 58150236Sanholt#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off) 59150236Sanholt#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v) 60150236Sanholt 61150236Sanholtstruct agp_ati_softc { 62150236Sanholt struct agp_softc agp; 63150236Sanholt struct resource *regs; /* memory mapped control registers */ 64150236Sanholt bus_space_tag_t bst; /* bus_space tag */ 65150236Sanholt bus_space_handle_t bsh; /* bus_space handle */ 66150236Sanholt u_int32_t initial_aperture; /* aperture size at startup */ 67150236Sanholt char is_rs300; 68150236Sanholt 69150236Sanholt /* The GATT */ 70150236Sanholt u_int32_t ag_entries; 71150236Sanholt u_int32_t *ag_virtual; /* virtual address of gatt */ 72150236Sanholt u_int32_t *ag_vdir; /* virtual address of page dir */ 73150236Sanholt vm_offset_t ag_pdir; /* physical address of page dir */ 74150236Sanholt}; 75150236Sanholt 76150236Sanholt 77150236Sanholtstatic const char* 78150236Sanholtagp_ati_match(device_t dev) 79150236Sanholt{ 80150236Sanholt if (pci_get_class(dev) != PCIC_BRIDGE || 81150236Sanholt pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 82150236Sanholt return NULL; 83150236Sanholt 84150236Sanholt if (agp_find_caps(dev) == 0) 85150236Sanholt return NULL; 86150236Sanholt 87150236Sanholt switch (pci_get_devid(dev)) { 88150236Sanholt case 0xcab01002: 89150236Sanholt return ("ATI RS100 AGP bridge"); 90150236Sanholt case 0xcab21002: 91150236Sanholt return ("ATI RS200 AGP bridge"); 92161788Sanholt case 0xcbb21002: 93161788Sanholt return ("ATI RS200M AGP bridge"); 94150236Sanholt case 0xcab31002: 95150236Sanholt return ("ATI RS250 AGP bridge"); 96150236Sanholt case 0x58301002: 97150236Sanholt return ("ATI RS300_100 AGP bridge"); 98150236Sanholt case 0x58311002: 99150236Sanholt return ("ATI RS300_133 AGP bridge"); 100150236Sanholt case 0x58321002: 101150236Sanholt return ("ATI RS300_166 AGP bridge"); 102150236Sanholt case 0x58331002: 103150236Sanholt return ("ATI RS300_200 AGP bridge"); 104150236Sanholt }; 105150236Sanholt 106150236Sanholt return NULL; 107150236Sanholt} 108150236Sanholt 109150236Sanholtstatic int 110150236Sanholtagp_ati_probe(device_t dev) 111150236Sanholt{ 112150236Sanholt const char *desc; 113150236Sanholt 114150236Sanholt desc = agp_ati_match(dev); 115150236Sanholt if (desc) { 116150236Sanholt device_set_desc(dev, desc); 117150236Sanholt return 0; 118150236Sanholt } 119150236Sanholt 120150236Sanholt return ENXIO; 121150236Sanholt} 122150236Sanholt 123150236Sanholtstatic int 124150236Sanholtagp_ati_alloc_gatt(device_t dev) 125150236Sanholt{ 126150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 127150236Sanholt u_int32_t apsize = AGP_GET_APERTURE(dev); 128150236Sanholt u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 129150236Sanholt u_int32_t apbase_offset; 130150236Sanholt int i; 131150236Sanholt 132150236Sanholt /* Alloc the GATT -- pointers to pages of AGP memory */ 133150236Sanholt sc->ag_entries = entries; 134150236Sanholt sc->ag_virtual = malloc(entries * sizeof(u_int32_t), M_AGP, 135150236Sanholt M_NOWAIT | M_ZERO); 136150236Sanholt if (sc->ag_virtual == NULL) { 137150236Sanholt if (bootverbose) 138150236Sanholt device_printf(dev, "aperture allocation failed\n"); 139150236Sanholt return ENOMEM; 140150236Sanholt } 141150236Sanholt 142150236Sanholt /* Alloc the page directory -- pointers to each page of the GATT */ 143150236Sanholt sc->ag_vdir = malloc(AGP_PAGE_SIZE, M_AGP, M_NOWAIT | M_ZERO); 144150236Sanholt if (sc->ag_vdir == NULL) { 145150236Sanholt if (bootverbose) 146150236Sanholt device_printf(dev, "pagedir allocation failed\n"); 147150236Sanholt free(sc->ag_virtual, M_AGP); 148150236Sanholt return ENOMEM; 149150236Sanholt } 150150236Sanholt sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir); 151150236Sanholt 152150236Sanholt apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22; 153150236Sanholt /* Fill in the pagedir's pointers to GATT pages */ 154150236Sanholt for (i = 0; i < sc->ag_entries / 1024; i++) { 155150236Sanholt vm_offset_t va; 156150236Sanholt vm_offset_t pa; 157150236Sanholt 158150236Sanholt va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE; 159150236Sanholt pa = vtophys(va); 160150236Sanholt sc->ag_vdir[apbase_offset + i] = pa | 1; 161150236Sanholt } 162150236Sanholt 163150236Sanholt /* 164150236Sanholt * Make sure the chipset can see everything. 165150236Sanholt */ 166150236Sanholt agp_flush_cache(); 167150236Sanholt 168150236Sanholt return 0; 169150236Sanholt} 170150236Sanholt 171150236Sanholt 172150236Sanholtstatic int 173150236Sanholtagp_ati_attach(device_t dev) 174150236Sanholt{ 175150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 176150236Sanholt int error, rid; 177150236Sanholt u_int32_t temp; 178150236Sanholt u_int32_t apsize_reg, agpmode_reg; 179150236Sanholt 180150236Sanholt error = agp_generic_attach(dev); 181150236Sanholt if (error) 182150236Sanholt return error; 183150236Sanholt 184150236Sanholt switch (pci_get_devid(dev)) { 185150236Sanholt case 0xcab01002: /* ATI RS100 AGP bridge */ 186161788Sanholt case 0xcab21002: /* ATI RS200 AGP bridge */ 187161788Sanholt case 0xcbb21002: /* ATI RS200M AGP bridge */ 188150236Sanholt case 0xcab31002: /* ATI RS250 AGP bridge */ 189150236Sanholt sc->is_rs300 = 0; 190150236Sanholt apsize_reg = ATI_RS100_APSIZE; 191150236Sanholt agpmode_reg = ATI_RS100_IG_AGPMODE; 192150236Sanholt break; 193150236Sanholt case 0x58301002: /* ATI RS300_100 AGP bridge */ 194150236Sanholt case 0x58311002: /* ATI RS300_133 AGP bridge */ 195150236Sanholt case 0x58321002: /* ATI RS300_166 AGP bridge */ 196150236Sanholt case 0x58331002: /* ATI RS300_200 AGP bridge */ 197150236Sanholt sc->is_rs300 = 1; 198150236Sanholt apsize_reg = ATI_RS300_APSIZE; 199150236Sanholt agpmode_reg = ATI_RS300_IG_AGPMODE; 200150236Sanholt break; 201150236Sanholt default: 202150236Sanholt /* Unknown chipset */ 203150236Sanholt return EINVAL; 204150236Sanholt }; 205150236Sanholt 206150236Sanholt rid = ATI_GART_MMADDR; 207150236Sanholt sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 208150236Sanholt if (!sc->regs) { 209150236Sanholt agp_generic_detach(dev); 210150236Sanholt return ENOMEM; 211150236Sanholt } 212150236Sanholt 213150236Sanholt sc->bst = rman_get_bustag(sc->regs); 214150236Sanholt sc->bsh = rman_get_bushandle(sc->regs); 215150236Sanholt 216150236Sanholt sc->initial_aperture = AGP_GET_APERTURE(dev); 217150236Sanholt 218150236Sanholt for (;;) { 219150236Sanholt if (agp_ati_alloc_gatt(dev) == 0) 220150236Sanholt break; 221150236Sanholt 222150236Sanholt /* 223150236Sanholt * Probably contigmalloc failure. Try reducing the 224150236Sanholt * aperture so that the gatt size reduces. 225150236Sanholt */ 226150236Sanholt if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) 227150236Sanholt return ENOMEM; 228150236Sanholt } 229150236Sanholt 230150236Sanholt temp = pci_read_config(dev, apsize_reg, 4); 231150236Sanholt pci_write_config(dev, apsize_reg, temp | 1, 4); 232150236Sanholt 233150236Sanholt pci_write_config(dev, agpmode_reg, 0x20000, 4); 234150236Sanholt 235150236Sanholt WRITE4(ATI_GART_FEATURE_ID, 0x00060000); 236150236Sanholt 237150236Sanholt temp = pci_read_config(dev, 4, 4); /* XXX: Magic reg# */ 238150236Sanholt pci_write_config(dev, 4, temp | (1 << 14), 4); 239150236Sanholt 240150236Sanholt WRITE4(ATI_GART_BASE, sc->ag_pdir); 241150236Sanholt 242150236Sanholt AGP_FLUSH_TLB(dev); 243150236Sanholt 244150236Sanholt return 0; 245150236Sanholt} 246150236Sanholt 247150236Sanholtstatic int 248150236Sanholtagp_ati_detach(device_t dev) 249150236Sanholt{ 250150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 251150236Sanholt u_int32_t apsize_reg, temp; 252150236Sanholt 253173203Sjhb agp_free_cdev(dev); 254173203Sjhb 255150236Sanholt if (sc->is_rs300) 256150236Sanholt apsize_reg = ATI_RS300_APSIZE; 257150236Sanholt else 258150236Sanholt apsize_reg = ATI_RS100_APSIZE; 259150236Sanholt 260150236Sanholt /* Clear the GATT base */ 261150236Sanholt WRITE4(ATI_GART_BASE, 0); 262150236Sanholt 263150236Sanholt /* Put the aperture back the way it started. */ 264150236Sanholt AGP_SET_APERTURE(dev, sc->initial_aperture); 265150236Sanholt 266150236Sanholt temp = pci_read_config(dev, apsize_reg, 4); 267150236Sanholt pci_write_config(dev, apsize_reg, temp & ~1, 4); 268150236Sanholt 269150236Sanholt free(sc->ag_vdir, M_AGP); 270150236Sanholt free(sc->ag_virtual, M_AGP); 271150236Sanholt 272150236Sanholt bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs); 273173203Sjhb agp_free_res(dev); 274150236Sanholt 275150236Sanholt return 0; 276150236Sanholt} 277150236Sanholt 278150236Sanholtstatic u_int32_t 279150236Sanholtagp_ati_get_aperture(device_t dev) 280150236Sanholt{ 281150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 282150236Sanholt int size_value; 283150236Sanholt 284150236Sanholt if (sc->is_rs300) 285150236Sanholt size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4); 286150236Sanholt else 287150236Sanholt size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4); 288150236Sanholt 289150236Sanholt size_value = (size_value & 0x0000000e) >> 1; 290150236Sanholt size_value = (32 * 1024 * 1024) << size_value; 291150236Sanholt 292150236Sanholt return size_value; 293150236Sanholt} 294150236Sanholt 295150236Sanholtstatic int 296150236Sanholtagp_ati_set_aperture(device_t dev, u_int32_t aperture) 297150236Sanholt{ 298150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 299150236Sanholt int size_value; 300150236Sanholt u_int32_t apsize_reg; 301150236Sanholt 302150236Sanholt if (sc->is_rs300) 303150236Sanholt apsize_reg = ATI_RS300_APSIZE; 304150236Sanholt else 305150236Sanholt apsize_reg = ATI_RS100_APSIZE; 306150236Sanholt 307150236Sanholt size_value = pci_read_config(dev, apsize_reg, 4); 308150236Sanholt 309150236Sanholt size_value &= ~0x0000000e; 310150236Sanholt size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1; 311150236Sanholt 312150236Sanholt pci_write_config(dev, apsize_reg, size_value, 4); 313150236Sanholt 314150236Sanholt return 0; 315150236Sanholt} 316150236Sanholt 317150236Sanholtstatic int 318194017Savgagp_ati_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical) 319150236Sanholt{ 320150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 321150236Sanholt 322194017Savg if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 323150236Sanholt return EINVAL; 324150236Sanholt 325150236Sanholt sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1; 326150236Sanholt 327150236Sanholt return 0; 328150236Sanholt} 329150236Sanholt 330150236Sanholtstatic int 331194017Savgagp_ati_unbind_page(device_t dev, vm_offset_t offset) 332150236Sanholt{ 333150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 334150236Sanholt 335194017Savg if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 336150236Sanholt return EINVAL; 337150236Sanholt 338150236Sanholt sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 339150236Sanholt return 0; 340150236Sanholt} 341150236Sanholt 342150236Sanholtstatic void 343150236Sanholtagp_ati_flush_tlb(device_t dev) 344150236Sanholt{ 345150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 346150236Sanholt 347150236Sanholt /* Set the cache invalidate bit and wait for the chipset to clear */ 348150236Sanholt WRITE4(ATI_GART_CACHE_CNTRL, 1); 349150236Sanholt (void)READ4(ATI_GART_CACHE_CNTRL); 350150236Sanholt} 351150236Sanholt 352150236Sanholtstatic device_method_t agp_ati_methods[] = { 353150236Sanholt /* Device interface */ 354150236Sanholt DEVMETHOD(device_probe, agp_ati_probe), 355150236Sanholt DEVMETHOD(device_attach, agp_ati_attach), 356150236Sanholt DEVMETHOD(device_detach, agp_ati_detach), 357150236Sanholt DEVMETHOD(device_shutdown, bus_generic_shutdown), 358150236Sanholt DEVMETHOD(device_suspend, bus_generic_suspend), 359150236Sanholt DEVMETHOD(device_resume, bus_generic_resume), 360150236Sanholt 361150236Sanholt /* AGP interface */ 362150236Sanholt DEVMETHOD(agp_get_aperture, agp_ati_get_aperture), 363150236Sanholt DEVMETHOD(agp_set_aperture, agp_ati_set_aperture), 364150236Sanholt DEVMETHOD(agp_bind_page, agp_ati_bind_page), 365150236Sanholt DEVMETHOD(agp_unbind_page, agp_ati_unbind_page), 366150236Sanholt DEVMETHOD(agp_flush_tlb, agp_ati_flush_tlb), 367150236Sanholt DEVMETHOD(agp_enable, agp_generic_enable), 368150236Sanholt DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 369150236Sanholt DEVMETHOD(agp_free_memory, agp_generic_free_memory), 370150236Sanholt DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 371150236Sanholt DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 372150236Sanholt 373150236Sanholt { 0, 0 } 374150236Sanholt}; 375150236Sanholt 376150236Sanholtstatic driver_t agp_ati_driver = { 377150236Sanholt "agp", 378150236Sanholt agp_ati_methods, 379150236Sanholt sizeof(struct agp_ati_softc), 380150236Sanholt}; 381150236Sanholt 382150236Sanholtstatic devclass_t agp_devclass; 383150236Sanholt 384153572SjhbDRIVER_MODULE(agp_ati, hostb, agp_ati_driver, agp_devclass, 0, 0); 385150236SanholtMODULE_DEPEND(agp_ati, agp, 1, 1, 1); 386150236SanholtMODULE_DEPEND(agp_ati, pci, 1, 1, 1); 387