agp_ati.c revision 161788
1181641Skmacy/*- 2181641Skmacy * Copyright (c) 2005 Eric Anholt 3181641Skmacy * All rights reserved. 4181641Skmacy * 5181641Skmacy * Redistribution and use in source and binary forms, with or without 6181641Skmacy * modification, are permitted provided that the following conditions 7181641Skmacy * are met: 8181641Skmacy * 1. Redistributions of source code must retain the above copyright 9181641Skmacy * notice, this list of conditions and the following disclaimer. 10181641Skmacy * 2. Redistributions in binary form must reproduce the above copyright 11181641Skmacy * notice, this list of conditions and the following disclaimer in the 12181641Skmacy * documentation and/or other materials provided with the distribution. 13181641Skmacy * 14181641Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15181641Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16181641Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17181641Skmacy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18181641Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19181641Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20181641Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21181641Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22181641Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23181641Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24181641Skmacy * SUCH DAMAGE. 25181641Skmacy * 26181641Skmacy * Based on reading the Linux 2.6.8.1 driver by Dave Jones. 27181641Skmacy */ 28181641Skmacy 29181641Skmacy#include <sys/cdefs.h> 30181641Skmacy__FBSDID("$FreeBSD: head/sys/dev/agp/agp_ati.c 161788 2006-09-01 02:22:17Z anholt $"); 31181641Skmacy 32181641Skmacy#include "opt_bus.h" 33181641Skmacy 34181641Skmacy#include <sys/param.h> 35181641Skmacy#include <sys/systm.h> 36181641Skmacy#include <sys/malloc.h> 37181641Skmacy#include <sys/kernel.h> 38181641Skmacy#include <sys/module.h> 39181641Skmacy#include <sys/bus.h> 40181641Skmacy#include <sys/lock.h> 41181641Skmacy#include <sys/mutex.h> 42181641Skmacy#include <sys/proc.h> 43181641Skmacy 44181641Skmacy#include <dev/pci/pcivar.h> 45181641Skmacy#include <dev/pci/pcireg.h> 46181641Skmacy#include <pci/agppriv.h> 47181641Skmacy#include <pci/agpreg.h> 48181641Skmacy 49181641Skmacy#include <vm/vm.h> 50181641Skmacy#include <vm/vm_object.h> 51181641Skmacy#include <vm/pmap.h> 52181641Skmacy#include <machine/bus.h> 53181641Skmacy#include <machine/resource.h> 54181641Skmacy#include <sys/rman.h> 55181641Skmacy 56181641SkmacyMALLOC_DECLARE(M_AGP); 57181641Skmacy 58181641Skmacy#define READ4(off) bus_space_read_4(sc->bst, sc->bsh, off) 59181641Skmacy#define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v) 60181641Skmacy 61181641Skmacystruct agp_ati_softc { 62181641Skmacy struct agp_softc agp; 63181641Skmacy struct resource *regs; /* memory mapped control registers */ 64181641Skmacy bus_space_tag_t bst; /* bus_space tag */ 65181641Skmacy bus_space_handle_t bsh; /* bus_space handle */ 66181641Skmacy u_int32_t initial_aperture; /* aperture size at startup */ 67181641Skmacy char is_rs300; 68181641Skmacy 69181641Skmacy /* The GATT */ 70181641Skmacy u_int32_t ag_entries; 71181641Skmacy u_int32_t *ag_virtual; /* virtual address of gatt */ 72181641Skmacy u_int32_t *ag_vdir; /* virtual address of page dir */ 73181641Skmacy vm_offset_t ag_pdir; /* physical address of page dir */ 74181641Skmacy}; 75181641Skmacy 76181641Skmacy 77181641Skmacystatic const char* 78181641Skmacyagp_ati_match(device_t dev) 79181641Skmacy{ 80181641Skmacy if (pci_get_class(dev) != PCIC_BRIDGE || 81181641Skmacy pci_get_subclass(dev) != PCIS_BRIDGE_HOST) 82181641Skmacy return NULL; 83181641Skmacy 84181641Skmacy if (agp_find_caps(dev) == 0) 85181641Skmacy return NULL; 86181641Skmacy 87181641Skmacy switch (pci_get_devid(dev)) { 88181641Skmacy case 0xcab01002: 89181641Skmacy return ("ATI RS100 AGP bridge"); 90181641Skmacy case 0xcab21002: 91181641Skmacy return ("ATI RS200 AGP bridge"); 92181641Skmacy case 0xcbb21002: 93181641Skmacy return ("ATI RS200M AGP bridge"); 94181641Skmacy case 0xcab31002: 95181641Skmacy return ("ATI RS250 AGP bridge"); 96181641Skmacy case 0x58301002: 97181641Skmacy return ("ATI RS300_100 AGP bridge"); 98181641Skmacy case 0x58311002: 99181641Skmacy return ("ATI RS300_133 AGP bridge"); 100181641Skmacy case 0x58321002: 101181641Skmacy return ("ATI RS300_166 AGP bridge"); 102181641Skmacy case 0x58331002: 103181641Skmacy return ("ATI RS300_200 AGP bridge"); 104181641Skmacy }; 105181641Skmacy 106181641Skmacy return NULL; 107181641Skmacy} 108181641Skmacy 109181641Skmacystatic int 110181641Skmacyagp_ati_probe(device_t dev) 111181641Skmacy{ 112181641Skmacy const char *desc; 113181641Skmacy 114241498Salc desc = agp_ati_match(dev); 115195949Skib if (desc) { 116181641Skmacy device_set_desc(dev, desc); 117181641Skmacy return 0; 118181641Skmacy } 119181641Skmacy 120181641Skmacy return ENXIO; 121181641Skmacy} 122228923Salc 123228923Salcstatic int 124181641Skmacyagp_ati_alloc_gatt(device_t dev) 125181641Skmacy{ 126181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 127181641Skmacy u_int32_t apsize = AGP_GET_APERTURE(dev); 128181641Skmacy u_int32_t entries = apsize >> AGP_PAGE_SHIFT; 129181641Skmacy u_int32_t apbase_offset; 130181641Skmacy int i; 131181641Skmacy 132181641Skmacy /* Alloc the GATT -- pointers to pages of AGP memory */ 133181641Skmacy sc->ag_entries = entries; 134181641Skmacy sc->ag_virtual = malloc(entries * sizeof(u_int32_t), M_AGP, 135181641Skmacy M_NOWAIT | M_ZERO); 136181641Skmacy if (sc->ag_virtual == NULL) { 137181641Skmacy if (bootverbose) 138181641Skmacy device_printf(dev, "aperture allocation failed\n"); 139181641Skmacy return ENOMEM; 140181641Skmacy } 141181641Skmacy 142181641Skmacy /* Alloc the page directory -- pointers to each page of the GATT */ 143181641Skmacy sc->ag_vdir = malloc(AGP_PAGE_SIZE, M_AGP, M_NOWAIT | M_ZERO); 144181641Skmacy if (sc->ag_vdir == NULL) { 145181641Skmacy if (bootverbose) 146181641Skmacy device_printf(dev, "pagedir allocation failed\n"); 147181641Skmacy free(sc->ag_virtual, M_AGP); 148181641Skmacy return ENOMEM; 149181641Skmacy } 150181641Skmacy sc->ag_pdir = vtophys((vm_offset_t)sc->ag_vdir); 151186557Skmacy 152181641Skmacy apbase_offset = pci_read_config(dev, AGP_APBASE, 4) >> 22; 153181641Skmacy /* Fill in the pagedir's pointers to GATT pages */ 154181641Skmacy for (i = 0; i < sc->ag_entries / 1024; i++) { 155181641Skmacy vm_offset_t va; 156181641Skmacy vm_offset_t pa; 157181641Skmacy 158181641Skmacy va = ((vm_offset_t)sc->ag_virtual) + i * AGP_PAGE_SIZE; 159181641Skmacy pa = vtophys(va); 160181641Skmacy sc->ag_vdir[apbase_offset + i] = pa | 1; 161181641Skmacy } 162181641Skmacy 163181641Skmacy /* 164208651Salc * Make sure the chipset can see everything. 165181641Skmacy */ 166208651Salc agp_flush_cache(); 167204041Sed 168208651Salc return 0; 169204041Sed} 170202628Sed 171204041Sed 172181641Skmacystatic int 173181641Skmacyagp_ati_attach(device_t dev) 174181641Skmacy{ 175181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 176181641Skmacy int error, rid; 177181641Skmacy u_int32_t temp; 178181641Skmacy u_int32_t apsize_reg, agpmode_reg; 179181641Skmacy 180181641Skmacy error = agp_generic_attach(dev); 181181641Skmacy if (error) 182181641Skmacy return error; 183181641Skmacy 184181641Skmacy switch (pci_get_devid(dev)) { 185181641Skmacy case 0xcab01002: /* ATI RS100 AGP bridge */ 186181641Skmacy case 0xcab21002: /* ATI RS200 AGP bridge */ 187181641Skmacy case 0xcbb21002: /* ATI RS200M AGP bridge */ 188181641Skmacy case 0xcab31002: /* ATI RS250 AGP bridge */ 189181641Skmacy sc->is_rs300 = 0; 190181641Skmacy apsize_reg = ATI_RS100_APSIZE; 191181641Skmacy agpmode_reg = ATI_RS100_IG_AGPMODE; 192181641Skmacy break; 193181641Skmacy case 0x58301002: /* ATI RS300_100 AGP bridge */ 194181641Skmacy case 0x58311002: /* ATI RS300_133 AGP bridge */ 195181641Skmacy case 0x58321002: /* ATI RS300_166 AGP bridge */ 196216960Scperciva case 0x58331002: /* ATI RS300_200 AGP bridge */ 197216960Scperciva sc->is_rs300 = 1; 198216960Scperciva apsize_reg = ATI_RS300_APSIZE; 199216960Scperciva agpmode_reg = ATI_RS300_IG_AGPMODE; 200216960Scperciva break; 201181641Skmacy default: 202181641Skmacy /* Unknown chipset */ 203181641Skmacy return EINVAL; 204181641Skmacy }; 205181641Skmacy 206181641Skmacy rid = ATI_GART_MMADDR; 207181641Skmacy sc->regs = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 208181641Skmacy if (!sc->regs) { 209181641Skmacy agp_generic_detach(dev); 210181641Skmacy return ENOMEM; 211182902Skmacy } 212181641Skmacy 213181641Skmacy sc->bst = rman_get_bustag(sc->regs); 214181641Skmacy sc->bsh = rman_get_bushandle(sc->regs); 215181641Skmacy 216181641Skmacy sc->initial_aperture = AGP_GET_APERTURE(dev); 217181641Skmacy 218181641Skmacy for (;;) { 219228923Salc if (agp_ati_alloc_gatt(dev) == 0) 220228923Salc break; 221196726Sadrian 222196726Sadrian /* 223181641Skmacy * Probably contigmalloc failure. Try reducing the 224241498Salc * aperture so that the gatt size reduces. 225241498Salc */ 226241498Salc if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) 227241498Salc return ENOMEM; 228241498Salc } 229241498Salc 230241498Salc temp = pci_read_config(dev, apsize_reg, 4); 231181641Skmacy pci_write_config(dev, apsize_reg, temp | 1, 4); 232181641Skmacy 233236240Salc pci_write_config(dev, agpmode_reg, 0x20000, 4); 234181641Skmacy 235181641Skmacy WRITE4(ATI_GART_FEATURE_ID, 0x00060000); 236181641Skmacy 237181641Skmacy temp = pci_read_config(dev, 4, 4); /* XXX: Magic reg# */ 238181641Skmacy pci_write_config(dev, 4, temp | (1 << 14), 4); 239181641Skmacy 240181641Skmacy WRITE4(ATI_GART_BASE, sc->ag_pdir); 241181641Skmacy 242181641Skmacy AGP_FLUSH_TLB(dev); 243181641Skmacy 244181641Skmacy return 0; 245181641Skmacy} 246181641Skmacy 247181641Skmacystatic int 248181641Skmacyagp_ati_detach(device_t dev) 249181641Skmacy{ 250181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 251181641Skmacy int error; 252181641Skmacy u_int32_t apsize_reg, temp; 253204160Skmacy 254181641Skmacy if (sc->is_rs300) 255181641Skmacy apsize_reg = ATI_RS300_APSIZE; 256181641Skmacy else 257181641Skmacy apsize_reg = ATI_RS100_APSIZE; 258181641Skmacy 259181641Skmacy error = agp_generic_detach(dev); 260181641Skmacy if (error) 261181641Skmacy return error; 262181641Skmacy 263181641Skmacy /* Clear the GATT base */ 264181641Skmacy WRITE4(ATI_GART_BASE, 0); 265181641Skmacy 266181641Skmacy /* Put the aperture back the way it started. */ 267181641Skmacy AGP_SET_APERTURE(dev, sc->initial_aperture); 268181641Skmacy 269181641Skmacy temp = pci_read_config(dev, apsize_reg, 4); 270181641Skmacy pci_write_config(dev, apsize_reg, temp & ~1, 4); 271181641Skmacy 272181641Skmacy free(sc->ag_vdir, M_AGP); 273181641Skmacy free(sc->ag_virtual, M_AGP); 274181641Skmacy 275181641Skmacy bus_release_resource(dev, SYS_RES_MEMORY, ATI_GART_MMADDR, sc->regs); 276181641Skmacy 277181641Skmacy return 0; 278181641Skmacy} 279181641Skmacy 280181641Skmacystatic u_int32_t 281236378Salcagp_ati_get_aperture(device_t dev) 282181641Skmacy{ 283236291Salc struct agp_ati_softc *sc = device_get_softc(dev); 284208651Salc int size_value; 285208651Salc 286208651Salc if (sc->is_rs300) 287181641Skmacy size_value = pci_read_config(dev, ATI_RS300_APSIZE, 4); 288181641Skmacy else 289181641Skmacy size_value = pci_read_config(dev, ATI_RS100_APSIZE, 4); 290228923Salc 291228923Salc size_value = (size_value & 0x0000000e) >> 1; 292181641Skmacy size_value = (32 * 1024 * 1024) << size_value; 293181641Skmacy 294181641Skmacy return size_value; 295181641Skmacy} 296181641Skmacy 297181641Skmacystatic int 298181641Skmacyagp_ati_set_aperture(device_t dev, u_int32_t aperture) 299181641Skmacy{ 300181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 301181641Skmacy int size_value; 302181641Skmacy u_int32_t apsize_reg; 303228923Salc 304240126Salc if (sc->is_rs300) 305181641Skmacy apsize_reg = ATI_RS300_APSIZE; 306181641Skmacy else 307181641Skmacy apsize_reg = ATI_RS100_APSIZE; 308181641Skmacy 309181641Skmacy size_value = pci_read_config(dev, apsize_reg, 4); 310196725Sadrian 311181747Skmacy size_value &= ~0x0000000e; 312181641Skmacy size_value |= (ffs(aperture / (32 * 1024 * 1024)) - 1) << 1; 313181641Skmacy 314181641Skmacy pci_write_config(dev, apsize_reg, size_value, 4); 315181641Skmacy 316181641Skmacy return 0; 317181641Skmacy} 318181641Skmacy 319181641Skmacystatic int 320181641Skmacyagp_ati_bind_page(device_t dev, int offset, vm_offset_t physical) 321181641Skmacy{ 322181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 323181641Skmacy 324181641Skmacy if (offset < 0 || offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 325181641Skmacy return EINVAL; 326181641Skmacy 327181641Skmacy sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = physical | 1; 328181641Skmacy 329181641Skmacy return 0; 330181641Skmacy} 331181641Skmacy 332181641Skmacystatic int 333181641Skmacyagp_ati_unbind_page(device_t dev, int offset) 334181641Skmacy{ 335181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 336181641Skmacy 337181641Skmacy if (offset < 0 || offset >= (sc->ag_entries << AGP_PAGE_SHIFT)) 338181641Skmacy return EINVAL; 339181641Skmacy 340181641Skmacy sc->ag_virtual[offset >> AGP_PAGE_SHIFT] = 0; 341181641Skmacy return 0; 342181641Skmacy} 343181641Skmacy 344181641Skmacystatic void 345181641Skmacyagp_ati_flush_tlb(device_t dev) 346181641Skmacy{ 347181641Skmacy struct agp_ati_softc *sc = device_get_softc(dev); 348181641Skmacy 349181641Skmacy /* Set the cache invalidate bit and wait for the chipset to clear */ 350181641Skmacy WRITE4(ATI_GART_CACHE_CNTRL, 1); 351181641Skmacy (void)READ4(ATI_GART_CACHE_CNTRL); 352181641Skmacy} 353181641Skmacy 354181641Skmacystatic device_method_t agp_ati_methods[] = { 355181641Skmacy /* Device interface */ 356181641Skmacy DEVMETHOD(device_probe, agp_ati_probe), 357181641Skmacy DEVMETHOD(device_attach, agp_ati_attach), 358181641Skmacy DEVMETHOD(device_detach, agp_ati_detach), 359181641Skmacy DEVMETHOD(device_shutdown, bus_generic_shutdown), 360181641Skmacy DEVMETHOD(device_suspend, bus_generic_suspend), 361181641Skmacy DEVMETHOD(device_resume, bus_generic_resume), 362181641Skmacy 363181641Skmacy /* AGP interface */ 364181641Skmacy DEVMETHOD(agp_get_aperture, agp_ati_get_aperture), 365181641Skmacy DEVMETHOD(agp_set_aperture, agp_ati_set_aperture), 366181641Skmacy DEVMETHOD(agp_bind_page, agp_ati_bind_page), 367181641Skmacy DEVMETHOD(agp_unbind_page, agp_ati_unbind_page), 368181641Skmacy DEVMETHOD(agp_flush_tlb, agp_ati_flush_tlb), 369181641Skmacy DEVMETHOD(agp_enable, agp_generic_enable), 370181641Skmacy DEVMETHOD(agp_alloc_memory, agp_generic_alloc_memory), 371228923Salc DEVMETHOD(agp_free_memory, agp_generic_free_memory), 372228923Salc DEVMETHOD(agp_bind_memory, agp_generic_bind_memory), 373228923Salc DEVMETHOD(agp_unbind_memory, agp_generic_unbind_memory), 374228923Salc 375228923Salc { 0, 0 } 376181641Skmacy}; 377181641Skmacy 378181641Skmacystatic driver_t agp_ati_driver = { 379181641Skmacy "agp", 380181641Skmacy agp_ati_methods, 381181641Skmacy sizeof(struct agp_ati_softc), 382181641Skmacy}; 383181641Skmacy 384181641Skmacystatic devclass_t agp_devclass; 385181641Skmacy 386181641SkmacyDRIVER_MODULE(agp_ati, hostb, agp_ati_driver, agp_devclass, 0, 0); 387181641SkmacyMODULE_DEPEND(agp_ati, agp, 1, 1, 1); 388181641SkmacyMODULE_DEPEND(agp_ati, pci, 1, 1, 1); 389222813Sattilio