1 /* 2 * Copyright 2008-2010, Axel Dörfler, axeld@pinc-software.de. 3 * Copyright 2011-2016, Haiku, Inc. All Rights Reserved. 4 * Distributed under the terms of the MIT License. 5 * 6 * Authors: 7 * Axel Dörfler, axeld@pinc-software.de 8 * Jerome Duval, jerome.duval@gmail.com 9 * Adrien Destugues, pulkomandy@gmail.com 10 * Michael Lotz, mmlr@mlotz.ch 11 * Alexander von Gluck IV, kallisti5@unixzen.com 12 */ 13 14 15 #include <AreaKeeper.h> 16 #include <intel_extreme.h> 17 18 #include <stdlib.h> 19 20 #include <AGP.h> 21 #include <KernelExport.h> 22 #include <PCI.h> 23 24 #include <new> 25 26 27 #define TRACE_INTEL 28 #ifdef TRACE_INTEL 29 # define TRACE(x...) dprintf("intel_gart: " x) 30 #else 31 # define TRACE(x...) ; 32 #endif 33 #define ERROR(x...) dprintf("intel_gart: " x) 34 35 #ifndef __HAIKU__ 36 # define B_KERNEL_READ_AREA 0 37 # define B_KERNEL_WRITE_AREA 0 38 #endif 39 40 /* read and write to PCI config space */ 41 #define get_pci_config(info, offset, size) \ 42 (sPCI->read_pci_config((info).bus, (info).device, (info).function, \ 43 (offset), (size))) 44 #define set_pci_config(info, offset, size, value) \ 45 (sPCI->write_pci_config((info).bus, (info).device, (info).function, \ 46 (offset), (size), (value))) 47 #define write32(address, data) \ 48 (*((volatile uint32*)(address)) = (data)) 49 #define read32(address) \ 50 (*((volatile uint32*)(address))) 51 52 53 // PCI "Host bridge" is most cases :-) 54 const struct supported_device { 55 uint32 bridge_id; 56 uint32 display_id; 57 int32 type; 58 const char *name; 59 } kSupportedDevices[] = { 60 {0x3575, 0x3577, INTEL_GROUP_83x, "i830GM"}, 61 {0x2560, 0x2562, INTEL_GROUP_83x, "i845G"}, 62 {0x3580, 0x3582, INTEL_GROUP_85x, "i855G"}, 63 {0x358c, 0x358e, INTEL_GROUP_85x, "i855G"}, 64 {0x2570, 0x2572, INTEL_GROUP_85x, "i865G"}, 65 66 // {0x2792, INTEL_GROUP_91x, "i910"}, 67 // {0x258a, INTEL_GROUP_91x, "i915"}, 68 {0x2580, 0x2582, INTEL_MODEL_915, "i915G"}, 69 {0x2590, 0x2592, INTEL_MODEL_915M, "i915GM"}, 70 {0x2770, 0x2772, INTEL_MODEL_945, "i945G"}, 71 {0x27a0, 0x27a2, INTEL_MODEL_945M, "i945GM"}, 72 {0x27ac, 0x27ae, INTEL_MODEL_945M, "i945GME"}, 73 74 {0x2970, 0x2972, INTEL_MODEL_965, "i946GZ"}, 75 {0x2980, 0x2982, INTEL_MODEL_965, "G35"}, 76 {0x2990, 0x2992, INTEL_MODEL_965, "i965Q"}, 77 {0x29a0, 0x29a2, INTEL_MODEL_965, "i965G"}, 78 {0x2a00, 0x2a02, INTEL_MODEL_965, "i965GM"}, 79 {0x2a10, 0x2a12, INTEL_MODEL_965, "i965GME"}, 80 81 {0x29b0, 0x29b2, INTEL_MODEL_G33, "G33"}, 82 {0x29c0, 0x29c2, INTEL_MODEL_G33, "Q35"}, 83 {0x29d0, 0x29d2, INTEL_MODEL_G33, "Q33"}, 84 85 {0x2a40, 0x2a42, INTEL_MODEL_GM45, "GM45"}, 86 {0x2e00, 0x2e02, INTEL_MODEL_G45, "IGD"}, 87 {0x2e10, 0x2e12, INTEL_MODEL_G45, "Q45"}, 88 {0x2e20, 0x2e22, INTEL_MODEL_G45, "G45"}, 89 {0x2e30, 0x2e32, INTEL_MODEL_G45, "G41"}, 90 {0x2e40, 0x2e42, INTEL_MODEL_G45, "B43"}, 91 {0x2e90, 0x2e92, INTEL_MODEL_G45, "B43"}, 92 93 {0xa000, 0xa001, INTEL_MODEL_PINE, "Atom D4xx"}, 94 {0xa000, 0xa002, INTEL_MODEL_PINE, "Atom D5xx"}, 95 {0xa010, 0xa011, INTEL_MODEL_PINEM, "Atom N4xx"}, 96 {0xa010, 0xa012, INTEL_MODEL_PINEM, "Atom N5xx"}, 97 98 {0x0040, 0x0042, INTEL_MODEL_ILKG, "IronLake Desktop"}, 99 {0x0044, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"}, 100 {0x0062, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"}, 101 {0x006a, 0x0046, INTEL_MODEL_ILKGM, "IronLake Mobile"}, 102 103 {0x0100, 0x0102, INTEL_MODEL_SNBG, "SandyBridge Desktop GT1"}, 104 {0x0100, 0x0112, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2"}, 105 {0x0100, 0x0122, INTEL_MODEL_SNBG, "SandyBridge Desktop GT2+"}, 106 {0x0104, 0x0106, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT1"}, 107 {0x0104, 0x0116, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2"}, 108 {0x0104, 0x0126, INTEL_MODEL_SNBGM, "SandyBridge Mobile GT2+"}, 109 {0x0108, 0x010a, INTEL_MODEL_SNBGS, "SandyBridge Server"}, 110 111 {0x0150, 0x0152, INTEL_MODEL_IVBG, "IvyBridge Desktop GT1"}, 112 {0x0150, 0x0162, INTEL_MODEL_IVBG, "IvyBridge Desktop GT2"}, 113 {0x0154, 0x0156, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT1"}, 114 {0x0154, 0x0166, INTEL_MODEL_IVBGM, "IvyBridge Mobile GT2"}, 115 {0x0158, 0x015a, INTEL_MODEL_IVBGS, "IvyBridge Server GT1"}, 116 {0x0158, 0x016a, INTEL_MODEL_IVBGS, "IvyBridge Server GT2"}, 117 118 {0x0c00, 0x0412, INTEL_MODEL_HAS, "Haswell Desktop"}, 119 {0x0c04, 0x0416, INTEL_MODEL_HASM, "Haswell Mobile"}, 120 {0x0d04, 0x0d26, INTEL_MODEL_HASM, "Haswell Mobile"}, 121 {0x0a04, 0x0a16, INTEL_MODEL_HASM, "Haswell Mobile"}, 122 123 // XXX: 0x0f00 only confirmed on 0x0f30, 0x0f31 124 {0x0f00, 0x0155, INTEL_MODEL_VLV, "ValleyView Desktop"}, 125 {0x0f00, 0x0f30, INTEL_MODEL_VLVM, "ValleyView Mobile"}, 126 {0x0f00, 0x0f31, INTEL_MODEL_VLVM, "ValleyView Mobile"}, 127 {0x0f00, 0x0f32, INTEL_MODEL_VLVM, "ValleyView Mobile"}, 128 {0x0f00, 0x0f33, INTEL_MODEL_VLVM, "ValleyView Mobile"}, 129 {0x0f00, 0x0157, INTEL_MODEL_VLVM, "ValleyView Mobile"}, 130 131 {0x1604, 0x1616, INTEL_MODEL_BDWM, "HD Graphics 5500 (Broadwell GT2)"}, 132 133 // XXX: 0x1904 only confirmed on 0x1916 134 {0x1904, 0x1902, INTEL_MODEL_SKY, "Skylake GT1"}, 135 {0x1904, 0x1906, INTEL_MODEL_SKYM, "Skylake GT1"}, 136 {0x1904, 0x190a, INTEL_MODEL_SKYS, "Skylake GT1"}, 137 {0x1904, 0x190b, INTEL_MODEL_SKY, "Skylake GT1"}, 138 {0x1904, 0x190e, INTEL_MODEL_SKYM, "Skylake GT1"}, 139 {0x1904, 0x1912, INTEL_MODEL_SKY, "Skylake GT2"}, 140 {0x1904, 0x1916, INTEL_MODEL_SKYM, "Skylake GT2"}, 141 {0x1904, 0x191a, INTEL_MODEL_SKYS, "Skylake GT2"}, 142 {0x1904, 0x191b, INTEL_MODEL_SKY, "Skylake GT2"}, 143 {0x1904, 0x191d, INTEL_MODEL_SKY, "Skylake GT2"}, 144 {0x1904, 0x191e, INTEL_MODEL_SKYM, "Skylake GT2"}, 145 {0x1904, 0x1921, INTEL_MODEL_SKYM, "Skylake GT2F"}, 146 {0x1904, 0x1926, INTEL_MODEL_SKYM, "Skylake GT3"}, 147 {0x1904, 0x192a, INTEL_MODEL_SKYS, "Skylake GT3"}, 148 {0x1904, 0x192b, INTEL_MODEL_SKY, "Skylake GT3"}, 149 }; 150 151 struct intel_info { 152 pci_info bridge; 153 pci_info display; 154 DeviceType* type; 155 156 uint32* gtt_base; 157 phys_addr_t gtt_physical_base; 158 area_id gtt_area; 159 size_t gtt_entries; 160 size_t gtt_stolen_entries; 161 162 vuint32* registers; 163 area_id registers_area; 164 165 addr_t aperture_base; 166 phys_addr_t aperture_physical_base; 167 area_id aperture_area; 168 size_t aperture_size; 169 size_t aperture_stolen_size; 170 171 phys_addr_t scratch_page; 172 area_id scratch_area; 173 }; 174 175 static intel_info sInfo; 176 static pci_module_info* sPCI; 177 178 179 static bool 180 has_display_device(pci_info &info, uint32 deviceID) 181 { 182 for (uint32 index = 0; sPCI->get_nth_pci_info(index, &info) == B_OK; 183 index++) { 184 if (info.vendor_id != VENDOR_ID_INTEL 185 || info.device_id != deviceID 186 || info.class_base != PCI_display) 187 continue; 188 189 return true; 190 } 191 192 return false; 193 } 194 195 196 static uint16 197 gtt_memory_config(intel_info &info) 198 { 199 uint8 controlRegister = INTEL_GRAPHICS_MEMORY_CONTROL; 200 if (info.type->InGroup(INTEL_GROUP_SNB)) 201 controlRegister = SNB_GRAPHICS_MEMORY_CONTROL; 202 203 return get_pci_config(info.bridge, controlRegister, 2); 204 } 205 206 207 static size_t 208 determine_gtt_stolen(intel_info &info) 209 { 210 uint16 memoryConfig = gtt_memory_config(info); 211 size_t memorySize = 1 << 20; // 1 MB 212 213 if (info.type->InGroup(INTEL_GROUP_83x)) { 214 // Older chips 215 switch (memoryConfig & STOLEN_MEMORY_MASK) { 216 case i830_LOCAL_MEMORY_ONLY: 217 // TODO: determine its size! 218 ERROR("getting local memory size not implemented.\n"); 219 break; 220 case i830_STOLEN_512K: 221 memorySize >>= 1; 222 break; 223 case i830_STOLEN_1M: 224 // default case 225 break; 226 case i830_STOLEN_8M: 227 memorySize *= 8; 228 break; 229 } 230 } else if (info.type->InGroup(INTEL_GROUP_SNB)) { 231 switch (memoryConfig & SNB_STOLEN_MEMORY_MASK) { 232 case SNB_STOLEN_MEMORY_32MB: 233 memorySize *= 32; 234 break; 235 case SNB_STOLEN_MEMORY_64MB: 236 memorySize *= 64; 237 break; 238 case SNB_STOLEN_MEMORY_96MB: 239 memorySize *= 96; 240 break; 241 case SNB_STOLEN_MEMORY_128MB: 242 memorySize *= 128; 243 break; 244 case SNB_STOLEN_MEMORY_160MB: 245 memorySize *= 160; 246 break; 247 case SNB_STOLEN_MEMORY_192MB: 248 memorySize *= 192; 249 break; 250 case SNB_STOLEN_MEMORY_224MB: 251 memorySize *= 224; 252 break; 253 case SNB_STOLEN_MEMORY_256MB: 254 memorySize *= 256; 255 break; 256 case SNB_STOLEN_MEMORY_288MB: 257 memorySize *= 288; 258 break; 259 case SNB_STOLEN_MEMORY_320MB: 260 memorySize *= 320; 261 break; 262 case SNB_STOLEN_MEMORY_352MB: 263 memorySize *= 352; 264 break; 265 case SNB_STOLEN_MEMORY_384MB: 266 memorySize *= 384; 267 break; 268 case SNB_STOLEN_MEMORY_416MB: 269 memorySize *= 416; 270 break; 271 case SNB_STOLEN_MEMORY_448MB: 272 memorySize *= 448; 273 break; 274 case SNB_STOLEN_MEMORY_480MB: 275 memorySize *= 480; 276 break; 277 case SNB_STOLEN_MEMORY_512MB: 278 memorySize *= 512; 279 break; 280 } 281 } else if (info.type->InGroup(INTEL_GROUP_85x) 282 || info.type->InFamily(INTEL_FAMILY_9xx) 283 || info.type->InFamily(INTEL_FAMILY_SER5) 284 || info.type->InFamily(INTEL_FAMILY_SOC0) 285 || info.type->InFamily(INTEL_FAMILY_POVR)) { 286 switch (memoryConfig & STOLEN_MEMORY_MASK) { 287 case i855_STOLEN_MEMORY_4M: 288 memorySize *= 4; 289 break; 290 case i855_STOLEN_MEMORY_8M: 291 memorySize *= 8; 292 break; 293 case i855_STOLEN_MEMORY_16M: 294 memorySize *= 16; 295 break; 296 case i855_STOLEN_MEMORY_32M: 297 memorySize *= 32; 298 break; 299 case i855_STOLEN_MEMORY_48M: 300 memorySize *= 48; 301 break; 302 case i855_STOLEN_MEMORY_64M: 303 memorySize *= 64; 304 break; 305 case i855_STOLEN_MEMORY_128M: 306 memorySize *= 128; 307 break; 308 case i855_STOLEN_MEMORY_256M: 309 memorySize *= 256; 310 break; 311 case G4X_STOLEN_MEMORY_96MB: 312 memorySize *= 96; 313 break; 314 case G4X_STOLEN_MEMORY_160MB: 315 memorySize *= 160; 316 break; 317 case G4X_STOLEN_MEMORY_224MB: 318 memorySize *= 224; 319 break; 320 case G4X_STOLEN_MEMORY_352MB: 321 memorySize *= 352; 322 break; 323 } 324 } else { 325 // TODO: error out! 326 memorySize = 4096; 327 } 328 return memorySize - 4096; 329 } 330 331 332 static size_t 333 determine_gtt_size(intel_info &info) 334 { 335 uint16 memoryConfig = gtt_memory_config(info); 336 size_t gttSize = 0; 337 338 if (info.type->IsModel(INTEL_MODEL_965)) { 339 switch (memoryConfig & i965_GTT_MASK) { 340 case i965_GTT_128K: 341 gttSize = 128 << 10; 342 break; 343 case i965_GTT_256K: 344 gttSize = 256 << 10; 345 break; 346 case i965_GTT_512K: 347 gttSize = 512 << 10; 348 break; 349 } 350 } else if (info.type->IsModel(INTEL_MODEL_G33) 351 || info.type->InGroup(INTEL_GROUP_PIN)) { 352 switch (memoryConfig & G33_GTT_MASK) { 353 case G33_GTT_1M: 354 gttSize = 1 << 20; 355 break; 356 case G33_GTT_2M: 357 gttSize = 2 << 20; 358 break; 359 } 360 } else if (info.type->InGroup(INTEL_GROUP_G4x) 361 || info.type->InGroup(INTEL_GROUP_ILK)) { 362 switch (memoryConfig & G4X_GTT_MASK) { 363 case G4X_GTT_NONE: 364 gttSize = 0; 365 break; 366 case G4X_GTT_1M_NO_IVT: 367 gttSize = 1 << 20; 368 break; 369 case G4X_GTT_2M_NO_IVT: 370 case G4X_GTT_2M_IVT: 371 gttSize = 2 << 20; 372 break; 373 case G4X_GTT_3M_IVT: 374 gttSize = 3 << 20; 375 break; 376 case G4X_GTT_4M_IVT: 377 gttSize = 4 << 20; 378 break; 379 } 380 } else if (info.type->InGroup(INTEL_GROUP_SNB)) { 381 switch (memoryConfig & SNB_GTT_SIZE_MASK) { 382 case SNB_GTT_SIZE_NONE: 383 gttSize = 0; 384 break; 385 case SNB_GTT_SIZE_1MB: 386 gttSize = 1 << 20; 387 break; 388 case SNB_GTT_SIZE_2MB: 389 gttSize = 2 << 20; 390 break; 391 } 392 } else { 393 // older models have the GTT as large as their frame buffer mapping 394 // TODO: check if the i9xx version works with the i8xx chips as well 395 size_t frameBufferSize = 0; 396 if (info.type->InFamily(INTEL_FAMILY_8xx)) { 397 if (info.type->InGroup(INTEL_GROUP_83x) 398 && (memoryConfig & MEMORY_MASK) == i830_FRAME_BUFFER_64M) 399 frameBufferSize = 64 << 20; 400 else 401 frameBufferSize = 128 << 20; 402 } else if (info.type->Generation() >= 3) { 403 frameBufferSize = info.display.u.h0.base_register_sizes[2]; 404 } 405 406 TRACE("frame buffer size %lu MB\n", frameBufferSize >> 20); 407 gttSize = frameBufferSize / 1024; 408 } 409 return gttSize; 410 } 411 412 413 static void 414 set_gtt_entry(intel_info &info, uint32 offset, phys_addr_t physicalAddress) 415 { 416 if (info.type->Generation() >= 8) { 417 // CHV + BXT 418 physicalAddress |= (physicalAddress >> 28) & 0x07f0; 419 // TODO: cache control? 420 } else if (info.type->Generation() >= 6) { 421 // SandyBridge, IronLake, IvyBridge, Haswell 422 physicalAddress |= (physicalAddress >> 28) & 0x0ff0; 423 physicalAddress |= 0x02; // cache control, l3 cacheable 424 } else if (info.type->Generation() >= 4) { 425 // Intel 9xx minus 91x, 94x, G33 426 // possible high bits are stored in the lower end 427 physicalAddress |= (physicalAddress >> 28) & 0x00f0; 428 // TODO: cache control? 429 } 430 431 // TODO: this is not 64-bit safe! 432 write32(info.gtt_base + (offset >> GTT_PAGE_SHIFT), 433 (uint32)physicalAddress | GTT_ENTRY_VALID); 434 } 435 436 437 static void 438 intel_unmap(intel_info &info) 439 { 440 delete_area(info.registers_area); 441 delete_area(info.gtt_area); 442 delete_area(info.scratch_area); 443 delete_area(info.aperture_area); 444 info.aperture_size = 0; 445 } 446 447 448 static status_t 449 intel_map(intel_info &info) 450 { 451 int fbIndex = 0; 452 int mmioIndex = 1; 453 if (info.type->Generation() >= 3) { 454 // for some reason Intel saw the need to change the order of the 455 // mappings with the introduction of the i9xx family 456 mmioIndex = 0; 457 fbIndex = 2; 458 } 459 460 AreaKeeper mmioMapper; 461 info.registers_area = mmioMapper.Map("intel GMCH mmio", 462 info.display.u.h0.base_registers[mmioIndex], 463 info.display.u.h0.base_register_sizes[mmioIndex], B_ANY_KERNEL_ADDRESS, 464 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.registers); 465 466 if (mmioMapper.InitCheck() < B_OK) { 467 ERROR("could not map memory I/O!\n"); 468 return info.registers_area; 469 } 470 471 // make sure bus master, memory-mapped I/O, and frame buffer is enabled 472 set_pci_config(info.display, PCI_command, 2, 473 get_pci_config(info.display, PCI_command, 2) 474 | PCI_command_io | PCI_command_memory | PCI_command_master); 475 476 void* scratchAddress; 477 AreaKeeper scratchCreator; 478 info.scratch_area = scratchCreator.Create("intel GMCH scratch", 479 &scratchAddress, B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_FULL_LOCK, 480 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 481 if (scratchCreator.InitCheck() < B_OK) { 482 ERROR("could not create scratch page!\n"); 483 return info.scratch_area; 484 } 485 486 physical_entry entry; 487 if (get_memory_map(scratchAddress, B_PAGE_SIZE, &entry, 1) != B_OK) 488 return B_ERROR; 489 490 // TODO: Review these 491 if (info.type->InFamily(INTEL_FAMILY_8xx)) { 492 info.gtt_physical_base = read32(info.registers 493 + INTEL_PAGE_TABLE_CONTROL) & ~PAGE_TABLE_ENABLED; 494 if (info.gtt_physical_base == 0) { 495 // TODO: not sure how this is supposed to work under Linux/FreeBSD, 496 // but on my i865, this code is needed for Haiku. 497 ERROR("Use GTT address fallback.\n"); 498 info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex] 499 + i830_GTT_BASE; 500 } 501 } else if (info.type->InGroup(INTEL_GROUP_91x)) { 502 info.gtt_physical_base = get_pci_config(info.display, i915_GTT_BASE, 4); 503 } else { 504 // 945+? 505 info.gtt_physical_base = info.display.u.h0.base_registers[mmioIndex] 506 + (2UL << 20); 507 } 508 509 size_t gttSize = determine_gtt_size(info); 510 size_t stolenSize = determine_gtt_stolen(info); 511 512 info.gtt_entries = gttSize / 4096; 513 info.gtt_stolen_entries = stolenSize / 4096; 514 515 TRACE("GTT base %" B_PRIxPHYSADDR ", size %lu, entries %lu, stolen %lu\n", 516 info.gtt_physical_base, gttSize, info.gtt_entries, stolenSize); 517 518 AreaKeeper gttMapper; 519 info.gtt_area = gttMapper.Map("intel GMCH gtt", 520 info.gtt_physical_base, gttSize, B_ANY_KERNEL_ADDRESS, 521 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&info.gtt_base); 522 if (gttMapper.InitCheck() < B_OK) { 523 ERROR("could not map GTT!\n"); 524 return info.gtt_area; 525 } 526 527 info.aperture_physical_base = info.display.u.h0.base_registers[fbIndex]; 528 info.aperture_stolen_size = stolenSize; 529 if (info.aperture_size == 0) 530 info.aperture_size = info.display.u.h0.base_register_sizes[fbIndex]; 531 532 ERROR("detected %ld MB of stolen memory, aperture size %ld MB, " 533 "GTT size %ld KB\n", (stolenSize + (1023 << 10)) >> 20, 534 info.aperture_size >> 20, gttSize >> 10); 535 536 ERROR("GTT base = 0x%" B_PRIxPHYSADDR "\n", info.gtt_physical_base); 537 ERROR("MMIO base = 0x%" B_PRIx32 "\n", 538 info.display.u.h0.base_registers[mmioIndex]); 539 ERROR("GMR base = 0x%" B_PRIxPHYSADDR "\n", info.aperture_physical_base); 540 541 AreaKeeper apertureMapper; 542 info.aperture_area = apertureMapper.Map("intel graphics aperture", 543 info.aperture_physical_base, info.aperture_size, 544 B_ANY_KERNEL_BLOCK_ADDRESS | B_MTR_WC, 545 B_READ_AREA | B_WRITE_AREA, (void**)&info.aperture_base); 546 if (apertureMapper.InitCheck() < B_OK) { 547 // try again without write combining 548 ERROR("enabling write combined mode failed.\n"); 549 550 info.aperture_area = apertureMapper.Map("intel graphics aperture", 551 info.aperture_physical_base, info.aperture_size, 552 B_ANY_KERNEL_BLOCK_ADDRESS, B_READ_AREA | B_WRITE_AREA, 553 (void**)&info.aperture_base); 554 } 555 if (apertureMapper.InitCheck() < B_OK) { 556 ERROR("could not map graphics aperture!\n"); 557 return info.aperture_area; 558 } 559 560 info.scratch_page = entry.address; 561 562 gttMapper.Detach(); 563 mmioMapper.Detach(); 564 scratchCreator.Detach(); 565 apertureMapper.Detach(); 566 567 return B_OK; 568 } 569 570 571 // #pragma mark - module interface 572 573 574 status_t 575 intel_create_aperture(uint8 bus, uint8 device, uint8 function, size_t size, 576 void** _aperture) 577 { 578 // TODO: we currently only support a single AGP bridge! 579 if ((bus != sInfo.bridge.bus || device != sInfo.bridge.device 580 || function != sInfo.bridge.function) 581 && (bus != sInfo.display.bus || device != sInfo.display.device 582 || function != sInfo.display.function)) 583 return B_BAD_VALUE; 584 585 sInfo.aperture_size = size; 586 587 if (intel_map(sInfo) < B_OK) 588 return B_ERROR; 589 590 uint16 gmchControl = get_pci_config(sInfo.bridge, 591 INTEL_GRAPHICS_MEMORY_CONTROL, 2) | MEMORY_CONTROL_ENABLED; 592 set_pci_config(sInfo.bridge, INTEL_GRAPHICS_MEMORY_CONTROL, 2, gmchControl); 593 594 write32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL, 595 sInfo.gtt_physical_base | PAGE_TABLE_ENABLED); 596 read32(sInfo.registers + INTEL_PAGE_TABLE_CONTROL); 597 598 if (sInfo.scratch_page != 0) { 599 for (size_t i = sInfo.gtt_stolen_entries; i < sInfo.gtt_entries; i++) { 600 set_gtt_entry(sInfo, i << GTT_PAGE_SHIFT, sInfo.scratch_page); 601 } 602 read32(sInfo.gtt_base + sInfo.gtt_entries - 1); 603 } 604 605 asm("wbinvd;"); 606 607 *_aperture = NULL; 608 return B_OK; 609 } 610 611 612 void 613 intel_delete_aperture(void* aperture) 614 { 615 intel_unmap(sInfo); 616 } 617 618 619 static status_t 620 intel_get_aperture_info(void* aperture, aperture_info* info) 621 { 622 if (info == NULL) 623 return B_BAD_VALUE; 624 625 info->base = sInfo.aperture_base; 626 info->physical_base = sInfo.aperture_physical_base; 627 info->size = sInfo.aperture_size; 628 info->reserved_size = sInfo.aperture_stolen_size; 629 630 return B_OK; 631 } 632 633 634 status_t 635 intel_set_aperture_size(void* aperture, size_t size) 636 { 637 return B_ERROR; 638 } 639 640 641 static status_t 642 intel_bind_page(void* aperture, uint32 offset, phys_addr_t physicalAddress) 643 { 644 //TRACE("bind_page(offset %lx, physical %lx)\n", offset, physicalAddress); 645 646 set_gtt_entry(sInfo, offset, physicalAddress); 647 return B_OK; 648 } 649 650 651 static status_t 652 intel_unbind_page(void* aperture, uint32 offset) 653 { 654 //TRACE("unbind_page(offset %lx)\n", offset); 655 656 if (sInfo.scratch_page != 0) 657 set_gtt_entry(sInfo, offset, sInfo.scratch_page); 658 659 return B_OK; 660 } 661 662 663 void 664 intel_flush_tlbs(void* aperture) 665 { 666 read32(sInfo.gtt_base + sInfo.gtt_entries - 1); 667 asm("wbinvd;"); 668 } 669 670 671 // #pragma mark - 672 673 674 static status_t 675 intel_init() 676 { 677 TRACE("bus manager init\n"); 678 679 if (get_module(B_PCI_MODULE_NAME, (module_info**)&sPCI) != B_OK) 680 return B_ERROR; 681 682 for (uint32 index = 0; sPCI->get_nth_pci_info(index, &sInfo.bridge) == B_OK; 683 index++) { 684 if (sInfo.bridge.vendor_id != VENDOR_ID_INTEL 685 || sInfo.bridge.class_base != PCI_bridge) 686 continue; 687 688 // check device 689 for (uint32 i = 0; i < sizeof(kSupportedDevices) 690 / sizeof(kSupportedDevices[0]); i++) { 691 if (sInfo.bridge.device_id == kSupportedDevices[i].bridge_id) { 692 sInfo.type = new DeviceType(kSupportedDevices[i].type); 693 if (has_display_device(sInfo.display, 694 kSupportedDevices[i].display_id)) { 695 TRACE("found intel bridge\n"); 696 return B_OK; 697 } 698 } 699 } 700 } 701 702 return ENODEV; 703 } 704 705 706 static void 707 intel_uninit() 708 { 709 if (sInfo.type) 710 delete sInfo.type; 711 } 712 713 714 static int32 715 intel_std_ops(int32 op, ...) 716 { 717 switch (op) { 718 case B_MODULE_INIT: 719 return intel_init(); 720 case B_MODULE_UNINIT: 721 intel_uninit(); 722 return B_OK; 723 } 724 725 return B_BAD_VALUE; 726 } 727 728 729 static struct agp_gart_bus_module_info sIntelModuleInfo = { 730 { 731 "busses/agp_gart/intel/v0", 732 0, 733 intel_std_ops 734 }, 735 736 intel_create_aperture, 737 intel_delete_aperture, 738 739 intel_get_aperture_info, 740 intel_set_aperture_size, 741 intel_bind_page, 742 intel_unbind_page, 743 intel_flush_tlbs 744 }; 745 746 module_info* modules[] = { 747 (module_info*)&sIntelModuleInfo, 748 NULL 749 }; 750