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