1 /* $NetBSD: agp_i810.c,v 1.27 2005/12/11 12:22:48 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2000 Doug Rabson 5 * Copyright (c) 2000 Ruslan Ermilov 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: src/sys/pci/agp_i810.c,v 1.4 2001/07/05 21:28:47 jhb Exp $ 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: agp_i810.c,v 1.27 2005/12/11 12:22:48 christos Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/malloc.h> 38 #include <sys/kernel.h> 39 #include <sys/lock.h> 40 #include <sys/proc.h> 41 #include <sys/device.h> 42 #include <sys/conf.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <dev/pci/pcivar.h> 47 #include <dev/pci/pcireg.h> 48 #include <dev/pci/pcidevs.h> 49 #include <dev/pci/agpvar.h> 50 #include <dev/pci/agpreg.h> 51 52 #include <sys/agpio.h> 53 54 #include <machine/bus.h> 55 56 #include "agp_intel.h" 57 58 #define READ1(off) bus_space_read_1(isc->bst, isc->bsh, off) 59 #define READ4(off) bus_space_read_4(isc->bst, isc->bsh, off) 60 #define WRITE4(off,v) bus_space_write_4(isc->bst, isc->bsh, off, v) 61 62 #define CHIP_I810 0 /* i810/i815 */ 63 #define CHIP_I830 1 /* 830M/845G */ 64 #define CHIP_I855 2 /* 852GM/855GM/865G */ 65 66 struct agp_i810_softc { 67 u_int32_t initial_aperture; /* aperture size at startup */ 68 struct agp_gatt *gatt; 69 int chiptype; /* i810-like or i830 */ 70 u_int32_t dcache_size; /* i810 only */ 71 u_int32_t stolen; /* number of i830/845 gtt entries 72 for stolen memory */ 73 bus_space_tag_t bst; /* bus_space tag */ 74 bus_space_handle_t bsh; /* bus_space handle */ 75 struct pci_attach_args vga_pa; 76 77 void *sc_powerhook; 78 struct pci_conf_state sc_pciconf; 79 }; 80 81 static u_int32_t agp_i810_get_aperture(struct agp_softc *); 82 static int agp_i810_set_aperture(struct agp_softc *, u_int32_t); 83 static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t); 84 static int agp_i810_unbind_page(struct agp_softc *, off_t); 85 static void agp_i810_flush_tlb(struct agp_softc *); 86 static int agp_i810_enable(struct agp_softc *, u_int32_t mode); 87 static struct agp_memory *agp_i810_alloc_memory(struct agp_softc *, int, 88 vsize_t); 89 static int agp_i810_free_memory(struct agp_softc *, struct agp_memory *); 90 static int agp_i810_bind_memory(struct agp_softc *, struct agp_memory *, off_t); 91 static int agp_i810_unbind_memory(struct agp_softc *, struct agp_memory *); 92 static void agp_i810_powerhook(int, void *); 93 94 static struct agp_methods agp_i810_methods = { 95 agp_i810_get_aperture, 96 agp_i810_set_aperture, 97 agp_i810_bind_page, 98 agp_i810_unbind_page, 99 agp_i810_flush_tlb, 100 agp_i810_enable, 101 agp_i810_alloc_memory, 102 agp_i810_free_memory, 103 agp_i810_bind_memory, 104 agp_i810_unbind_memory, 105 }; 106 107 /* XXXthorpej -- duplicated code (see arch/i386/pci/pchb.c) */ 108 static int 109 agp_i810_vgamatch(struct pci_attach_args *pa) 110 { 111 112 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 113 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA) 114 return (0); 115 116 switch (PCI_PRODUCT(pa->pa_id)) { 117 case PCI_PRODUCT_INTEL_82810_GC: 118 case PCI_PRODUCT_INTEL_82810_DC100_GC: 119 case PCI_PRODUCT_INTEL_82810E_GC: 120 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 121 case PCI_PRODUCT_INTEL_82830MP_IV: 122 case PCI_PRODUCT_INTEL_82845G_IGD: 123 case PCI_PRODUCT_INTEL_82855GM_IGD: 124 case PCI_PRODUCT_INTEL_82865_IGD: 125 return (1); 126 } 127 128 return (0); 129 } 130 131 int 132 agp_i810_attach(struct device *parent, struct device *self, void *aux) 133 { 134 struct agp_softc *sc = (void *)self; 135 struct agp_i810_softc *isc; 136 struct agp_gatt *gatt; 137 int error; 138 139 isc = malloc(sizeof *isc, M_AGP, M_NOWAIT|M_ZERO); 140 if (isc == NULL) { 141 aprint_error(": can't allocate chipset-specific softc\n"); 142 return ENOMEM; 143 } 144 sc->as_chipc = isc; 145 sc->as_methods = &agp_i810_methods; 146 147 if (pci_find_device(&isc->vga_pa, agp_i810_vgamatch) == 0) { 148 #if NAGP_INTEL > 0 149 const struct pci_attach_args *pa = aux; 150 151 switch (PCI_PRODUCT(pa->pa_id)) { 152 case PCI_PRODUCT_INTEL_82840_HB: 153 case PCI_PRODUCT_INTEL_82865_HB: 154 case PCI_PRODUCT_INTEL_82845G_DRAM: 155 case PCI_PRODUCT_INTEL_82815_FULL_HUB: 156 return agp_intel_attach(parent, self, aux); 157 } 158 #endif 159 aprint_error(": can't find internal VGA device config space\n"); 160 free(isc, M_AGP); 161 return ENOENT; 162 } 163 164 /* XXXfvdl */ 165 sc->as_dmat = isc->vga_pa.pa_dmat; 166 167 error = agp_map_aperture(&isc->vga_pa, sc); 168 if (error != 0) { 169 aprint_error(": can't map aperture\n"); 170 free(isc, M_AGP); 171 return error; 172 } 173 174 switch (PCI_PRODUCT(isc->vga_pa.pa_id)) { 175 case PCI_PRODUCT_INTEL_82810_GC: 176 case PCI_PRODUCT_INTEL_82810_DC100_GC: 177 case PCI_PRODUCT_INTEL_82810E_GC: 178 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 179 isc->chiptype = CHIP_I810; 180 break; 181 case PCI_PRODUCT_INTEL_82830MP_IV: 182 case PCI_PRODUCT_INTEL_82845G_IGD: 183 isc->chiptype = CHIP_I830; 184 break; 185 case PCI_PRODUCT_INTEL_82855GM_IGD: 186 case PCI_PRODUCT_INTEL_82865_IGD: 187 isc->chiptype = CHIP_I855; 188 break; 189 } 190 191 error = pci_mapreg_map(&isc->vga_pa, AGP_I810_MMADR, 192 PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL); 193 if (error != 0) { 194 aprint_error(": can't map mmadr registers\n"); 195 return error; 196 } 197 198 isc->initial_aperture = AGP_GET_APERTURE(sc); 199 200 gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 201 if (!gatt) { 202 agp_generic_detach(sc); 203 return ENOMEM; 204 } 205 isc->gatt = gatt; 206 207 gatt->ag_entries = AGP_GET_APERTURE(sc) >> AGP_PAGE_SHIFT; 208 209 if (isc->chiptype == CHIP_I810) { 210 int dummyseg; 211 /* Some i810s have on-chip memory called dcache */ 212 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 213 isc->dcache_size = 4 * 1024 * 1024; 214 else 215 isc->dcache_size = 0; 216 217 /* According to the specs the gatt on the i810 must be 64k */ 218 if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024, 219 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, 220 &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0) { 221 free(gatt, M_AGP); 222 agp_generic_detach(sc); 223 return ENOMEM; 224 } 225 226 gatt->ag_size = gatt->ag_entries * sizeof(u_int32_t); 227 memset(gatt->ag_virtual, 0, gatt->ag_size); 228 229 agp_flush_cache(); 230 /* Install the GATT. */ 231 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 232 } else if (isc->chiptype == CHIP_I830) { 233 /* The i830 automatically initializes the 128k gatt on boot. */ 234 pcireg_t reg; 235 u_int32_t pgtblctl; 236 u_int16_t gcc1; 237 238 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 239 gcc1 = (u_int16_t)(reg >> 16); 240 switch (gcc1 & AGP_I830_GCC1_GMS) { 241 case AGP_I830_GCC1_GMS_STOLEN_512: 242 isc->stolen = (512 - 132) * 1024 / 4096; 243 break; 244 case AGP_I830_GCC1_GMS_STOLEN_1024: 245 isc->stolen = (1024 - 132) * 1024 / 4096; 246 break; 247 case AGP_I830_GCC1_GMS_STOLEN_8192: 248 isc->stolen = (8192 - 132) * 1024 / 4096; 249 break; 250 default: 251 isc->stolen = 0; 252 aprint_error( 253 ": unknown memory configuration, disabling\n"); 254 agp_generic_detach(sc); 255 return EINVAL; 256 } 257 if (isc->stolen > 0) { 258 aprint_error(": detected %dk stolen memory\n%s", 259 isc->stolen * 4, sc->as_dev.dv_xname); 260 } 261 262 /* GATT address is already in there, make sure it's enabled */ 263 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 264 pgtblctl |= 1; 265 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 266 267 gatt->ag_physical = pgtblctl & ~1; 268 } else { /* CHIP_I855 */ 269 /* The 855GM automatically initializes the 128k gatt on boot. */ 270 pcireg_t reg; 271 u_int32_t pgtblctl; 272 u_int16_t gcc1; 273 274 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I855_GCC1); 275 gcc1 = (u_int16_t)(reg >> 16); 276 switch (gcc1 & AGP_I855_GCC1_GMS) { 277 case AGP_I855_GCC1_GMS_STOLEN_1M: 278 isc->stolen = (1024 - 132) * 1024 / 4096; 279 break; 280 case AGP_I855_GCC1_GMS_STOLEN_4M: 281 isc->stolen = (4096 - 132) * 1024 / 4096; 282 break; 283 case AGP_I855_GCC1_GMS_STOLEN_8M: 284 isc->stolen = (8192 - 132) * 1024 / 4096; 285 break; 286 case AGP_I855_GCC1_GMS_STOLEN_16M: 287 isc->stolen = (16384 - 132) * 1024 / 4096; 288 break; 289 case AGP_I855_GCC1_GMS_STOLEN_32M: 290 isc->stolen = (32768 - 132) * 1024 / 4096; 291 break; 292 default: 293 isc->stolen = 0; 294 aprint_error( 295 ": unknown memory configuration, disabling\n"); 296 agp_generic_detach(sc); 297 return EINVAL; 298 } 299 if (isc->stolen > 0) { 300 aprint_error(": detected %dk stolen memory\n%s", 301 isc->stolen * 4, sc->as_dev.dv_xname); 302 } 303 304 /* GATT address is already in there, make sure it's enabled */ 305 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 306 pgtblctl |= 1; 307 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 308 309 gatt->ag_physical = pgtblctl & ~1; 310 } 311 312 /* 313 * Make sure the chipset can see everything. 314 */ 315 agp_flush_cache(); 316 317 isc->sc_powerhook = powerhook_establish(agp_i810_powerhook, sc); 318 if (isc->sc_powerhook == NULL) 319 printf("%s: WARNING: unable to establish PCI power hook\n", 320 sc->as_dev.dv_xname); 321 322 return 0; 323 } 324 325 #if 0 326 static int 327 agp_i810_detach(struct agp_softc *sc) 328 { 329 int error; 330 struct agp_i810_softc *isc = sc->as_chipc; 331 332 error = agp_generic_detach(sc); 333 if (error) 334 return error; 335 336 /* Clear the GATT base. */ 337 if (sc->chiptype == CHIP_I810) { 338 WRITE4(AGP_I810_PGTBL_CTL, 0); 339 } else { 340 unsigned int pgtblctl; 341 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 342 pgtblctl &= ~1; 343 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 344 } 345 346 /* Put the aperture back the way it started. */ 347 AGP_SET_APERTURE(sc, isc->initial_aperture); 348 349 if (sc->chiptype == CHIP_I810) { 350 agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap, 351 (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 352 } 353 free(sc->gatt, M_AGP); 354 355 return 0; 356 } 357 #endif 358 359 static u_int32_t 360 agp_i810_get_aperture(struct agp_softc *sc) 361 { 362 struct agp_i810_softc *isc = sc->as_chipc; 363 pcireg_t reg; 364 365 if (isc->chiptype == CHIP_I810) { 366 u_int16_t miscc; 367 368 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 369 miscc = (u_int16_t)(reg >> 16); 370 if ((miscc & AGP_I810_MISCC_WINSIZE) == 371 AGP_I810_MISCC_WINSIZE_32) 372 return 32 * 1024 * 1024; 373 else 374 return 64 * 1024 * 1024; 375 } else if (isc->chiptype == CHIP_I830) { 376 u_int16_t gcc1; 377 378 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 379 gcc1 = (u_int16_t)(reg >> 16); 380 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64) 381 return 64 * 1024 * 1024; 382 else 383 return 128 * 1024 * 1024; 384 } else { /* CHIP_I855 */ 385 return 128 * 1024 * 1024; 386 } 387 } 388 389 static int 390 agp_i810_set_aperture(struct agp_softc *sc, u_int32_t aperture) 391 { 392 struct agp_i810_softc *isc = sc->as_chipc; 393 pcireg_t reg; 394 395 if (isc->chiptype == CHIP_I810) { 396 u_int16_t miscc; 397 398 /* 399 * Double check for sanity. 400 */ 401 if (aperture != (32 * 1024 * 1024) && 402 aperture != (64 * 1024 * 1024)) { 403 printf("%s: bad aperture size %d\n", 404 sc->as_dev.dv_xname, aperture); 405 return EINVAL; 406 } 407 408 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 409 miscc = (u_int16_t)(reg >> 16); 410 miscc &= ~AGP_I810_MISCC_WINSIZE; 411 if (aperture == 32 * 1024 * 1024) 412 miscc |= AGP_I810_MISCC_WINSIZE_32; 413 else 414 miscc |= AGP_I810_MISCC_WINSIZE_64; 415 416 reg &= 0x0000ffff; 417 reg |= ((pcireg_t)miscc) << 16; 418 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I810_SMRAM, reg); 419 } if (isc->chiptype == CHIP_I830) { 420 u_int16_t gcc1; 421 422 if (aperture != (64 * 1024 * 1024) && 423 aperture != (128 * 1024 * 1024)) { 424 printf("%s: bad aperture size %d\n", 425 sc->as_dev.dv_xname, aperture); 426 return EINVAL; 427 } 428 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 429 gcc1 = (u_int16_t)(reg >> 16); 430 gcc1 &= ~AGP_I830_GCC1_GMASIZE; 431 if (aperture == 64 * 1024 * 1024) 432 gcc1 |= AGP_I830_GCC1_GMASIZE_64; 433 else 434 gcc1 |= AGP_I830_GCC1_GMASIZE_128; 435 436 reg &= 0x0000ffff; 437 reg |= ((pcireg_t)gcc1) << 16; 438 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I830_GCC0, reg); 439 } else { /* CHIP_I855 */ 440 if (aperture != 128 * 1024 * 1024) { 441 printf("%s: bad aperture size %d\n", 442 sc->as_dev.dv_xname, aperture); 443 return EINVAL; 444 } 445 } 446 447 return 0; 448 } 449 450 static int 451 agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical) 452 { 453 struct agp_i810_softc *isc = sc->as_chipc; 454 455 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) { 456 #ifdef DEBUG 457 printf("%s: failed: offset 0x%08x, shift %d, entries %d\n", 458 sc->as_dev.dv_xname, (int)offset, AGP_PAGE_SHIFT, 459 isc->gatt->ag_entries); 460 #endif 461 return EINVAL; 462 } 463 464 if (isc->chiptype != CHIP_I830) { 465 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 466 #ifdef DEBUG 467 printf("%s: trying to bind into stolen memory", 468 sc->as_dev.dv_xname); 469 #endif 470 return EINVAL; 471 } 472 } 473 474 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 475 physical | 1); 476 return 0; 477 } 478 479 static int 480 agp_i810_unbind_page(struct agp_softc *sc, off_t offset) 481 { 482 struct agp_i810_softc *isc = sc->as_chipc; 483 484 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 485 return EINVAL; 486 487 if (isc->chiptype != CHIP_I810 ) { 488 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 489 #ifdef DEBUG 490 printf("%s: trying to unbind from stolen memory", 491 sc->as_dev.dv_xname); 492 #endif 493 return EINVAL; 494 } 495 } 496 497 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 0); 498 return 0; 499 } 500 501 /* 502 * Writing via memory mapped registers already flushes all TLBs. 503 */ 504 static void 505 agp_i810_flush_tlb(struct agp_softc *sc) 506 { 507 } 508 509 static int 510 agp_i810_enable(struct agp_softc *sc, u_int32_t mode) 511 { 512 513 return 0; 514 } 515 516 static struct agp_memory * 517 agp_i810_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 518 { 519 struct agp_i810_softc *isc = sc->as_chipc; 520 struct agp_memory *mem; 521 522 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 523 return 0; 524 525 if (sc->as_allocated + size > sc->as_maxmem) 526 return 0; 527 528 if (type == 1) { 529 /* 530 * Mapping local DRAM into GATT. 531 */ 532 if (isc->chiptype != CHIP_I810 ) 533 return 0; 534 if (size != isc->dcache_size) 535 return 0; 536 } else if (type == 2) { 537 /* 538 * Bogus mapping of a single page for the hardware cursor. 539 */ 540 if (size != AGP_PAGE_SIZE) 541 return 0; 542 } 543 544 mem = malloc(sizeof *mem, M_AGP, M_WAITOK|M_ZERO); 545 if (mem == NULL) 546 return NULL; 547 mem->am_id = sc->as_nextid++; 548 mem->am_size = size; 549 mem->am_type = type; 550 551 if (type == 2) { 552 /* 553 * Allocate and wire down the page now so that we can 554 * get its physical address. 555 */ 556 mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_AGP, 557 M_WAITOK); 558 if (mem->am_dmaseg == NULL) { 559 free(mem, M_AGP); 560 return NULL; 561 } 562 if (agp_alloc_dmamem(sc->as_dmat, size, 0, 563 &mem->am_dmamap, &mem->am_virtual, &mem->am_physical, 564 mem->am_dmaseg, 1, &mem->am_nseg) != 0) { 565 free(mem->am_dmaseg, M_AGP); 566 free(mem, M_AGP); 567 return NULL; 568 } 569 } else if (type != 1) { 570 if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1, 571 size, 0, BUS_DMA_NOWAIT, 572 &mem->am_dmamap) != 0) { 573 free(mem, M_AGP); 574 return NULL; 575 } 576 } 577 578 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 579 sc->as_allocated += size; 580 581 return mem; 582 } 583 584 static int 585 agp_i810_free_memory(struct agp_softc *sc, struct agp_memory *mem) 586 { 587 if (mem->am_is_bound) 588 return EBUSY; 589 590 if (mem->am_type == 2) { 591 agp_free_dmamem(sc->as_dmat, mem->am_size, mem->am_dmamap, 592 mem->am_virtual, mem->am_dmaseg, mem->am_nseg); 593 free(mem->am_dmaseg, M_AGP); 594 } 595 596 sc->as_allocated -= mem->am_size; 597 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 598 free(mem, M_AGP); 599 return 0; 600 } 601 602 static int 603 agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 604 off_t offset) 605 { 606 struct agp_i810_softc *isc = sc->as_chipc; 607 u_int32_t regval, i; 608 609 /* 610 * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the 611 * X server for mysterious reasons which leads to crashes if we write 612 * to the GTT through the MMIO window. 613 * Until the issue is solved, simply restore it. 614 */ 615 regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL); 616 if (regval != (isc->gatt->ag_physical | 1)) { 617 printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n", 618 regval); 619 bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL, 620 isc->gatt->ag_physical | 1); 621 } 622 623 if (mem->am_type == 2) { 624 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 625 mem->am_physical | 1); 626 mem->am_offset = offset; 627 mem->am_is_bound = 1; 628 return 0; 629 } 630 631 if (mem->am_type != 1) 632 return agp_generic_bind_memory(sc, mem, offset); 633 634 if (isc->chiptype != CHIP_I810) 635 return EINVAL; 636 637 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { 638 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 639 i | 3); 640 } 641 mem->am_is_bound = 1; 642 return 0; 643 } 644 645 static int 646 agp_i810_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 647 { 648 struct agp_i810_softc *isc = sc->as_chipc; 649 u_int32_t i; 650 651 if (mem->am_type == 2) { 652 WRITE4(AGP_I810_GTT + 653 (u_int32_t)(mem->am_offset >> AGP_PAGE_SHIFT) * 4, 654 0); 655 mem->am_offset = 0; 656 mem->am_is_bound = 0; 657 return 0; 658 } 659 660 if (mem->am_type != 1) 661 return agp_generic_unbind_memory(sc, mem); 662 663 if (isc->chiptype != CHIP_I810) 664 return EINVAL; 665 666 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 667 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0); 668 mem->am_is_bound = 0; 669 return 0; 670 } 671 672 static void 673 agp_i810_powerhook(int why, void *arg) 674 { 675 struct agp_softc *sc = (struct agp_softc *)arg; 676 struct agp_i810_softc *isc = sc->as_chipc; 677 678 if (why == PWR_RESUME) { 679 pci_conf_restore(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 680 agp_flush_cache(); 681 } else if ((why == PWR_STANDBY) || (why == PWR_SUSPEND)) 682 pci_conf_capture(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 683 684 return; 685 } 686