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