1 /* $NetBSD: agp_i810.c,v 1.22 2004/03/20 14:00:40 jdolecek 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.22 2004/03/20 14:00:40 jdolecek 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 78 static u_int32_t agp_i810_get_aperture(struct agp_softc *); 79 static int agp_i810_set_aperture(struct agp_softc *, u_int32_t); 80 static int agp_i810_bind_page(struct agp_softc *, off_t, bus_addr_t); 81 static int agp_i810_unbind_page(struct agp_softc *, off_t); 82 static void agp_i810_flush_tlb(struct agp_softc *); 83 static int agp_i810_enable(struct agp_softc *, u_int32_t mode); 84 static struct agp_memory *agp_i810_alloc_memory(struct agp_softc *, int, 85 vsize_t); 86 static int agp_i810_free_memory(struct agp_softc *, struct agp_memory *); 87 static int agp_i810_bind_memory(struct agp_softc *, struct agp_memory *, off_t); 88 static int agp_i810_unbind_memory(struct agp_softc *, struct agp_memory *); 89 90 struct agp_methods agp_i810_methods = { 91 agp_i810_get_aperture, 92 agp_i810_set_aperture, 93 agp_i810_bind_page, 94 agp_i810_unbind_page, 95 agp_i810_flush_tlb, 96 agp_i810_enable, 97 agp_i810_alloc_memory, 98 agp_i810_free_memory, 99 agp_i810_bind_memory, 100 agp_i810_unbind_memory, 101 }; 102 103 /* XXXthorpej -- duplicated code (see arch/i386/pci/pchb.c) */ 104 static int 105 agp_i810_vgamatch(struct pci_attach_args *pa) 106 { 107 108 if (PCI_CLASS(pa->pa_class) != PCI_CLASS_DISPLAY || 109 PCI_SUBCLASS(pa->pa_class) != PCI_SUBCLASS_DISPLAY_VGA) 110 return (0); 111 112 switch (PCI_PRODUCT(pa->pa_id)) { 113 case PCI_PRODUCT_INTEL_82810_GC: 114 case PCI_PRODUCT_INTEL_82810_DC100_GC: 115 case PCI_PRODUCT_INTEL_82810E_GC: 116 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 117 case PCI_PRODUCT_INTEL_82830MP_IV: 118 case PCI_PRODUCT_INTEL_82845G_IGD: 119 case PCI_PRODUCT_INTEL_82855GM_IGD: 120 case PCI_PRODUCT_INTEL_82865_IGD: 121 return (1); 122 } 123 124 return (0); 125 } 126 127 int 128 agp_i810_attach(struct device *parent, struct device *self, void *aux) 129 { 130 struct agp_softc *sc = (void *)self; 131 struct agp_i810_softc *isc; 132 struct agp_gatt *gatt; 133 int error; 134 135 isc = malloc(sizeof *isc, M_AGP, M_NOWAIT|M_ZERO); 136 if (isc == NULL) { 137 aprint_error(": can't allocate chipset-specific softc\n"); 138 return ENOMEM; 139 } 140 sc->as_chipc = isc; 141 sc->as_methods = &agp_i810_methods; 142 143 if (pci_find_device(&isc->vga_pa, agp_i810_vgamatch) == 0) { 144 #if NAGP_INTEL > 0 145 const struct pci_attach_args *pa = aux; 146 147 switch (PCI_PRODUCT(pa->pa_id)) { 148 case PCI_PRODUCT_INTEL_82840_HB: 149 case PCI_PRODUCT_INTEL_82865_HB: 150 case PCI_PRODUCT_INTEL_82845G_DRAM: 151 return agp_intel_attach(parent, self, aux); 152 } 153 #endif 154 aprint_error(": can't find internal VGA device config space\n"); 155 free(isc, M_AGP); 156 return ENOENT; 157 } 158 159 /* XXXfvdl */ 160 sc->as_dmat = isc->vga_pa.pa_dmat; 161 162 error = agp_map_aperture(&isc->vga_pa, sc); 163 if (error != 0) { 164 aprint_error(": can't map aperture\n"); 165 free(isc, M_AGP); 166 return error; 167 } 168 169 switch (PCI_PRODUCT(isc->vga_pa.pa_id)) { 170 case PCI_PRODUCT_INTEL_82810_GC: 171 case PCI_PRODUCT_INTEL_82810_DC100_GC: 172 case PCI_PRODUCT_INTEL_82810E_GC: 173 case PCI_PRODUCT_INTEL_82815_FULL_GRAPH: 174 isc->chiptype = CHIP_I810; 175 break; 176 case PCI_PRODUCT_INTEL_82830MP_IV: 177 case PCI_PRODUCT_INTEL_82845G_IGD: 178 isc->chiptype = CHIP_I830; 179 break; 180 case PCI_PRODUCT_INTEL_82855GM_IGD: 181 case PCI_PRODUCT_INTEL_82865_IGD: 182 isc->chiptype = CHIP_I855; 183 break; 184 } 185 186 error = pci_mapreg_map(&isc->vga_pa, AGP_I810_MMADR, 187 PCI_MAPREG_TYPE_MEM, 0, &isc->bst, &isc->bsh, NULL, NULL); 188 if (error != 0) { 189 aprint_error(": can't map mmadr registers\n"); 190 return error; 191 } 192 193 isc->initial_aperture = AGP_GET_APERTURE(sc); 194 195 gatt = malloc(sizeof(struct agp_gatt), M_AGP, M_NOWAIT); 196 if (!gatt) { 197 agp_generic_detach(sc); 198 return ENOMEM; 199 } 200 isc->gatt = gatt; 201 202 gatt->ag_entries = AGP_GET_APERTURE(sc) >> AGP_PAGE_SHIFT; 203 204 if (isc->chiptype == CHIP_I810) { 205 int dummyseg; 206 /* Some i810s have on-chip memory called dcache */ 207 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 208 isc->dcache_size = 4 * 1024 * 1024; 209 else 210 isc->dcache_size = 0; 211 212 /* According to the specs the gatt on the i810 must be 64k */ 213 if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024, 214 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, 215 &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0) { 216 free(gatt, M_AGP); 217 agp_generic_detach(sc); 218 return ENOMEM; 219 } 220 221 gatt->ag_size = gatt->ag_entries * sizeof(u_int32_t); 222 memset(gatt->ag_virtual, 0, gatt->ag_size); 223 224 agp_flush_cache(); 225 /* Install the GATT. */ 226 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 227 } else if (isc->chiptype == CHIP_I830) { 228 /* The i830 automatically initializes the 128k gatt on boot. */ 229 pcireg_t reg; 230 u_int32_t pgtblctl; 231 u_int16_t gcc1; 232 233 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 234 gcc1 = (u_int16_t)(reg >> 16); 235 switch (gcc1 & AGP_I830_GCC1_GMS) { 236 case AGP_I830_GCC1_GMS_STOLEN_512: 237 isc->stolen = (512 - 132) * 1024 / 4096; 238 break; 239 case AGP_I830_GCC1_GMS_STOLEN_1024: 240 isc->stolen = (1024 - 132) * 1024 / 4096; 241 break; 242 case AGP_I830_GCC1_GMS_STOLEN_8192: 243 isc->stolen = (8192 - 132) * 1024 / 4096; 244 break; 245 default: 246 isc->stolen = 0; 247 aprint_error( 248 ": unknown memory configuration, disabling\n"); 249 agp_generic_detach(sc); 250 return EINVAL; 251 } 252 if (isc->stolen > 0) { 253 aprint_error(": detected %dk stolen memory\n%s", 254 isc->stolen * 4, sc->as_dev.dv_xname); 255 } 256 257 /* GATT address is already in there, make sure it's enabled */ 258 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 259 pgtblctl |= 1; 260 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 261 262 gatt->ag_physical = pgtblctl & ~1; 263 } else { /* CHIP_I855 */ 264 /* The 855GM automatically initializes the 128k gatt on boot. */ 265 pcireg_t reg; 266 u_int32_t pgtblctl; 267 u_int16_t gcc1; 268 269 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I855_GCC1); 270 gcc1 = (u_int16_t)(reg >> 16); 271 switch (gcc1 & AGP_I855_GCC1_GMS) { 272 case AGP_I855_GCC1_GMS_STOLEN_1M: 273 isc->stolen = (1024 - 132) * 1024 / 4096; 274 break; 275 case AGP_I855_GCC1_GMS_STOLEN_4M: 276 isc->stolen = (4096 - 132) * 1024 / 4096; 277 break; 278 case AGP_I855_GCC1_GMS_STOLEN_8M: 279 isc->stolen = (8192 - 132) * 1024 / 4096; 280 break; 281 case AGP_I855_GCC1_GMS_STOLEN_16M: 282 isc->stolen = (16384 - 132) * 1024 / 4096; 283 break; 284 case AGP_I855_GCC1_GMS_STOLEN_32M: 285 isc->stolen = (32768 - 132) * 1024 / 4096; 286 break; 287 default: 288 isc->stolen = 0; 289 aprint_error( 290 ": unknown memory configuration, disabling\n"); 291 agp_generic_detach(sc); 292 return EINVAL; 293 } 294 if (isc->stolen > 0) { 295 aprint_error(": detected %dk stolen memory\n%s", 296 isc->stolen * 4, sc->as_dev.dv_xname); 297 } 298 299 /* GATT address is already in there, make sure it's enabled */ 300 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 301 pgtblctl |= 1; 302 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 303 304 gatt->ag_physical = pgtblctl & ~1; 305 } 306 307 /* 308 * Make sure the chipset can see everything. 309 */ 310 agp_flush_cache(); 311 312 return 0; 313 } 314 315 #if 0 316 static int 317 agp_i810_detach(struct agp_softc *sc) 318 { 319 int error; 320 struct agp_i810_softc *isc = sc->as_chipc; 321 322 error = agp_generic_detach(sc); 323 if (error) 324 return error; 325 326 /* Clear the GATT base. */ 327 if (sc->chiptype == CHIP_I810) { 328 WRITE4(AGP_I810_PGTBL_CTL, 0); 329 } else { 330 unsigned int pgtblctl; 331 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 332 pgtblctl &= ~1; 333 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 334 } 335 336 /* Put the aperture back the way it started. */ 337 AGP_SET_APERTURE(sc, isc->initial_aperture); 338 339 if (sc->chiptype == CHIP_I810) { 340 agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap, 341 (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 342 } 343 free(sc->gatt, M_AGP); 344 345 return 0; 346 } 347 #endif 348 349 static u_int32_t 350 agp_i810_get_aperture(struct agp_softc *sc) 351 { 352 struct agp_i810_softc *isc = sc->as_chipc; 353 pcireg_t reg; 354 355 if (isc->chiptype == CHIP_I810) { 356 u_int16_t miscc; 357 358 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 359 miscc = (u_int16_t)(reg >> 16); 360 if ((miscc & AGP_I810_MISCC_WINSIZE) == 361 AGP_I810_MISCC_WINSIZE_32) 362 return 32 * 1024 * 1024; 363 else 364 return 64 * 1024 * 1024; 365 } else if (isc->chiptype == CHIP_I830) { 366 u_int16_t gcc1; 367 368 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 369 gcc1 = (u_int16_t)(reg >> 16); 370 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64) 371 return 64 * 1024 * 1024; 372 else 373 return 128 * 1024 * 1024; 374 } else { /* CHIP_I855 */ 375 return 128 * 1024 * 1024; 376 } 377 } 378 379 static int 380 agp_i810_set_aperture(struct agp_softc *sc, u_int32_t aperture) 381 { 382 struct agp_i810_softc *isc = sc->as_chipc; 383 pcireg_t reg; 384 385 if (isc->chiptype == CHIP_I810) { 386 u_int16_t miscc; 387 388 /* 389 * Double check for sanity. 390 */ 391 if (aperture != (32 * 1024 * 1024) && 392 aperture != (64 * 1024 * 1024)) { 393 printf("%s: bad aperture size %d\n", 394 sc->as_dev.dv_xname, aperture); 395 return EINVAL; 396 } 397 398 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 399 miscc = (u_int16_t)(reg >> 16); 400 miscc &= ~AGP_I810_MISCC_WINSIZE; 401 if (aperture == 32 * 1024 * 1024) 402 miscc |= AGP_I810_MISCC_WINSIZE_32; 403 else 404 miscc |= AGP_I810_MISCC_WINSIZE_64; 405 406 reg &= 0x0000ffff; 407 reg |= ((pcireg_t)miscc) << 16; 408 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I810_SMRAM, reg); 409 } if (isc->chiptype == CHIP_I830) { 410 u_int16_t gcc1; 411 412 if (aperture != (64 * 1024 * 1024) && 413 aperture != (128 * 1024 * 1024)) { 414 printf("%s: bad aperture size %d\n", 415 sc->as_dev.dv_xname, aperture); 416 return EINVAL; 417 } 418 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 419 gcc1 = (u_int16_t)(reg >> 16); 420 gcc1 &= ~AGP_I830_GCC1_GMASIZE; 421 if (aperture == 64 * 1024 * 1024) 422 gcc1 |= AGP_I830_GCC1_GMASIZE_64; 423 else 424 gcc1 |= AGP_I830_GCC1_GMASIZE_128; 425 426 reg &= 0x0000ffff; 427 reg |= ((pcireg_t)gcc1) << 16; 428 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I830_GCC0, reg); 429 } else { /* CHIP_I855 */ 430 if (aperture != 128 * 1024 * 1024) { 431 printf("%s: bad aperture size %d\n", 432 sc->as_dev.dv_xname, aperture); 433 return EINVAL; 434 } 435 } 436 437 return 0; 438 } 439 440 static int 441 agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical) 442 { 443 struct agp_i810_softc *isc = sc->as_chipc; 444 445 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) { 446 #ifdef DEBUG 447 printf("%s: failed: offset 0x%08x, shift %d, entries %d\n", 448 sc->as_dev.dv_xname, (int)offset, AGP_PAGE_SHIFT, 449 isc->gatt->ag_entries); 450 #endif 451 return EINVAL; 452 } 453 454 if (isc->chiptype != CHIP_I830) { 455 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 456 #ifdef DEBUG 457 printf("%s: trying to bind into stolen memory", 458 sc->as_dev.dv_xname); 459 #endif 460 return EINVAL; 461 } 462 } 463 464 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 465 physical | 1); 466 return 0; 467 } 468 469 static int 470 agp_i810_unbind_page(struct agp_softc *sc, off_t offset) 471 { 472 struct agp_i810_softc *isc = sc->as_chipc; 473 474 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 475 return EINVAL; 476 477 if (isc->chiptype != CHIP_I810 ) { 478 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 479 #ifdef DEBUG 480 printf("%s: trying to unbind from stolen memory", 481 sc->as_dev.dv_xname); 482 #endif 483 return EINVAL; 484 } 485 } 486 487 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 0); 488 return 0; 489 } 490 491 /* 492 * Writing via memory mapped registers already flushes all TLBs. 493 */ 494 static void 495 agp_i810_flush_tlb(struct agp_softc *sc) 496 { 497 } 498 499 static int 500 agp_i810_enable(struct agp_softc *sc, u_int32_t mode) 501 { 502 503 return 0; 504 } 505 506 static struct agp_memory * 507 agp_i810_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 508 { 509 struct agp_i810_softc *isc = sc->as_chipc; 510 struct agp_memory *mem; 511 512 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 513 return 0; 514 515 if (sc->as_allocated + size > sc->as_maxmem) 516 return 0; 517 518 if (type == 1) { 519 /* 520 * Mapping local DRAM into GATT. 521 */ 522 if (isc->chiptype != CHIP_I810 ) 523 return 0; 524 if (size != isc->dcache_size) 525 return 0; 526 } else if (type == 2) { 527 /* 528 * Bogus mapping of a single page for the hardware cursor. 529 */ 530 if (size != AGP_PAGE_SIZE) 531 return 0; 532 } 533 534 mem = malloc(sizeof *mem, M_AGP, M_WAITOK|M_ZERO); 535 if (mem == NULL) 536 return NULL; 537 mem->am_id = sc->as_nextid++; 538 mem->am_size = size; 539 mem->am_type = type; 540 541 if (type == 2) { 542 /* 543 * Allocate and wire down the page now so that we can 544 * get its physical address. 545 */ 546 mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_AGP, 547 M_WAITOK); 548 if (mem->am_dmaseg == NULL) { 549 free(mem, M_AGP); 550 return NULL; 551 } 552 if (agp_alloc_dmamem(sc->as_dmat, size, 0, 553 &mem->am_dmamap, &mem->am_virtual, &mem->am_physical, 554 mem->am_dmaseg, 1, &mem->am_nseg) != 0) { 555 free(mem->am_dmaseg, M_AGP); 556 free(mem, M_AGP); 557 return NULL; 558 } 559 } else if (type != 1) { 560 if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1, 561 size, 0, BUS_DMA_NOWAIT, 562 &mem->am_dmamap) != 0) { 563 free(mem, M_AGP); 564 return NULL; 565 } 566 } 567 568 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 569 sc->as_allocated += size; 570 571 return mem; 572 } 573 574 static int 575 agp_i810_free_memory(struct agp_softc *sc, struct agp_memory *mem) 576 { 577 if (mem->am_is_bound) 578 return EBUSY; 579 580 if (mem->am_type == 2) { 581 agp_free_dmamem(sc->as_dmat, mem->am_size, mem->am_dmamap, 582 mem->am_virtual, mem->am_dmaseg, mem->am_nseg); 583 free(mem->am_dmaseg, M_AGP); 584 } 585 586 sc->as_allocated -= mem->am_size; 587 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 588 free(mem, M_AGP); 589 return 0; 590 } 591 592 static int 593 agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 594 off_t offset) 595 { 596 struct agp_i810_softc *isc = sc->as_chipc; 597 u_int32_t regval, i; 598 599 /* 600 * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the 601 * X server for mysterious reasons which leads to crashes if we write 602 * to the GTT through the MMIO window. 603 * Until the issue is solved, simply restore it. 604 */ 605 regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL); 606 if (regval != (isc->gatt->ag_physical | 1)) { 607 printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n", 608 regval); 609 bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL, 610 isc->gatt->ag_physical | 1); 611 } 612 613 if (mem->am_type == 2) { 614 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 615 mem->am_physical | 1); 616 mem->am_offset = offset; 617 mem->am_is_bound = 1; 618 return 0; 619 } 620 621 if (mem->am_type != 1) 622 return agp_generic_bind_memory(sc, mem, offset); 623 624 if (isc->chiptype != CHIP_I810) 625 return EINVAL; 626 627 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { 628 WRITE4(AGP_I810_GTT + (u_int32_t)(offset >> AGP_PAGE_SHIFT) * 4, 629 i | 3); 630 } 631 mem->am_is_bound = 1; 632 return 0; 633 } 634 635 static int 636 agp_i810_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 637 { 638 struct agp_i810_softc *isc = sc->as_chipc; 639 u_int32_t i; 640 641 if (mem->am_type == 2) { 642 WRITE4(AGP_I810_GTT + 643 (u_int32_t)(mem->am_offset >> AGP_PAGE_SHIFT) * 4, 644 0); 645 mem->am_offset = 0; 646 mem->am_is_bound = 0; 647 return 0; 648 } 649 650 if (mem->am_type != 1) 651 return agp_generic_unbind_memory(sc, mem); 652 653 if (isc->chiptype != CHIP_I810) 654 return EINVAL; 655 656 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 657 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0); 658 mem->am_is_bound = 0; 659 return 0; 660 } 661