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