1 /* 2 * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <AreaKeeper.h> 8 #include <intel_extreme.h> 9 10 #include <stdlib.h> 11 12 #include <AGP.h> 13 #include <KernelExport.h> 14 #include <PCI.h> 15 16 17 //#define TRACE_INTEL 18 #ifdef TRACE_INTEL 19 # define TRACE(x...) dprintf("\33[33magp-intel:\33[0m " x) 20 #else 21 # define TRACE(x...) ; 22 #endif 23 24 #ifndef __HAIKU__ 25 # define B_KERNEL_READ_AREA 0 26 # define B_KERNEL_WRITE_AREA 0 27 #endif 28 29 /* read and write to PCI config space */ 30 #define get_pci_config(info, offset, size) \ 31 (sPCI->read_pci_config((info).bus, (info).device, (info).function, \ 32 (offset), (size))) 33 #define set_pci_config(info, offset, size, value) \ 34 (sPCI->write_pci_config((info).bus, (info).device, (info).function, \ 35 (offset), (size), (value))) 36 #define write32(address, data) \ 37 (*((volatile uint32 *)(address)) = (data)) 38 #define read32(address) \ 39 (*((volatile uint32 *)(address))) 40 41 42 const struct supported_device { 43 uint32 bridge_id; 44 uint32 display_id; 45 uint32 type; 46 const char *name; 47 } kSupportedDevices[] = { 48 {0x3575, 0x3577, INTEL_TYPE_83x, "i830GM"}, 49 {0x2560, 0x2562, INTEL_TYPE_83x, "i845G"}, 50 {0x3580, 0x3582, INTEL_TYPE_85x, "i855G"}, 51 {0x2570, 0x2572, INTEL_TYPE_85x, "i865G"}, 52 53 // {0x2792, INTEL_TYPE_91x, "i910"}, 54 // {0x258a, INTEL_TYPE_91x, "i915"}, 55 {0x2580, 0x2582, INTEL_TYPE_91x, "i915G"}, 56 {0x2590, 0x2592, INTEL_TYPE_91x, "i915GM"}, 57 {0x2770, 0x2772, INTEL_TYPE_945, "i945G"}, 58 {0x27a0, 0x27a2, INTEL_TYPE_945, "i945GM"}, 59 {0x27ac, 0x27ae, INTEL_TYPE_945, "i945GME"}, 60 61 {0x2970, 0x2972, INTEL_TYPE_965, "i946GZ"}, 62 {0x2980, 0x2982, INTEL_TYPE_965, "i965G"}, 63 {0x2990, 0x2992, INTEL_TYPE_965, "i965Q"}, 64 {0x29a0, 0x29a2, INTEL_TYPE_965, "i965G"}, 65 {0x2a00, 0x2a02, INTEL_TYPE_965, "i965GM"}, 66 {0x2a10, 0x2a12, INTEL_TYPE_965, "i965GME"}, 67 68 {0x29b0, 0x29b2, INTEL_TYPE_G33, "G33"}, 69 {0x29c0, 0x29c2, INTEL_TYPE_G33, "Q35"}, 70 {0x29d0, 0x29d2, INTEL_TYPE_G33, "Q33"}, 71 72 {0x2a40, 0x2a42, INTEL_TYPE_GM45, "GM45"}, 73 }; 74 75 struct intel_info { 76 pci_info bridge; 77 pci_info display; 78 uint32 type; 79 80 uint32 *gtt_base; 81 addr_t gtt_physical_base; 82 area_id gtt_area; 83 size_t gtt_entries; 84 size_t gtt_stolen_entries; 85 86 vuint32 *registers; 87 area_id registers_area; 88 89 addr_t aperture_base; 90 addr_t aperture_physical_base; 91 area_id aperture_area; 92 size_t aperture_size; 93 size_t aperture_stolen_size; 94 95 addr_t scratch_page; 96 area_id scratch_area; 97 }; 98 99 static intel_info sInfo; 100 static pci_module_info *sPCI; 101 102 103 static bool 104 has_display_device(pci_info &info, uint32 deviceID) 105 { 106 for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK; 107 index++) { 108 if (info.vendor_id != VENDOR_ID_INTEL 109 || info.device_id != deviceID 110 || info.class_base != PCI_display) 111 continue; 112 113 return true; 114 } 115 116 return false; 117 } 118 119 120 static void 121 determine_memory_sizes(intel_info &info, size_t >tSize, size_t &stolenSize) 122 { 123 // read stolen memory from the PCI configuration of the PCI bridge 124 uint16 memoryConfig = get_pci_config(info.bridge, 125 INTEL_GRAPHICS_MEMORY_CONTROL, 2); 126 size_t memorySize = 1 << 20; // 1 MB 127 gttSize = 0; 128 stolenSize = 0; 129 130 if (info.type == INTEL_TYPE_965) { 131 switch (memoryConfig & i965_GTT_MASK) { 132 case i965_GTT_128K: 133 gttSize = 128 << 10; 134 break; 135 case i965_GTT_256K: 136 gttSize = 256 << 10; 137 break; 138 case i965_GTT_512K: 139 gttSize = 512 << 10; 140 break; 141 } 142 } else if (info.type == INTEL_TYPE_G33) { 143 switch (memoryConfig & G33_GTT_MASK) { 144 case G33_GTT_1M: 145 gttSize = 1 << 20; 146 break; 147 case G33_GTT_2M: 148 gttSize = 2 << 20; 149 break; 150 } 151 } else if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) { 152 switch (memoryConfig & G4X_GTT_MASK) { 153 case G4X_GTT_NONE: 154 gttSize = 0; 155 break; 156 case G4X_GTT_1M_NO_IVT: 157 gttSize = 1 << 20; 158 break; 159 case G4X_GTT_2M_NO_IVT: 160 case G4X_GTT_2M_IVT: 161 gttSize = 2 << 20; 162 break; 163 case G4X_GTT_3M_IVT: 164 gttSize = 3 << 20; 165 break; 166 case G4X_GTT_4M_IVT: 167 gttSize = 4 << 20; 168 break; 169 } 170 } else { 171 // older models have the GTT as large as their frame buffer mapping 172 // TODO: check if the i9xx version works with the i8xx chips as well 173 size_t frameBufferSize = 0; 174 if ((info.type & INTEL_TYPE_8xx) != 0) { 175 if (info.type == INTEL_TYPE_83x 176 && (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M) 177 frameBufferSize = 64 << 20; 178 else 179 frameBufferSize = 128 << 20; 180 } else if ((info.type & INTEL_TYPE_9xx) != 0) 181 frameBufferSize = info.display.u.h0.base_register_sizes[2]; 182 183 TRACE(("frame buffer size %lu MB\n", frameBufferSize >> 20)); 184 gttSize = frameBufferSize / 1024; 185 } 186 187 // TODO: test with different models! 188 189 if (info.type == INTEL_TYPE_83x) { 190 // Older chips 191 switch (memoryConfig & STOLEN_MEMORY_MASK) { 192 case i830_LOCAL_MEMORY_ONLY: 193 // TODO: determine its size! 194 dprintf("intel_gart: getting local memory size not implemented.\n"); 195 break; 196 case i830_STOLEN_512K: 197 memorySize >>= 1; 198 break; 199 case i830_STOLEN_1M: 200 // default case 201 break; 202 case i830_STOLEN_8M: 203 memorySize *= 8; 204 break; 205 } 206 } else if (info.type == INTEL_TYPE_85x 207 || (info.type & INTEL_TYPE_9xx) == INTEL_TYPE_9xx) { 208 switch (memoryConfig & STOLEN_MEMORY_MASK) { 209 case i855_STOLEN_MEMORY_4M: 210 memorySize *= 4; 211 break; 212 case i855_STOLEN_MEMORY_8M: 213 memorySize *= 8; 214 break; 215 case i855_STOLEN_MEMORY_16M: 216 memorySize *= 16; 217 break; 218 case i855_STOLEN_MEMORY_32M: 219 memorySize *= 32; 220 break; 221 case i855_STOLEN_MEMORY_48M: 222 memorySize *= 48; 223 break; 224 case i855_STOLEN_MEMORY_64M: 225 memorySize *= 64; 226 break; 227 case i855_STOLEN_MEMORY_128M: 228 memorySize *= 128; 229 break; 230 case i855_STOLEN_MEMORY_256M: 231 memorySize *= 256; 232 break; 233 case G4X_STOLEN_MEMORY_96MB: 234 memorySize *= 96; 235 break; 236 case G4X_STOLEN_MEMORY_160MB: 237 memorySize *= 160; 238 break; 239 case G4X_STOLEN_MEMORY_224MB: 240 memorySize *= 224; 241 break; 242 case G4X_STOLEN_MEMORY_352MB: 243 memorySize *= 352; 244 break; 245 } 246 } else { 247 // TODO: error out! 248 memorySize = 4096; 249 } 250 251 stolenSize = memorySize - 4096; 252 } 253 254 255 static void 256 set_gtt_entry(intel_info &info, uint32 offset, addr_t physicalAddress) 257 { 258 write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT), 259 (uint32)physicalAddress | GTT_ENTRY_VALID); 260 } 261 262 263 static void 264 intel_unmap(intel_info &info) 265 { 266 delete_area(info.registers_area); 267 delete_area(info.gtt_area); 268 delete_area(info.scratch_area); 269 delete_area(info.aperture_area); 270 info.aperture_size = 0; 271 } 272 273 274 static status_t 275 intel_map(intel_info &info) 276 { 277 int fbIndex = 0; 278 int mmioIndex = 1; 279 if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) { 280 // for some reason Intel saw the need to change the order of the mappings 281 // with the introduction of the i9xx family 282 mmioIndex = 0; 283 fbIndex = 2; 284 } 285 286 AreaKeeper mmioMapper; 287 info.registers_area = mmioMapper.Map("intel GMCH mmio", 288 (void *)info.display.u.h0.base_registers[mmioIndex], 289 info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS, 290 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.registers); 291 if (mmioMapper.InitCheck() < B_OK) { 292 dprintf("agp_intel: could not map memory I/O!\n"); 293 return info.registers_area; 294 } 295 296 // make sure bus master, memory-mapped I/O, and frame buffer is enabled 297 set_pci_config(info.display, PCI_command, 2, 298 get_pci_config(info.display, PCI_command, 2) 299 | PCI_command_io | PCI_command_memory | PCI_command_master); 300 301 void *scratchAddress; 302 AreaKeeper scratchCreator; 303 info.scratch_area = scratchCreator.Create("intel GMCH scratch", 304 &scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 305 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 306 if (scratchCreator.InitCheck() < B_OK) { 307 dprintf("agp_intel: could not create scratch page!\n"); 308 return info.scratch_area; 309 } 310 311 physical_entry entry; 312 if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK) 313 return B_ERROR; 314 315 if ((info.type & INTEL_TYPE_FAMILY_MASK) == INTEL_TYPE_9xx) { 316 if ((info.type & INTEL_TYPE_GROUP_MASK) == INTEL_TYPE_G4x) { 317 info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex] 318 + (2UL << 20); 319 } else 320 info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4); 321 } else { 322 info.gtt_physical_base = read32(info.registers 323 + INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED; 324 if (info.gtt_physical_base == 0) { 325 // TODO: not sure how this is supposed to work under Linux/FreeBSD, 326 // but on my i865, this code is needed for Haiku. 327 dprintf("intel_gart: Use GTT address fallback.\n"); 328 info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex] 329 + i830_GTT_BASE; 330 } 331 } 332 333 size_t gttSize, stolenSize; 334 determine_memory_sizes(info, gttSize, stolenSize); 335 336 info.gtt_entries = gttSize / 4096; 337 info.gtt_stolen_entries = stolenSize / 4096; 338 339 TRACE("GTT base %lx, size %lu, entries %lu, stolen %lu\n", info.gtt_physical_base, 340 gttSize, info.gtt_entries, stolenSize); 341 342 AreaKeeper gttMapper; 343 info.gtt_area = gttMapper.Map("intel GMCH gtt", 344 (void *)info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS, 345 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&info.gtt_base); 346 if (gttMapper.InitCheck() < B_OK) { 347 dprintf("intel_gart: could not map GTT!\n"); 348 return info.gtt_area; 349 } 350 351 info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex]; 352 info.aperture_stolen_size = stolenSize; 353 if (info.aperture_size == 0) 354 info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex]; 355 356 dprintf("intel_gart: detected %ld MB of stolen memory, aperture " 357 "size %ld MB, GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20, 358 info.aperture_size >> 20, gttSize >> 10); 359 360 dprintf("intel_gart: GTT base = 0x%lx\n", info.gtt_physical_base); 361 dprintf("intel_gart: MMIO base = 0x%lx\n", info.display.u.h0.base_registers[mmioIndex]); 362 dprintf("intel_gart: GMR base = 0x%lx\n", info.aperture_physical_base); 363 364 AreaKeeper apertureMapper; 365 info.aperture_area = apertureMapper.Map("intel graphics aperture", 366 (void *)info.aperture_physical_base, info.aperture_size, 367 B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, 368 B_READ_AREA | B_WRITE_AREA, (void **)&info.aperture_base); 369 if (apertureMapper.InitCheck() < B_OK) { 370 // try again without write combining 371 dprintf(DEVICE_NAME ": enabling write combined mode failed.\n"); 372 373 info.aperture_area = apertureMapper.Map("intel graphics aperture", 374 (void *)info.aperture_physical_base, info.aperture_size, 375 B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, 376 (void **)&info.aperture_base); 377 } 378 if (apertureMapper.InitCheck() < B_OK) { 379 dprintf(DEVICE_NAME ": could not map graphics aperture!\n"); 380 return info.aperture_area; 381 } 382 383 info.scratch_page = (addr_t)entry.address; 384 385 gttMapper.Detach(); 386 mmioMapper.Detach(); 387 scratchCreator.Detach(); 388 apertureMapper.Detach(); 389 390 return B_OK; 391 } 392 393 394 // #pragma mark - module interface 395 396 397 status_t 398 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size, 399 void **_aperture) 400 { 401 // TODO: we currently only support a single AGP bridge! 402 if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device 403 || function != sInfo.bridge.function) 404 && (bus != sInfo.display.bus || device != sInfo.display.device 405 || function != sInfo.display.function)) 406 return B_BAD_VALUE; 407 408 sInfo.aperture_size = size; 409 410 if (intel_map(sInfo) < B_OK) 411 return B_ERROR; 412 413 uint16 gmchControl = get_pci_config(sInfo.bridge, 414 INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED; 415 set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl); 416 417 write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL, 418 sInfo.gtt_physical_base | PAGE_TABLE_ENABLED); 419 read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL); 420 421 if (sInfo.scratch_page != 0) { 422 for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) { 423 set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page); 424 } 425 read32(sInfo.gtt_base + sInfo.gtt_entries - 1); 426 } 427 428 asm("wbinvd;"); 429 430 *_aperture = NULL; 431 return B_OK; 432 } 433 434 435 void 436 intel_delete_aperture(void *aperture) 437 { 438 intel_unmap(sInfo); 439 } 440 441 442 static status_t 443 intel_get_aperture_info(void *aperture, aperture_info *info) 444 { 445 if (info == NULL) 446 return B_BAD_VALUE; 447 448 info->base = sInfo.aperture_base; 449 info->physical_base = sInfo.aperture_physical_base; 450 info->size = sInfo.aperture_size; 451 info->reserved_size = sInfo.aperture_stolen_size; 452 453 return B_OK; 454 } 455 456 457 status_t 458 intel_set_aperture_size(void *aperture, size_t size) 459 { 460 return B_ERROR; 461 } 462 463 464 static status_t 465 intel_bind_page(void *aperture, uint32 offset, addr_t physicalAddress) 466 { 467 //TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress); 468 469 set_gtt_entry(sInfo, offset, physicalAddress); 470 return B_OK; 471 } 472 473 474 static status_t 475 intel_unbind_page(void *aperture, uint32 offset) 476 { 477 //TRACE("unbind_page(offset %lx)\n", offset); 478 479 if (sInfo.scratch_page != 0) 480 set_gtt_entry(sInfo, offset, sInfo.scratch_page); 481 482 return B_OK; 483 } 484 485 486 void 487 intel_flush_tlbs(void *aperture) 488 { 489 read32(sInfo.gtt_base + sInfo.gtt_entries - 1); 490 asm("wbinvd;"); 491 } 492 493 494 // #pragma mark - 495 496 497 static status_t 498 intel_init() 499 { 500 TRACE("bus manager init\n"); 501 502 if (get_module(B_PCI_MODULE_NAME, (module_info **)&sPCI) != B_OK) 503 return B_ERROR; 504 505 bool found = false; 506 507 for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK; 508 index++) { 509 if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL 510 || sInfo.bridge.class_base != PCI_bridge) 511 continue; 512 513 // check device 514 for (uint32 i = 0; i < sizeof(kSupportedDevices) 515 / sizeof(kSupportedDevices[0]); i++) { 516 if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) { 517 sInfo.type = kSupportedDevices[i].type; 518 found = has_display_device(sInfo.display, 519 kSupportedDevices[i].display_id); 520 break; 521 } 522 } 523 524 if (found) 525 break; 526 } 527 528 if (!found) 529 return ENODEV; 530 531 TRACE("found intel bridge\n"); 532 return B_OK; 533 } 534 535 536 static void 537 intel_uninit() 538 { 539 } 540 541 542 static int32 543 intel_std_ops(int32 op, ...) 544 { 545 switch (op) { 546 case B_MODULE_INIT: 547 return intel_init(); 548 case B_MODULE_UNINIT: 549 intel_uninit(); 550 return B_OK; 551 } 552 553 return B_BAD_VALUE; 554 } 555 556 557 static struct agp_gart_bus_module_info sIntelModuleInfo = { 558 { 559 "busses/agp_gart/intel/v0", 560 0, 561 intel_std_ops 562 }, 563 564 intel_create_aperture, 565 intel_delete_aperture, 566 567 intel_get_aperture_info, 568 intel_set_aperture_size, 569 intel_bind_page, 570 intel_unbind_page, 571 intel_flush_tlbs 572 }; 573 574 module_info *modules[] = { 575 (module_info *)&sIntelModuleInfo, 576 NULL 577 }; 578