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: releng/10.2/sys/dev/agp/agp_ati.c 275406 2014-12-02 13:46:13Z tijl $"); 31150236Sanholt 32150236Sanholt#include <sys/param.h> 33150236Sanholt#include <sys/systm.h> 34150236Sanholt#include <sys/malloc.h> 35150236Sanholt#include <sys/kernel.h> 36150236Sanholt#include <sys/module.h> 37150236Sanholt#include <sys/bus.h> 38150236Sanholt#include <sys/lock.h> 39150236Sanholt#include <sys/mutex.h> 40150236Sanholt#include <sys/proc.h> 41150236Sanholt 42173573Sjhb#include <dev/agp/agppriv.h> 43173573Sjhb#include <dev/agp/agpreg.h> 44150236Sanholt#include <dev/pci/pcivar.h> 45150236Sanholt#include <dev/pci/pcireg.h> 46150236Sanholt 47150236Sanholt#include <vm/vm.h> 48275406Stijl#include <vm/vm_extern.h> 49275406Stijl#include <vm/vm_kern.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"); 104244926Santoine } 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; 134275406Stijl sc->ag_virtual = (void *)kmem_alloc_attr(kernel_arena, 135275406Stijl entries * sizeof(u_int32_t), M_NOWAIT | M_ZERO, 0, ~0, 136275406Stijl VM_MEMATTR_WRITE_COMBINING); 137150236Sanholt if (sc->ag_virtual == NULL) { 138150236Sanholt if (bootverbose) 139275406Stijl device_printf(dev, "GATT allocation failed\n"); 140150236Sanholt return ENOMEM; 141150236Sanholt } 142150236Sanholt 143150236Sanholt /* Alloc the page directory -- pointers to each page of the GATT */ 144275406Stijl sc->ag_vdir = (void *)kmem_alloc_attr(kernel_arena, AGP_PAGE_SIZE, 145275406Stijl M_NOWAIT | M_ZERO, 0, ~0, VM_MEMATTR_WRITE_COMBINING); 146150236Sanholt if (sc->ag_vdir == NULL) { 147150236Sanholt if (bootverbose) 148150236Sanholt device_printf(dev, "pagedir allocation failed\n"); 149275406Stijl kmem_free(kernel_arena, (vm_offset_t)sc->ag_virtual, 150275406Stijl entries * sizeof(u_int32_t)); 151150236Sanholt return ENOMEM; 152150236Sanholt } 153150236Sanholt sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir); 154150236Sanholt 155150236Sanholt apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22; 156150236Sanholt /* Fill in the pagedir's pointers to GATT pages */ 157150236Sanholt for (i = 0; i < sc->ag_entries / 1024; i++) { 158150236Sanholt vm_offset_t va; 159150236Sanholt vm_offset_t pa; 160150236Sanholt 161150236Sanholt va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE; 162150236Sanholt pa = vtophys(va); 163150236Sanholt sc->ag_vdir[apbase_offset + i] = pa | 1; 164150236Sanholt } 165150236Sanholt 166150236Sanholt return 0; 167150236Sanholt} 168150236Sanholt 169150236Sanholt 170150236Sanholtstatic int 171150236Sanholtagp_ati_attach(device_t dev) 172150236Sanholt{ 173150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 174150236Sanholt int error, rid; 175150236Sanholt u_int32_t temp; 176150236Sanholt u_int32_t apsize_reg, agpmode_reg; 177150236Sanholt 178150236Sanholt error = agp_generic_attach(dev); 179150236Sanholt if (error) 180150236Sanholt return error; 181150236Sanholt 182150236Sanholt switch (pci_get_devid(dev)) { 183150236Sanholt case 0xcab01002: /* ATI RS100 AGP bridge */ 184161788Sanholt case 0xcab21002: /* ATI RS200 AGP bridge */ 185161788Sanholt case 0xcbb21002: /* ATI RS200M AGP bridge */ 186150236Sanholt case 0xcab31002: /* ATI RS250 AGP bridge */ 187150236Sanholt sc->is_rs300 = 0; 188150236Sanholt apsize_reg = ATI_RS100_APSIZE; 189150236Sanholt agpmode_reg = ATI_RS100_IG_AGPMODE; 190150236Sanholt break; 191150236Sanholt case 0x58301002: /* ATI RS300_100 AGP bridge */ 192150236Sanholt case 0x58311002: /* ATI RS300_133 AGP bridge */ 193150236Sanholt case 0x58321002: /* ATI RS300_166 AGP bridge */ 194150236Sanholt case 0x58331002: /* ATI RS300_200 AGP bridge */ 195150236Sanholt sc->is_rs300 = 1; 196150236Sanholt apsize_reg = ATI_RS300_APSIZE; 197150236Sanholt agpmode_reg = ATI_RS300_IG_AGPMODE; 198150236Sanholt break; 199150236Sanholt default: 200150236Sanholt /* Unknown chipset */ 201150236Sanholt return EINVAL; 202244926Santoine } 203150236Sanholt 204150236Sanholt rid = ATI_GART_MMADDR; 205150236Sanholt sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 206150236Sanholt if (!sc->regs) { 207150236Sanholt agp_generic_detach(dev); 208150236Sanholt return ENOMEM; 209150236Sanholt } 210150236Sanholt 211150236Sanholt sc->bst = rman_get_bustag(sc->regs); 212150236Sanholt sc->bsh = rman_get_bushandle(sc->regs); 213150236Sanholt 214150236Sanholt sc->initial_aperture = AGP_GET_APERTURE(dev); 215150236Sanholt 216150236Sanholt for (;;) { 217150236Sanholt if (agp_ati_alloc_gatt(dev) == 0) 218150236Sanholt break; 219150236Sanholt 220150236Sanholt /* 221150236Sanholt * Probably contigmalloc failure. Try reducing the 222150236Sanholt * aperture so that the gatt size reduces. 223150236Sanholt */ 224150236Sanholt if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) 225150236Sanholt return ENOMEM; 226150236Sanholt } 227150236Sanholt 228150236Sanholt temp = pci_read_config(dev, apsize_reg, 4); 229150236Sanholt pci_write_config(dev, apsize_reg, temp | 1, 4); 230150236Sanholt 231150236Sanholt pci_write_config(dev, agpmode_reg, 0x20000, 4); 232150236Sanholt 233150236Sanholt WRITE4(ATI_GART_FEATURE_ID, 0x00060000); 234150236Sanholt 235150236Sanholt temp = pci_read_config(dev, 4, 4); /* XXX: Magic reg# */ 236150236Sanholt pci_write_config(dev, 4, temp | (1 << 14), 4); 237150236Sanholt 238150236Sanholt WRITE4(ATI_GART_BASE, sc->ag_pdir); 239150236Sanholt 240150236Sanholt AGP_FLUSH_TLB(dev); 241150236Sanholt 242150236Sanholt return 0; 243150236Sanholt} 244150236Sanholt 245150236Sanholtstatic int 246150236Sanholtagp_ati_detach(device_t dev) 247150236Sanholt{ 248150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 249150236Sanholt u_int32_t apsize_reg, temp; 250150236Sanholt 251173203Sjhb agp_free_cdev(dev); 252173203Sjhb 253150236Sanholt if (sc->is_rs300) 254150236Sanholt apsize_reg = ATI_RS300_APSIZE; 255150236Sanholt else 256150236Sanholt apsize_reg = ATI_RS100_APSIZE; 257150236Sanholt 258150236Sanholt /* Clear the GATT base */ 259150236Sanholt WRITE4(ATI_GART_BASE, 0); 260150236Sanholt 261150236Sanholt /* Put the aperture back the way it started. */ 262150236Sanholt AGP_SET_APERTURE(dev, sc->initial_aperture); 263150236Sanholt 264150236Sanholt temp = pci_read_config(dev, apsize_reg, 4); 265150236Sanholt pci_write_config(dev, apsize_reg, temp & ~1, 4); 266150236Sanholt 267275406Stijl kmem_free(kernel_arena, (vm_offset_t)sc->ag_vdir, AGP_PAGE_SIZE); 268275406Stijl kmem_free(kernel_arena, (vm_offset_t)sc->ag_virtual, 269275406Stijl sc->ag_entries * sizeof(u_int32_t)); 270150236Sanholt 271150236Sanholt bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs); 272173203Sjhb agp_free_res(dev); 273150236Sanholt 274150236Sanholt return 0; 275150236Sanholt} 276150236Sanholt 277150236Sanholtstatic u_int32_t 278150236Sanholtagp_ati_get_aperture(device_t dev) 279150236Sanholt{ 280150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 281150236Sanholt int size_value; 282150236Sanholt 283150236Sanholt if (sc->is_rs300) 284150236Sanholt size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4); 285150236Sanholt else 286150236Sanholt size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4); 287150236Sanholt 288150236Sanholt size_value = (size_value & 0x0000000e) >> 1; 289150236Sanholt size_value = (32 * 1024 * 1024) << size_value; 290150236Sanholt 291150236Sanholt return size_value; 292150236Sanholt} 293150236Sanholt 294150236Sanholtstatic int 295150236Sanholtagp_ati_set_aperture(device_t dev, u_int32_t aperture) 296150236Sanholt{ 297150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 298150236Sanholt int size_value; 299150236Sanholt u_int32_t apsize_reg; 300150236Sanholt 301150236Sanholt if (sc->is_rs300) 302150236Sanholt apsize_reg = ATI_RS300_APSIZE; 303150236Sanholt else 304150236Sanholt apsize_reg = ATI_RS100_APSIZE; 305150236Sanholt 306150236Sanholt size_value = pci_read_config(dev, apsize_reg, 4); 307150236Sanholt 308150236Sanholt size_value &= ~0x0000000e; 309150236Sanholt size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1; 310150236Sanholt 311150236Sanholt pci_write_config(dev, apsize_reg, size_value, 4); 312150236Sanholt 313150236Sanholt return 0; 314150236Sanholt} 315150236Sanholt 316150236Sanholtstatic int 317194017Savgagp_ati_bind_page(device_t dev, vm_offset_t offset, vm_offset_t physical) 318150236Sanholt{ 319150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 320150236Sanholt 321194017Savg if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 322150236Sanholt return EINVAL; 323150236Sanholt 324150236Sanholt sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1; 325150236Sanholt 326150236Sanholt return 0; 327150236Sanholt} 328150236Sanholt 329150236Sanholtstatic int 330194017Savgagp_ati_unbind_page(device_t dev, vm_offset_t offset) 331150236Sanholt{ 332150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 333150236Sanholt 334194017Savg if (offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 335150236Sanholt return EINVAL; 336150236Sanholt 337150236Sanholt sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 338150236Sanholt return 0; 339150236Sanholt} 340150236Sanholt 341150236Sanholtstatic void 342150236Sanholtagp_ati_flush_tlb(device_t dev) 343150236Sanholt{ 344150236Sanholt struct agp_ati_softc *sc = device_get_softc(dev); 345150236Sanholt 346150236Sanholt /* Set the cache invalidate bit and wait for the chipset to clear */ 347150236Sanholt WRITE4(ATI_GART_CACHE_CNTRL, 1); 348150236Sanholt (void)READ4(ATI_GART_CACHE_CNTRL); 349150236Sanholt} 350150236Sanholt 351150236Sanholtstatic device_method_t agp_ati_methods[] = { 352150236Sanholt /* Device interface */ 353150236Sanholt DEVMETHOD(device_probe, agp_ati_probe), 354150236Sanholt DEVMETHOD(device_attach, agp_ati_attach), 355150236Sanholt DEVMETHOD(device_detach, agp_ati_detach), 356150236Sanholt DEVMETHOD(device_shutdown, bus_generic_shutdown), 357150236Sanholt DEVMETHOD(device_suspend, bus_generic_suspend), 358150236Sanholt DEVMETHOD(device_resume, bus_generic_resume), 359150236Sanholt 360150236Sanholt /* AGP interface */ 361150236Sanholt DEVMETHOD(agp_get_aperture, agp_ati_get_aperture), 362150236Sanholt DEVMETHOD(agp_set_aperture, agp_ati_set_aperture), 363150236Sanholt DEVMETHOD(agp_bind_page, agp_ati_bind_page), 364150236Sanholt DEVMETHOD(agp_unbind_page, agp_ati_unbind_page), 365150236Sanholt DEVMETHOD(agp_flush_tlb, agp_ati_flush_tlb), 366150236Sanholt DEVMETHOD(agp_enable, agp_generic_enable), 367150236Sanholt DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 368150236Sanholt DEVMETHOD(agp_free_memory, agp_generic_free_memory), 369150236Sanholt DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 370150236Sanholt DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 371150236Sanholt 372150236Sanholt { 0, 0 } 373150236Sanholt}; 374150236Sanholt 375150236Sanholtstatic driver_t agp_ati_driver = { 376150236Sanholt "agp", 377150236Sanholt agp_ati_methods, 378150236Sanholt sizeof(struct agp_ati_softc), 379150236Sanholt}; 380150236Sanholt 381150236Sanholtstatic devclass_t agp_devclass; 382150236Sanholt 383153572SjhbDRIVER_MODULE(agp_ati, hostb, agp_ati_driver, agp_devclass, 0, 0); 384150236SanholtMODULE_DEPEND(agp_ati, agp, 1, 1, 1); 385150236SanholtMODULE_DEPEND(agp_ati, pci, 1, 1, 1); 386