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