1 /* 2 * Copyright 2006-2016, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "accelerant_protos.h" 11 #include "accelerant.h" 12 13 #include "utility.h" 14 15 #include <Debug.h> 16 #include <errno.h> 17 #include <stdlib.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include <syslog.h> 21 22 #include <new> 23 24 #include <AGP.h> 25 #include <AutoDeleterOS.h> 26 27 28 #undef TRACE 29 #define TRACE_ACCELERANT 30 #ifdef TRACE_ACCELERANT 31 # define TRACE(x...) _sPrintf("intel_extreme: " x) 32 #else 33 # define TRACE(x...) 34 #endif 35 36 #define ERROR(x...) _sPrintf("intel_extreme: " x) 37 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 38 39 40 struct accelerant_info* gInfo; 41 uint32 gDumpCount; 42 43 44 // #pragma mark - 45 46 47 // intel_reg --mmio=ie-0001.bin --devid=27a2 dump 48 void 49 dump_registers() 50 { 51 char filename[255]; 52 53 sprintf(filename, "/boot/system/cache/tmp/ie-%04" B_PRId32 ".bin", 54 gDumpCount); 55 56 ERROR("%s: Taking register dump #%" B_PRId32 "\n", __func__, gDumpCount); 57 58 area_info areaInfo; 59 get_area_info(gInfo->shared_info->registers_area, &areaInfo); 60 61 int fd = open(filename, O_CREAT | O_WRONLY, 0644); 62 uint32 data = 0; 63 if (fd >= 0) { 64 for (uint32 i = 0; i < areaInfo.size; i += sizeof(data)) { 65 //char line[512]; 66 //int length = sprintf(line, "%05" B_PRIx32 ": " 67 // "%08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 "\n", 68 // i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12)); 69 data = read32(i); 70 write(fd, &data, sizeof(data)); 71 } 72 close(fd); 73 sync(); 74 } 75 76 gDumpCount++; 77 } 78 79 80 /*! This is the common accelerant_info initializer. It is called by 81 both, the first accelerant and all clones. 82 */ 83 static status_t 84 init_common(int device, bool isClone) 85 { 86 // initialize global accelerant info structure 87 88 // Number of register dumps we have... taken. 89 gDumpCount = 0; 90 91 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info)); 92 if (gInfo == NULL) 93 return B_NO_MEMORY; 94 MemoryDeleter infoDeleter(gInfo); 95 96 memset(gInfo, 0, sizeof(accelerant_info)); 97 98 gInfo->is_clone = isClone; 99 gInfo->device = device; 100 101 // get basic info from driver 102 103 intel_get_private_data data; 104 data.magic = INTEL_PRIVATE_DATA_MAGIC; 105 106 if (ioctl(device, INTEL_GET_PRIVATE_DATA, &data, 107 sizeof(intel_get_private_data)) != 0) 108 return B_ERROR; 109 110 AreaDeleter sharedDeleter(clone_area("intel extreme shared info", 111 (void**)&gInfo->shared_info, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 112 data.shared_info_area)); 113 status_t status = gInfo->shared_info_area = sharedDeleter.Get(); 114 if (status < B_OK) 115 return status; 116 117 AreaDeleter regsDeleter(clone_area("intel extreme regs", 118 (void**)&gInfo->registers, B_ANY_ADDRESS, B_READ_AREA | B_WRITE_AREA, 119 gInfo->shared_info->registers_area)); 120 status = gInfo->regs_area = regsDeleter.Get(); 121 if (status < B_OK) 122 return status; 123 124 infoDeleter.Detach(); 125 sharedDeleter.Detach(); 126 regsDeleter.Detach(); 127 128 // The overlay registers, hardware status, and cursor memory share 129 // a single area with the shared_info 130 131 if (gInfo->shared_info->overlay_offset != 0) { 132 gInfo->overlay_registers = (struct overlay_registers*) 133 (gInfo->shared_info->graphics_memory 134 + gInfo->shared_info->overlay_offset); 135 } 136 137 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) { 138 // allocate some extra memory for the 3D context 139 if (intel_allocate_memory(INTEL_i965_3D_CONTEXT_SIZE, 140 B_APERTURE_NON_RESERVED, gInfo->context_base) == B_OK) { 141 gInfo->context_offset = gInfo->context_base 142 - (addr_t)gInfo->shared_info->graphics_memory; 143 } 144 } 145 146 gInfo->pipe_count = 0; 147 148 // Allocate all of our pipes 149 int pipeCnt = 2; 150 if (gInfo->shared_info->device_type.Generation() >= 12) 151 pipeCnt = 4; 152 else if (gInfo->shared_info->device_type.Generation() >= 7) 153 pipeCnt = 3; 154 155 for (int i = 0; i < pipeCnt; i++) { 156 switch (i) { 157 case 0: 158 gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_A); 159 break; 160 case 1: 161 gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_B); 162 break; 163 case 2: 164 gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_C); 165 break; 166 case 3: 167 gInfo->pipes[i] = new(std::nothrow) Pipe(INTEL_PIPE_D); 168 break; 169 default: 170 ERROR("%s: Unknown pipe %d\n", __func__, i); 171 } 172 if (gInfo->pipes[i] == NULL) 173 ERROR("%s: Error allocating pipe %d\n", __func__, i); 174 else 175 gInfo->pipe_count++; 176 } 177 178 return B_OK; 179 } 180 181 182 /*! Clean up data common to both primary and cloned accelerant */ 183 static void 184 uninit_common(void) 185 { 186 intel_free_memory(gInfo->context_base); 187 188 delete_area(gInfo->regs_area); 189 delete_area(gInfo->shared_info_area); 190 191 gInfo->regs_area = gInfo->shared_info_area = -1; 192 193 // close the file handle ONLY if we're the clone 194 if (gInfo->is_clone) 195 close(gInfo->device); 196 197 free(gInfo); 198 } 199 200 201 static void 202 dump_ports() 203 { 204 if (gInfo->port_count == 0) { 205 TRACE("%s: No ports connected\n", __func__); 206 return; 207 } 208 209 TRACE("%s: Connected ports: (port_count: %" B_PRIu32 ")\n", __func__, 210 gInfo->port_count); 211 212 for (uint32 i = 0; i < gInfo->port_count; i++) { 213 Port* port = gInfo->ports[i]; 214 if (!port) { 215 TRACE("port %" B_PRIu32 ":: INVALID ALLOC!\n", i); 216 continue; 217 } 218 TRACE("port %" B_PRIu32 ": %s %s\n", i, port->PortName(), 219 port->IsConnected() ? "connected" : "disconnected"); 220 } 221 } 222 223 224 static bool 225 has_connected_port(port_index portIndex, uint32 type) 226 { 227 for (uint32 i = 0; i < gInfo->port_count; i++) { 228 Port* port = gInfo->ports[i]; 229 if (type != INTEL_PORT_TYPE_ANY && port->Type() != type) 230 continue; 231 if (portIndex != INTEL_PORT_ANY && port->PortIndex() != portIndex) 232 continue; 233 234 return true; 235 } 236 237 return false; 238 } 239 240 241 static status_t 242 probe_ports() 243 { 244 // Try to determine what ports to use. We use the following heuristic: 245 // * Check for DisplayPort, these can be more or less detected reliably. 246 // * Check for HDMI, it'll fail on devices not having HDMI for us to fall 247 // back to DVI. 248 // * Assume DVI B if no HDMI and no DisplayPort is present, confirmed by 249 // reading EDID in the IsConnected() call. 250 // * Check for analog if possible (there's a detection bit on PCH), 251 // otherwise the assumed presence is confirmed by reading EDID in 252 // IsConnected(). 253 254 TRACE("adpa: %08" B_PRIx32 "\n", read32(INTEL_ANALOG_PORT)); 255 TRACE("dova: %08" B_PRIx32 ", dovb: %08" B_PRIx32 256 ", dovc: %08" B_PRIx32 "\n", read32(INTEL_DIGITAL_PORT_A), 257 read32(INTEL_DIGITAL_PORT_B), read32(INTEL_DIGITAL_PORT_C)); 258 TRACE("lvds: %08" B_PRIx32 "\n", read32(INTEL_DIGITAL_LVDS_PORT)); 259 260 TRACE("dp_a: %08" B_PRIx32 "\n", read32(INTEL_DISPLAY_PORT_A)); 261 TRACE("dp_b: %08" B_PRIx32 "\n", read32(INTEL_DISPLAY_PORT_B)); 262 TRACE("dp_c: %08" B_PRIx32 "\n", read32(INTEL_DISPLAY_PORT_C)); 263 TRACE("dp_d: %08" B_PRIx32 "\n", read32(INTEL_DISPLAY_PORT_D)); 264 TRACE("tra_dp: %08" B_PRIx32 "\n", read32(INTEL_TRANSCODER_A_DP_CTL)); 265 TRACE("trb_dp: %08" B_PRIx32 "\n", read32(INTEL_TRANSCODER_B_DP_CTL)); 266 TRACE("trc_dp: %08" B_PRIx32 "\n", read32(INTEL_TRANSCODER_C_DP_CTL)); 267 268 bool foundLVDS = false; 269 bool foundDP = false; 270 bool foundDDI = false; 271 272 gInfo->port_count = 0; 273 #if 0 274 // make sure I2C hardware controller is off (we use bit-banging) 275 if (gInfo->shared_info->device_type.Generation() >= 5) { 276 write32(INTEL_DSPCLK_GATE_D, 277 read32(INTEL_DSPCLK_GATE_D) | PCH_GMBUSUNIT_CLK_GATE_DIS); 278 read32(INTEL_DSPCLK_GATE_D); 279 280 write32(INTEL_GEN9_CLKGATE_DIS_4, 281 read32(INTEL_GEN9_CLKGATE_DIS_4) | BXT_GMBUSUNIT_CLK_GATE_DIS); 282 read32(INTEL_GEN9_CLKGATE_DIS_4); 283 284 write32(INTEL_GMBUS0, 0); //reset, idle 285 write32(INTEL_GMBUS4, 0); //block interrupts 286 } 287 #endif 288 289 // Display Port 290 if (!gInfo->shared_info->device_type.HasDDI()) { 291 for (int i = INTEL_PORT_A; i <= INTEL_PORT_D; i++) { 292 TRACE("Probing DisplayPort %d\n", i); 293 Port* displayPort = new(std::nothrow) DisplayPort((port_index)i); 294 if (displayPort == NULL) 295 return B_NO_MEMORY; 296 297 if (displayPort->IsConnected()) { 298 foundDP = true; 299 gInfo->ports[gInfo->port_count++] = displayPort; 300 } else 301 delete displayPort; 302 } 303 } 304 305 // Digital Display Interface (for DP, HDMI, DVI and eDP) 306 if (gInfo->shared_info->device_type.HasDDI()) { 307 for (int i = INTEL_PORT_A; i <= INTEL_PORT_F; i++) { 308 TRACE("Probing DDI %d\n", i); 309 310 Port* ddiPort 311 = new(std::nothrow) DigitalDisplayInterface((port_index)i); 312 313 if (ddiPort == NULL) 314 return B_NO_MEMORY; 315 316 if (ddiPort->IsConnected()) { 317 foundDDI = true; 318 gInfo->ports[gInfo->port_count++] = ddiPort; 319 } else 320 delete ddiPort; 321 } 322 } 323 324 #if 0 325 // never execute this as the 'standard' DisplayPort class called above already handles it. 326 if (!gInfo->shared_info->device_type.HasDDI()) { 327 // Ensure DP_A isn't already taken 328 TRACE("Probing eDP\n"); 329 if (!has_connected_port((port_index)INTEL_PORT_A, INTEL_PORT_TYPE_ANY)) { 330 // also always try eDP, it'll also just fail if not applicable 331 Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort(); 332 if (eDPPort == NULL) 333 return B_NO_MEMORY; 334 if (eDPPort->IsConnected()) 335 gInfo->ports[gInfo->port_count++] = eDPPort; 336 else 337 delete eDPPort; 338 } 339 } 340 #endif 341 342 if (!gInfo->shared_info->device_type.HasDDI()) { 343 for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { 344 TRACE("Probing HDMI %d\n", i); 345 if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) { 346 // Ensure port not already claimed by something like DDI 347 TRACE("Port already claimed\n"); 348 continue; 349 } 350 351 Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i); 352 if (hdmiPort == NULL) 353 return B_NO_MEMORY; 354 355 if (hdmiPort->IsConnected()) 356 gInfo->ports[gInfo->port_count++] = hdmiPort; 357 else 358 delete hdmiPort; 359 } 360 } 361 362 // always try the LVDS port when chipset supports it, it'll simply fail if not applicable 363 if (!gInfo->shared_info->device_type.HasDDI()) { 364 TRACE("Probing LVDS\n"); 365 Port* lvdsPort = new(std::nothrow) LVDSPort(); 366 if (lvdsPort == NULL) 367 return B_NO_MEMORY; 368 if (lvdsPort->IsConnected()) { 369 foundLVDS = true; 370 gInfo->ports[gInfo->port_count++] = lvdsPort; 371 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 372 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 373 } else 374 delete lvdsPort; 375 } 376 377 if (!gInfo->shared_info->device_type.HasDDI()) { 378 if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) { 379 TRACE("Probing DVI\n"); 380 // there's neither DisplayPort nor HDMI so far, assume DVI B 381 for (port_index index = INTEL_PORT_B; index <= INTEL_PORT_C; 382 index = (port_index)(index + 1)) { 383 Port* dviPort = new(std::nothrow) DigitalPort(index, "DVI"); 384 if (dviPort == NULL) 385 return B_NO_MEMORY; 386 387 if (dviPort->IsConnected()) { 388 gInfo->ports[gInfo->port_count++] = dviPort; 389 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 390 } else 391 delete dviPort; 392 } 393 } 394 } 395 396 // then finally always try the analog port when chipsets supports it 397 if (gInfo->shared_info->device_type.Generation() <= 8 398 && gInfo->shared_info->internal_crt_support) { 399 TRACE("Probing Analog\n"); 400 Port* analogPort = new(std::nothrow) AnalogPort(); 401 if (analogPort == NULL) 402 return B_NO_MEMORY; 403 if (analogPort->IsConnected()) { 404 gInfo->ports[gInfo->port_count++] = analogPort; 405 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 406 } else 407 delete analogPort; 408 } 409 410 if (gInfo->port_count == 0) 411 return B_ERROR; 412 413 // Activate reference clocks if needed 414 if (gInfo->shared_info->pch_info == INTEL_PCH_IBX 415 || gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 416 TRACE("Activating clocks\n"); 417 refclk_activate_ilk(foundLVDS || foundDP || foundDDI); 418 } 419 /* 420 } else if (gInfo->shared_info->pch_info == INTEL_PCH_LPT) { 421 // TODO: Some kind of stepped bend thing? 422 // only needed for vga 423 refclk_activate_lpt(foundLVDS); 424 } 425 */ 426 427 TRACE("Probing complete.\n"); 428 return B_OK; 429 } 430 431 432 static status_t 433 assign_pipes() 434 { 435 // TODO: At some point we should "group" ports to pipes with the same mode. 436 // You can drive multiple ports from a single pipe as long as the mode is 437 // the same. For the moment we could get displays with the wrong pipes 438 // assigned when the count is > 1; 439 440 uint32 current = 0; 441 442 bool assigned[gInfo->pipe_count]; 443 memset(assigned, 0, gInfo->pipe_count); 444 445 // Some ports need to be assigned to a fixed pipe on old hardware (or due 446 // to limitations in the current driver on current hardware). Assign those 447 // first 448 for (uint32 i = 0; i < gInfo->port_count; i++) { 449 if (!gInfo->ports[i]->IsConnected()) 450 continue; 451 452 pipe_index preference = gInfo->ports[i]->PipePreference(); 453 if (preference != INTEL_PIPE_ANY) { 454 int index = (int)preference - 1; 455 if (assigned[index]) { 456 TRACE("Pipe %d is already assigned, it will drive multiple " 457 "displays\n", index); 458 } 459 gInfo->ports[i]->SetPipe(gInfo->pipes[index]); 460 assigned[index] = true; 461 continue; 462 } 463 } 464 465 // In a second pass, assign the remaining ports to the remaining pipes 466 for (uint32 i = 0; i < gInfo->port_count; i++) { 467 if (gInfo->ports[i]->IsConnected() && gInfo->ports[i]->GetPipe() == NULL) { 468 while (current < gInfo->pipe_count && assigned[current]) 469 current++; 470 471 if (current >= gInfo->pipe_count) { 472 ERROR("%s: No pipes left to assign to port %s!\n", __func__, 473 gInfo->ports[i]->PortName()); 474 continue; 475 } 476 477 gInfo->ports[i]->SetPipe(gInfo->pipes[current]); 478 assigned[current] = true; 479 } 480 } 481 482 return B_OK; 483 } 484 485 486 // #pragma mark - public accelerant functions 487 488 489 /*! Init primary accelerant */ 490 status_t 491 intel_init_accelerant(int device) 492 { 493 CALLED(); 494 495 status_t status = init_common(device, false); 496 if (status != B_OK) 497 return status; 498 499 intel_shared_info &info = *gInfo->shared_info; 500 501 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 502 init_lock(&info.engine_lock, "intel extreme engine"); 503 504 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 505 506 // Probe all ports 507 status = probe_ports(); 508 509 // On TRACE, dump ports and states 510 dump_ports(); 511 512 if (status != B_OK) 513 ERROR("Warning: zero active displays were found!\n"); 514 515 status = assign_pipes(); 516 517 if (status != B_OK) 518 ERROR("Warning: error while assigning pipes!\n"); 519 520 status = create_mode_list(); 521 if (status != B_OK) { 522 uninit_common(); 523 return status; 524 } 525 526 return B_OK; 527 } 528 529 530 ssize_t 531 intel_accelerant_clone_info_size(void) 532 { 533 CALLED(); 534 // clone info is device name, so return its maximum size 535 return B_PATH_NAME_LENGTH; 536 } 537 538 539 void 540 intel_get_accelerant_clone_info(void* info) 541 { 542 CALLED(); 543 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 544 } 545 546 547 status_t 548 intel_clone_accelerant(void* info) 549 { 550 CALLED(); 551 552 // create full device name 553 char path[B_PATH_NAME_LENGTH]; 554 strcpy(path, "/dev/"); 555 #ifdef __HAIKU__ 556 strlcat(path, (const char*)info, sizeof(path)); 557 #else 558 strcat(path, (const char*)info); 559 #endif 560 561 int fd = open(path, B_READ_WRITE); 562 if (fd < 0) 563 return errno; 564 565 status_t status = init_common(fd, true); 566 if (status != B_OK) 567 goto err1; 568 569 // get read-only clone of supported display modes 570 status = gInfo->mode_list_area = clone_area( 571 "intel extreme cloned modes", (void**)&gInfo->mode_list, 572 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 573 if (status < B_OK) 574 goto err2; 575 576 return B_OK; 577 578 err2: 579 uninit_common(); 580 err1: 581 close(fd); 582 return status; 583 } 584 585 586 /*! This function is called for both, the primary accelerant and all of 587 its clones. 588 */ 589 void 590 intel_uninit_accelerant(void) 591 { 592 CALLED(); 593 594 // delete accelerant instance data 595 delete_area(gInfo->mode_list_area); 596 gInfo->mode_list = NULL; 597 598 if (!gInfo->is_clone) { 599 intel_shared_info &info = *gInfo->shared_info; 600 uninit_lock(&info.accelerant_lock); 601 uninit_lock(&info.engine_lock); 602 uninit_ring_buffer(info.primary_ring_buffer); 603 } 604 uninit_common(); 605 } 606 607 608 status_t 609 intel_get_accelerant_device_info(accelerant_device_info* info) 610 { 611 CALLED(); 612 613 info->version = B_ACCELERANT_VERSION; 614 615 DeviceType* type = &gInfo->shared_info->device_type; 616 617 if (type->InFamily(INTEL_FAMILY_8xx)) 618 strcpy(info->name, "Intel Extreme"); 619 else if (type->InFamily(INTEL_FAMILY_9xx)) 620 strcpy(info->name, "Intel GMA"); 621 else if (type->InFamily(INTEL_FAMILY_SOC0)) 622 strcpy(info->name, "Intel Atom"); 623 else if (type->InFamily(INTEL_FAMILY_SER5)) 624 strcpy(info->name, "Intel HD/Iris"); 625 else 626 strcpy(info->name, "Intel"); 627 628 strcpy(info->chipset, gInfo->shared_info->device_identifier); 629 strcpy(info->serial_no, "None"); 630 631 info->memory = gInfo->shared_info->graphics_memory_size; 632 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 633 634 return B_OK; 635 } 636 637 638 sem_id 639 intel_accelerant_retrace_semaphore() 640 { 641 CALLED(); 642 return gInfo->shared_info->vblank_sem; 643 } 644