1 /* $NetBSD: agp_i810.c,v 1.28 2006/01/16 22:59:36 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.28 2006/01/16 22:59:36 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 #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 int dummyseg; 253 /* Some i810s have on-chip memory called dcache */ 254 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 255 isc->dcache_size = 4 * 1024 * 1024; 256 else 257 isc->dcache_size = 0; 258 259 /* According to the specs the gatt on the i810 must be 64k */ 260 if (agp_alloc_dmamem(sc->as_dmat, 64 * 1024, 261 0, &gatt->ag_dmamap, (caddr_t *)&gatt->ag_virtual, 262 &gatt->ag_physical, &gatt->ag_dmaseg, 1, &dummyseg) != 0) { 263 free(gatt, M_AGP); 264 agp_generic_detach(sc); 265 return ENOMEM; 266 } 267 268 gatt->ag_size = gatt->ag_entries * sizeof(u_int32_t); 269 memset(gatt->ag_virtual, 0, gatt->ag_size); 270 271 agp_flush_cache(); 272 /* Install the GATT. */ 273 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 274 } else if (isc->chiptype == CHIP_I830) { 275 /* The i830 automatically initializes the 128k gatt on boot. */ 276 pcireg_t reg; 277 u_int32_t pgtblctl; 278 u_int16_t gcc1; 279 280 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 281 gcc1 = (u_int16_t)(reg >> 16); 282 switch (gcc1 & AGP_I830_GCC1_GMS) { 283 case AGP_I830_GCC1_GMS_STOLEN_512: 284 isc->stolen = (512 - 132) * 1024 / 4096; 285 break; 286 case AGP_I830_GCC1_GMS_STOLEN_1024: 287 isc->stolen = (1024 - 132) * 1024 / 4096; 288 break; 289 case AGP_I830_GCC1_GMS_STOLEN_8192: 290 isc->stolen = (8192 - 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 } else if (isc->chiptype == CHIP_I855) { 311 /* The 855GM automatically initializes the 128k gatt on boot. */ 312 pcireg_t reg; 313 u_int32_t pgtblctl; 314 u_int16_t gcc1; 315 316 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I855_GCC1); 317 gcc1 = (u_int16_t)(reg >> 16); 318 switch (gcc1 & AGP_I855_GCC1_GMS) { 319 case AGP_I855_GCC1_GMS_STOLEN_1M: 320 isc->stolen = (1024 - 132) * 1024 / 4096; 321 break; 322 case AGP_I855_GCC1_GMS_STOLEN_4M: 323 isc->stolen = (4096 - 132) * 1024 / 4096; 324 break; 325 case AGP_I855_GCC1_GMS_STOLEN_8M: 326 isc->stolen = (8192 - 132) * 1024 / 4096; 327 break; 328 case AGP_I855_GCC1_GMS_STOLEN_16M: 329 isc->stolen = (16384 - 132) * 1024 / 4096; 330 break; 331 case AGP_I855_GCC1_GMS_STOLEN_32M: 332 isc->stolen = (32768 - 132) * 1024 / 4096; 333 break; 334 default: 335 isc->stolen = 0; 336 aprint_error( 337 ": unknown memory configuration, disabling\n"); 338 agp_generic_detach(sc); 339 return EINVAL; 340 } 341 if (isc->stolen > 0) { 342 aprint_error(": detected %dk stolen memory\n%s", 343 isc->stolen * 4, sc->as_dev.dv_xname); 344 } 345 346 /* GATT address is already in there, make sure it's enabled */ 347 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 348 pgtblctl |= 1; 349 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 350 351 gatt->ag_physical = pgtblctl & ~1; 352 } else { /* CHIP_I915 */ 353 /* The 915G automatically initializes the 256k gatt on boot. */ 354 pcireg_t reg; 355 u_int32_t pgtblctl; 356 u_int16_t gcc1; 357 358 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_GCC1); 359 gcc1 = (u_int16_t)(reg >> 16); 360 switch (gcc1 & AGP_I915_GCC1_GMS) { 361 case AGP_I915_GCC1_GMS_STOLEN_0M: 362 isc->stolen = 0; 363 break; 364 case AGP_I915_GCC1_GMS_STOLEN_1M: 365 isc->stolen = (1024 - 260) * 1024 / 4096; 366 break; 367 case AGP_I915_GCC1_GMS_STOLEN_8M: 368 isc->stolen = (8192 - 260) * 1024 / 4096; 369 break; 370 default: 371 isc->stolen = 0; 372 aprint_error( 373 ": unknown memory configuration, disabling\n"); 374 agp_generic_detach(sc); 375 return EINVAL; 376 } 377 if (isc->stolen > 0) { 378 aprint_error(": detected %dk stolen memory\n%s", 379 isc->stolen * 4, sc->as_dev.dv_xname); 380 } 381 382 /* GATT address is already in there, make sure it's enabled */ 383 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 384 pgtblctl |= 1; 385 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 386 387 gatt->ag_physical = pgtblctl & ~1; 388 } 389 390 /* 391 * Make sure the chipset can see everything. 392 */ 393 agp_flush_cache(); 394 395 isc->sc_powerhook = powerhook_establish(agp_i810_powerhook, sc); 396 if (isc->sc_powerhook == NULL) 397 printf("%s: WARNING: unable to establish PCI power hook\n", 398 sc->as_dev.dv_xname); 399 400 return 0; 401 } 402 403 #if 0 404 static int 405 agp_i810_detach(struct agp_softc *sc) 406 { 407 int error; 408 struct agp_i810_softc *isc = sc->as_chipc; 409 410 error = agp_generic_detach(sc); 411 if (error) 412 return error; 413 414 /* Clear the GATT base. */ 415 if (sc->chiptype == CHIP_I810) { 416 WRITE4(AGP_I810_PGTBL_CTL, 0); 417 } else { 418 unsigned int pgtblctl; 419 pgtblctl = READ4(AGP_I810_PGTBL_CTL); 420 pgtblctl &= ~1; 421 WRITE4(AGP_I810_PGTBL_CTL, pgtblctl); 422 } 423 424 /* Put the aperture back the way it started. */ 425 AGP_SET_APERTURE(sc, isc->initial_aperture); 426 427 if (sc->chiptype == CHIP_I810) { 428 agp_free_dmamem(sc->as_dmat, gatt->ag_size, gatt->ag_dmamap, 429 (caddr_t)gatt->ag_virtual, &gatt->ag_dmaseg, 1); 430 } 431 free(sc->gatt, M_AGP); 432 433 return 0; 434 } 435 #endif 436 437 static u_int32_t 438 agp_i810_get_aperture(struct agp_softc *sc) 439 { 440 struct agp_i810_softc *isc = sc->as_chipc; 441 pcireg_t reg; 442 443 if (isc->chiptype == CHIP_I810) { 444 u_int16_t miscc; 445 446 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 447 miscc = (u_int16_t)(reg >> 16); 448 if ((miscc & AGP_I810_MISCC_WINSIZE) == 449 AGP_I810_MISCC_WINSIZE_32) 450 return 32 * 1024 * 1024; 451 else 452 return 64 * 1024 * 1024; 453 } else if (isc->chiptype == CHIP_I830) { 454 u_int16_t gcc1; 455 456 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 457 gcc1 = (u_int16_t)(reg >> 16); 458 if ((gcc1 & AGP_I830_GCC1_GMASIZE) == AGP_I830_GCC1_GMASIZE_64) 459 return 64 * 1024 * 1024; 460 else 461 return 128 * 1024 * 1024; 462 } else if (isc->chiptype == CHIP_I855) { 463 return 128 * 1024 * 1024; 464 } else { /* CHIP_I915 */ 465 u_int16_t msac; 466 467 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I915_MSAC); 468 msac = (u_int16_t)(reg >> 16); 469 if (msac & AGP_I915_MSAC_APER_128M) 470 return 128 * 1024 * 1024; 471 else 472 return 256 * 1024 * 1024; 473 } 474 } 475 476 static int 477 agp_i810_set_aperture(struct agp_softc *sc, u_int32_t aperture) 478 { 479 struct agp_i810_softc *isc = sc->as_chipc; 480 pcireg_t reg; 481 482 if (isc->chiptype == CHIP_I810) { 483 u_int16_t miscc; 484 485 /* 486 * Double check for sanity. 487 */ 488 if (aperture != (32 * 1024 * 1024) && 489 aperture != (64 * 1024 * 1024)) { 490 printf("%s: bad aperture size %d\n", 491 sc->as_dev.dv_xname, aperture); 492 return EINVAL; 493 } 494 495 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I810_SMRAM); 496 miscc = (u_int16_t)(reg >> 16); 497 miscc &= ~AGP_I810_MISCC_WINSIZE; 498 if (aperture == 32 * 1024 * 1024) 499 miscc |= AGP_I810_MISCC_WINSIZE_32; 500 else 501 miscc |= AGP_I810_MISCC_WINSIZE_64; 502 503 reg &= 0x0000ffff; 504 reg |= ((pcireg_t)miscc) << 16; 505 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I810_SMRAM, reg); 506 } else if (isc->chiptype == CHIP_I830) { 507 u_int16_t gcc1; 508 509 if (aperture != (64 * 1024 * 1024) && 510 aperture != (128 * 1024 * 1024)) { 511 printf("%s: bad aperture size %d\n", 512 sc->as_dev.dv_xname, aperture); 513 return EINVAL; 514 } 515 reg = pci_conf_read(sc->as_pc, sc->as_tag, AGP_I830_GCC0); 516 gcc1 = (u_int16_t)(reg >> 16); 517 gcc1 &= ~AGP_I830_GCC1_GMASIZE; 518 if (aperture == 64 * 1024 * 1024) 519 gcc1 |= AGP_I830_GCC1_GMASIZE_64; 520 else 521 gcc1 |= AGP_I830_GCC1_GMASIZE_128; 522 523 reg &= 0x0000ffff; 524 reg |= ((pcireg_t)gcc1) << 16; 525 pci_conf_write(sc->as_pc, sc->as_tag, AGP_I830_GCC0, reg); 526 } else { /* CHIP_I855 or CHIP_I915 */ 527 if (aperture != agp_i810_get_aperture(sc)) { 528 printf("%s: bad aperture size %d\n", 529 sc->as_dev.dv_xname, aperture); 530 return EINVAL; 531 } 532 } 533 534 return 0; 535 } 536 537 static int 538 agp_i810_bind_page(struct agp_softc *sc, off_t offset, bus_addr_t physical) 539 { 540 struct agp_i810_softc *isc = sc->as_chipc; 541 542 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) { 543 #ifdef DEBUG 544 printf("%s: failed: offset 0x%08x, shift %d, entries %d\n", 545 sc->as_dev.dv_xname, (int)offset, AGP_PAGE_SHIFT, 546 isc->gatt->ag_entries); 547 #endif 548 return EINVAL; 549 } 550 551 if (isc->chiptype != CHIP_I830) { 552 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 553 #ifdef DEBUG 554 printf("%s: trying to bind into stolen memory", 555 sc->as_dev.dv_xname); 556 #endif 557 return EINVAL; 558 } 559 } 560 561 WRITEGTT(offset, physical | 1); 562 return 0; 563 } 564 565 static int 566 agp_i810_unbind_page(struct agp_softc *sc, off_t offset) 567 { 568 struct agp_i810_softc *isc = sc->as_chipc; 569 570 if (offset < 0 || offset >= (isc->gatt->ag_entries << AGP_PAGE_SHIFT)) 571 return EINVAL; 572 573 if (isc->chiptype != CHIP_I810 ) { 574 if ((offset >> AGP_PAGE_SHIFT) < isc->stolen) { 575 #ifdef DEBUG 576 printf("%s: trying to unbind from stolen memory", 577 sc->as_dev.dv_xname); 578 #endif 579 return EINVAL; 580 } 581 } 582 583 WRITEGTT(offset, 0); 584 return 0; 585 } 586 587 /* 588 * Writing via memory mapped registers already flushes all TLBs. 589 */ 590 static void 591 agp_i810_flush_tlb(struct agp_softc *sc) 592 { 593 } 594 595 static int 596 agp_i810_enable(struct agp_softc *sc, u_int32_t mode) 597 { 598 599 return 0; 600 } 601 602 static struct agp_memory * 603 agp_i810_alloc_memory(struct agp_softc *sc, int type, vsize_t size) 604 { 605 struct agp_i810_softc *isc = sc->as_chipc; 606 struct agp_memory *mem; 607 608 #ifdef DEBUG 609 printf("AGP: alloc(%d, 0x%x)\n", type, (int) size); 610 #endif 611 612 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 613 return 0; 614 615 if (sc->as_allocated + size > sc->as_maxmem) 616 return 0; 617 618 if (type == 1) { 619 /* 620 * Mapping local DRAM into GATT. 621 */ 622 if (isc->chiptype != CHIP_I810 ) 623 return 0; 624 if (size != isc->dcache_size) 625 return 0; 626 } else if (type == 2) { 627 /* 628 * Bogus mapping for the hardware cursor. 629 */ 630 if (size != AGP_PAGE_SIZE && size != 4 * AGP_PAGE_SIZE) 631 return 0; 632 } 633 634 mem = malloc(sizeof *mem, M_AGP, M_WAITOK|M_ZERO); 635 if (mem == NULL) 636 return NULL; 637 mem->am_id = sc->as_nextid++; 638 mem->am_size = size; 639 mem->am_type = type; 640 641 if (type == 2) { 642 /* 643 * Allocate and wire down the memory now so that we can 644 * get its physical address. 645 */ 646 mem->am_dmaseg = malloc(sizeof *mem->am_dmaseg, M_AGP, 647 M_WAITOK); 648 if (mem->am_dmaseg == NULL) { 649 free(mem, M_AGP); 650 return NULL; 651 } 652 if (agp_alloc_dmamem(sc->as_dmat, size, 0, 653 &mem->am_dmamap, &mem->am_virtual, &mem->am_physical, 654 mem->am_dmaseg, 1, &mem->am_nseg) != 0) { 655 free(mem->am_dmaseg, M_AGP); 656 free(mem, M_AGP); 657 return NULL; 658 } 659 memset(mem->am_virtual, 0, size); 660 } else if (type != 1) { 661 if (bus_dmamap_create(sc->as_dmat, size, size / PAGE_SIZE + 1, 662 size, 0, BUS_DMA_NOWAIT, 663 &mem->am_dmamap) != 0) { 664 free(mem, M_AGP); 665 return NULL; 666 } 667 } 668 669 TAILQ_INSERT_TAIL(&sc->as_memory, mem, am_link); 670 sc->as_allocated += size; 671 672 return mem; 673 } 674 675 static int 676 agp_i810_free_memory(struct agp_softc *sc, struct agp_memory *mem) 677 { 678 if (mem->am_is_bound) 679 return EBUSY; 680 681 if (mem->am_type == 2) { 682 agp_free_dmamem(sc->as_dmat, mem->am_size, mem->am_dmamap, 683 mem->am_virtual, mem->am_dmaseg, mem->am_nseg); 684 free(mem->am_dmaseg, M_AGP); 685 } 686 687 sc->as_allocated -= mem->am_size; 688 TAILQ_REMOVE(&sc->as_memory, mem, am_link); 689 free(mem, M_AGP); 690 return 0; 691 } 692 693 static int 694 agp_i810_bind_memory(struct agp_softc *sc, struct agp_memory *mem, 695 off_t offset) 696 { 697 struct agp_i810_softc *isc = sc->as_chipc; 698 u_int32_t regval, i; 699 700 /* 701 * XXX evil hack: the PGTBL_CTL appearently gets overwritten by the 702 * X server for mysterious reasons which leads to crashes if we write 703 * to the GTT through the MMIO window. 704 * Until the issue is solved, simply restore it. 705 */ 706 regval = bus_space_read_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL); 707 if (regval != (isc->gatt->ag_physical | 1)) { 708 printf("agp_i810_bind_memory: PGTBL_CTL is 0x%x - fixing\n", 709 regval); 710 bus_space_write_4(isc->bst, isc->bsh, AGP_I810_PGTBL_CTL, 711 isc->gatt->ag_physical | 1); 712 } 713 714 if (mem->am_type == 2) { 715 WRITEGTT(offset, mem->am_physical | 1); 716 mem->am_offset = offset; 717 mem->am_is_bound = 1; 718 return 0; 719 } 720 721 if (mem->am_type != 1) 722 return agp_generic_bind_memory(sc, mem, offset); 723 724 if (isc->chiptype != CHIP_I810) 725 return EINVAL; 726 727 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 728 WRITEGTT(offset, i | 3); 729 mem->am_is_bound = 1; 730 return 0; 731 } 732 733 static int 734 agp_i810_unbind_memory(struct agp_softc *sc, struct agp_memory *mem) 735 { 736 struct agp_i810_softc *isc = sc->as_chipc; 737 u_int32_t i; 738 739 if (mem->am_type == 2) { 740 WRITEGTT(mem->am_offset, 0); 741 mem->am_offset = 0; 742 mem->am_is_bound = 0; 743 return 0; 744 } 745 746 if (mem->am_type != 1) 747 return agp_generic_unbind_memory(sc, mem); 748 749 if (isc->chiptype != CHIP_I810) 750 return EINVAL; 751 752 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 753 WRITEGTT(i, 0); 754 mem->am_is_bound = 0; 755 return 0; 756 } 757 758 static void 759 agp_i810_powerhook(int why, void *arg) 760 { 761 struct agp_softc *sc = (struct agp_softc *)arg; 762 struct agp_i810_softc *isc = sc->as_chipc; 763 764 if (why == PWR_RESUME) { 765 pci_conf_restore(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 766 agp_flush_cache(); 767 } else if ((why == PWR_STANDBY) || (why == PWR_SUSPEND)) 768 pci_conf_capture(sc->as_pc, sc->as_tag, &isc->sc_pciconf); 769 770 return; 771 } 772