1 /*- 2 * Copyright (c) 2000 Doug Rabson 3 * Copyright (c) 2000 Ruslan Ermilov 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include "opt_bus.h" 31 #include "opt_pci.h" 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 #include <sys/kernel.h> 37 #include <sys/bus.h> 38 #include <sys/lock.h> 39 #include <sys/mutex.h> 40 #include <sys/proc.h> 41 42 #include <pci/pcivar.h> 43 #include <pci/pcireg.h> 44 #include <pci/agppriv.h> 45 #include <pci/agpreg.h> 46 47 #include <vm/vm.h> 48 #include <vm/vm_object.h> 49 #include <vm/vm_page.h> 50 #include <vm/vm_pageout.h> 51 #include <vm/pmap.h> 52 53 #include <machine/bus.h> 54 #include <machine/resource.h> 55 #include <sys/rman.h> 56 57 MALLOC_DECLARE(M_AGP); 58 59 #define READ1(off) bus_space_read_1(sc->bst, sc->bsh, off) 60 #define WRITE4(off,v) bus_space_write_4(sc->bst, sc->bsh, off, v) 61 62 struct agp_i810_softc { 63 struct agp_softc agp; 64 u_int32_t initial_aperture; /* aperture size at startup */ 65 struct agp_gatt *gatt; 66 u_int32_t dcache_size; 67 device_t bdev; /* bridge device */ 68 struct resource *regs; /* memory mapped GC registers */ 69 bus_space_tag_t bst; /* bus_space tag */ 70 bus_space_handle_t bsh; /* bus_space handle */ 71 }; 72 73 static const char* 74 agp_i810_match(device_t dev) 75 { 76 if (pci_get_class(dev) != PCIC_DISPLAY 77 || pci_get_subclass(dev) != PCIS_DISPLAY_VGA) 78 return NULL; 79 80 switch (pci_get_devid(dev)) { 81 case 0x71218086: 82 return ("Intel 82810 (i810 GMCH) SVGA controller"); 83 84 case 0x71238086: 85 return ("Intel 82810-DC100 (i810-DC100 GMCH) SVGA controller"); 86 87 case 0x71258086: 88 return ("Intel 82810E (i810E GMCH) SVGA controller"); 89 90 case 0x11328086: 91 return ("Intel 82815 (i815 GMCH) SVGA controller"); 92 }; 93 94 return NULL; 95 } 96 97 /* 98 * Find bridge device. 99 */ 100 static device_t 101 agp_i810_find_bridge(device_t dev) 102 { 103 device_t *children, child; 104 int nchildren, i; 105 u_int32_t devid; 106 107 /* 108 * Calculate bridge device's ID. 109 */ 110 devid = pci_get_devid(dev); 111 switch (devid) { 112 case 0x71218086: 113 case 0x71238086: 114 case 0x71258086: 115 devid -= 0x10000; 116 break; 117 118 case 0x11328086: 119 devid = 0x11308086; 120 break; 121 }; 122 if (device_get_children(device_get_parent(dev), &children, &nchildren)) 123 return 0; 124 125 for (i = 0; i < nchildren; i++) { 126 child = children[i]; 127 128 if (pci_get_devid(child) == devid) { 129 free(children, M_TEMP); 130 return child; 131 } 132 } 133 free(children, M_TEMP); 134 return 0; 135 } 136 137 static int 138 agp_i810_probe(device_t dev) 139 { 140 const char *desc; 141 142 desc = agp_i810_match(dev); 143 if (desc) { 144 device_t bdev; 145 u_int8_t smram; 146 147 bdev = agp_i810_find_bridge(dev); 148 if (!bdev) { 149 if (bootverbose) 150 printf("I810: can't find bridge device\n"); 151 return ENXIO; 152 } 153 154 smram = pci_read_config(bdev, AGP_I810_SMRAM, 1); 155 if ((smram & AGP_I810_SMRAM_GMS) 156 == AGP_I810_SMRAM_GMS_DISABLED) { 157 if (bootverbose) 158 printf("I810: disabled, not probing\n"); 159 return ENXIO; 160 } 161 162 device_verbose(dev); 163 device_set_desc(dev, desc); 164 return 0; 165 } 166 167 return ENXIO; 168 } 169 170 static int 171 agp_i810_attach(device_t dev) 172 { 173 struct agp_i810_softc *sc = device_get_softc(dev); 174 struct agp_gatt *gatt; 175 int error, rid; 176 177 sc->bdev = agp_i810_find_bridge(dev); 178 if (!sc->bdev) 179 return ENOENT; 180 181 error = agp_generic_attach(dev); 182 if (error) 183 return error; 184 185 rid = AGP_I810_MMADR; 186 sc->regs = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 187 0, ~0, 1, RF_ACTIVE); 188 if (!sc->regs) { 189 agp_generic_detach(dev); 190 return ENOMEM; 191 } 192 sc->bst = rman_get_bustag(sc->regs); 193 sc->bsh = rman_get_bushandle(sc->regs); 194 195 sc->initial_aperture = AGP_GET_APERTURE(dev); 196 197 if (READ1(AGP_I810_DRT) & AGP_I810_DRT_POPULATED) 198 sc->dcache_size = 4 * 1024 * 1024; 199 else 200 sc->dcache_size = 0; 201 202 for (;;) { 203 gatt = agp_alloc_gatt(dev); 204 if (gatt) 205 break; 206 207 /* 208 * Probably contigmalloc failure. Try reducing the 209 * aperture so that the gatt size reduces. 210 */ 211 if (AGP_SET_APERTURE(dev, AGP_GET_APERTURE(dev) / 2)) { 212 agp_generic_detach(dev); 213 return ENOMEM; 214 } 215 } 216 sc->gatt = gatt; 217 218 /* Install the GATT. */ 219 WRITE4(AGP_I810_PGTBL_CTL, gatt->ag_physical | 1); 220 221 /* 222 * Make sure the chipset can see everything. 223 */ 224 agp_flush_cache(); 225 226 return 0; 227 } 228 229 static int 230 agp_i810_detach(device_t dev) 231 { 232 struct agp_i810_softc *sc = device_get_softc(dev); 233 int error; 234 235 error = agp_generic_detach(dev); 236 if (error) 237 return error; 238 239 /* Clear the GATT base. */ 240 WRITE4(AGP_I810_PGTBL_CTL, 0); 241 242 /* Put the aperture back the way it started. */ 243 AGP_SET_APERTURE(dev, sc->initial_aperture); 244 245 agp_free_gatt(sc->gatt); 246 247 bus_release_resource(dev, SYS_RES_MEMORY, 248 AGP_I810_MMADR, sc->regs); 249 250 return 0; 251 } 252 253 static u_int32_t 254 agp_i810_get_aperture(device_t dev) 255 { 256 struct agp_i810_softc *sc = device_get_softc(dev); 257 u_int16_t miscc; 258 259 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2); 260 if ((miscc & AGP_I810_MISCC_WINSIZE) == AGP_I810_MISCC_WINSIZE_32) 261 return 32 * 1024 * 1024; 262 else 263 return 64 * 1024 * 1024; 264 } 265 266 static int 267 agp_i810_set_aperture(device_t dev, u_int32_t aperture) 268 { 269 struct agp_i810_softc *sc = device_get_softc(dev); 270 u_int16_t miscc; 271 272 /* 273 * Double check for sanity. 274 */ 275 if (aperture != 32 * 1024 * 1024 && aperture != 64 * 1024 * 1024) { 276 device_printf(dev, "bad aperture size %d\n", aperture); 277 return EINVAL; 278 } 279 280 miscc = pci_read_config(sc->bdev, AGP_I810_MISCC, 2); 281 miscc &= ~AGP_I810_MISCC_WINSIZE; 282 if (aperture == 32 * 1024 * 1024) 283 miscc |= AGP_I810_MISCC_WINSIZE_32; 284 else 285 miscc |= AGP_I810_MISCC_WINSIZE_64; 286 287 pci_write_config(sc->bdev, AGP_I810_MISCC, miscc, 2); 288 289 return 0; 290 } 291 292 static int 293 agp_i810_bind_page(device_t dev, int offset, vm_offset_t physical) 294 { 295 struct agp_i810_softc *sc = device_get_softc(dev); 296 297 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 298 return EINVAL; 299 300 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, physical | 1); 301 return 0; 302 } 303 304 static int 305 agp_i810_unbind_page(device_t dev, int offset) 306 { 307 struct agp_i810_softc *sc = device_get_softc(dev); 308 309 if (offset < 0 || offset >= (sc->gatt->ag_entries << AGP_PAGE_SHIFT)) 310 return EINVAL; 311 312 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 0); 313 return 0; 314 } 315 316 /* 317 * Writing via memory mapped registers already flushes all TLBs. 318 */ 319 static void 320 agp_i810_flush_tlb(device_t dev) 321 { 322 } 323 324 static int 325 agp_i810_enable(device_t dev, u_int32_t mode) 326 { 327 328 return 0; 329 } 330 331 static struct agp_memory * 332 agp_i810_alloc_memory(device_t dev, int type, vm_size_t size) 333 { 334 struct agp_i810_softc *sc = device_get_softc(dev); 335 struct agp_memory *mem; 336 337 if ((size & (AGP_PAGE_SIZE - 1)) != 0) 338 return 0; 339 340 if (sc->agp.as_allocated + size > sc->agp.as_maxmem) 341 return 0; 342 343 if (type == 1) { 344 /* 345 * Mapping local DRAM into GATT. 346 */ 347 if (size != sc->dcache_size) 348 return 0; 349 } else if (type == 2) { 350 /* 351 * Bogus mapping of a single page for the hardware cursor. 352 */ 353 if (size != AGP_PAGE_SIZE) 354 return 0; 355 } 356 357 mem = malloc(sizeof *mem, M_AGP, M_WAITOK); 358 mem->am_id = sc->agp.as_nextid++; 359 mem->am_size = size; 360 mem->am_type = type; 361 if (type != 1) 362 mem->am_obj = vm_object_allocate(OBJT_DEFAULT, 363 atop(round_page(size))); 364 else 365 mem->am_obj = 0; 366 367 if (type == 2) { 368 /* 369 * Allocate and wire down the page now so that we can 370 * get its physical address. 371 */ 372 vm_page_t m; 373 m = vm_page_grab(mem->am_obj, 0, VM_ALLOC_ZERO|VM_ALLOC_RETRY); 374 if ((m->flags & PG_ZERO) == 0) 375 vm_page_zero_fill(m); 376 vm_page_lock_queues(); 377 vm_page_wire(m); 378 mem->am_physical = VM_PAGE_TO_PHYS(m); 379 vm_page_wakeup(m); 380 vm_page_unlock_queues(); 381 } else { 382 mem->am_physical = 0; 383 } 384 385 mem->am_offset = 0; 386 mem->am_is_bound = 0; 387 TAILQ_INSERT_TAIL(&sc->agp.as_memory, mem, am_link); 388 sc->agp.as_allocated += size; 389 390 return mem; 391 } 392 393 static int 394 agp_i810_free_memory(device_t dev, struct agp_memory *mem) 395 { 396 struct agp_i810_softc *sc = device_get_softc(dev); 397 398 if (mem->am_is_bound) 399 return EBUSY; 400 401 if (mem->am_type == 2) { 402 /* 403 * Unwire the page which we wired in alloc_memory. 404 */ 405 vm_page_t m = vm_page_lookup(mem->am_obj, 0); 406 vm_page_lock_queues(); 407 vm_page_unwire(m, 0); 408 vm_page_unlock_queues(); 409 } 410 411 sc->agp.as_allocated -= mem->am_size; 412 TAILQ_REMOVE(&sc->agp.as_memory, mem, am_link); 413 if (mem->am_obj) 414 vm_object_deallocate(mem->am_obj); 415 free(mem, M_AGP); 416 return 0; 417 } 418 419 static int 420 agp_i810_bind_memory(device_t dev, struct agp_memory *mem, 421 vm_offset_t offset) 422 { 423 struct agp_i810_softc *sc = device_get_softc(dev); 424 vm_offset_t i; 425 426 if (mem->am_type != 1) 427 return agp_generic_bind_memory(dev, mem, offset); 428 429 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) { 430 WRITE4(AGP_I810_GTT + (offset >> AGP_PAGE_SHIFT) * 4, 431 i | 3); 432 } 433 434 return 0; 435 } 436 437 static int 438 agp_i810_unbind_memory(device_t dev, struct agp_memory *mem) 439 { 440 struct agp_i810_softc *sc = device_get_softc(dev); 441 vm_offset_t i; 442 443 if (mem->am_type != 1) 444 return agp_generic_unbind_memory(dev, mem); 445 446 for (i = 0; i < mem->am_size; i += AGP_PAGE_SIZE) 447 WRITE4(AGP_I810_GTT + (i >> AGP_PAGE_SHIFT) * 4, 0); 448 449 return 0; 450 } 451 452 static device_method_t agp_i810_methods[] = { 453 /* Device interface */ 454 DEVMETHOD(device_probe, agp_i810_probe), 455 DEVMETHOD(device_attach, agp_i810_attach), 456 DEVMETHOD(device_detach, agp_i810_detach), 457 DEVMETHOD(device_shutdown, bus_generic_shutdown), 458 DEVMETHOD(device_suspend, bus_generic_suspend), 459 DEVMETHOD(device_resume, bus_generic_resume), 460 461 /* AGP interface */ 462 DEVMETHOD(agp_get_aperture, agp_i810_get_aperture), 463 DEVMETHOD(agp_set_aperture, agp_i810_set_aperture), 464 DEVMETHOD(agp_bind_page, agp_i810_bind_page), 465 DEVMETHOD(agp_unbind_page, agp_i810_unbind_page), 466 DEVMETHOD(agp_flush_tlb, agp_i810_flush_tlb), 467 DEVMETHOD(agp_enable, agp_i810_enable), 468 DEVMETHOD(agp_alloc_memory, agp_i810_alloc_memory), 469 DEVMETHOD(agp_free_memory, agp_i810_free_memory), 470 DEVMETHOD(agp_bind_memory, agp_i810_bind_memory), 471 DEVMETHOD(agp_unbind_memory, agp_i810_unbind_memory), 472 473 { 0, 0 } 474 }; 475 476 static driver_t agp_i810_driver = { 477 "agp", 478 agp_i810_methods, 479 sizeof(struct agp_i810_softc), 480 }; 481 482 static devclass_t agp_devclass; 483 484 DRIVER_MODULE(agp_i810, pci, agp_i810_driver, agp_devclass, 0, 0); 485