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