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 int maxPort = INTEL_PORT_F; 308 if (gInfo->shared_info->device_type.Generation() >= 12) 309 maxPort = INTEL_PORT_G; 310 for (int i = INTEL_PORT_A; i <= maxPort; i++) { 311 TRACE("Probing DDI %d\n", i); 312 313 Port* ddiPort 314 = new(std::nothrow) DigitalDisplayInterface((port_index)i); 315 316 if (ddiPort == NULL) 317 return B_NO_MEMORY; 318 319 if (ddiPort->IsConnected()) { 320 foundDDI = true; 321 gInfo->ports[gInfo->port_count++] = ddiPort; 322 } else 323 delete ddiPort; 324 } 325 } 326 327 #if 0 328 // never execute this as the 'standard' DisplayPort class called above already handles it. 329 if (!gInfo->shared_info->device_type.HasDDI()) { 330 // Ensure DP_A isn't already taken 331 TRACE("Probing eDP\n"); 332 if (!has_connected_port((port_index)INTEL_PORT_A, INTEL_PORT_TYPE_ANY)) { 333 // also always try eDP, it'll also just fail if not applicable 334 Port* eDPPort = new(std::nothrow) EmbeddedDisplayPort(); 335 if (eDPPort == NULL) 336 return B_NO_MEMORY; 337 if (eDPPort->IsConnected()) 338 gInfo->ports[gInfo->port_count++] = eDPPort; 339 else 340 delete eDPPort; 341 } 342 } 343 #endif 344 345 if (!gInfo->shared_info->device_type.HasDDI()) { 346 for (int i = INTEL_PORT_B; i <= INTEL_PORT_D; i++) { 347 TRACE("Probing HDMI %d\n", i); 348 if (has_connected_port((port_index)i, INTEL_PORT_TYPE_ANY)) { 349 // Ensure port not already claimed by something like DDI 350 TRACE("Port already claimed\n"); 351 continue; 352 } 353 354 Port* hdmiPort = new(std::nothrow) HDMIPort((port_index)i); 355 if (hdmiPort == NULL) 356 return B_NO_MEMORY; 357 358 if (hdmiPort->IsConnected()) 359 gInfo->ports[gInfo->port_count++] = hdmiPort; 360 else 361 delete hdmiPort; 362 } 363 } 364 365 // always try the LVDS port when chipset supports it, it'll simply fail if not applicable 366 if (!gInfo->shared_info->device_type.HasDDI()) { 367 TRACE("Probing LVDS\n"); 368 Port* lvdsPort = new(std::nothrow) LVDSPort(); 369 if (lvdsPort == NULL) 370 return B_NO_MEMORY; 371 if (lvdsPort->IsConnected()) { 372 foundLVDS = true; 373 gInfo->ports[gInfo->port_count++] = lvdsPort; 374 gInfo->head_mode |= HEAD_MODE_LVDS_PANEL; 375 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 376 } else 377 delete lvdsPort; 378 } 379 380 if (!gInfo->shared_info->device_type.HasDDI()) { 381 if (!has_connected_port(INTEL_PORT_ANY, INTEL_PORT_TYPE_ANY)) { 382 TRACE("Probing DVI\n"); 383 // there's neither DisplayPort nor HDMI so far, assume DVI B 384 for (port_index index = INTEL_PORT_B; index <= INTEL_PORT_C; 385 index = (port_index)(index + 1)) { 386 Port* dviPort = new(std::nothrow) DigitalPort(index, "DVI"); 387 if (dviPort == NULL) 388 return B_NO_MEMORY; 389 390 if (dviPort->IsConnected()) { 391 gInfo->ports[gInfo->port_count++] = dviPort; 392 gInfo->head_mode |= HEAD_MODE_B_DIGITAL; 393 } else 394 delete dviPort; 395 } 396 } 397 } 398 399 // then finally always try the analog port when chipsets supports it 400 if (gInfo->shared_info->device_type.Generation() <= 8 401 && gInfo->shared_info->internal_crt_support) { 402 TRACE("Probing Analog\n"); 403 Port* analogPort = new(std::nothrow) AnalogPort(); 404 if (analogPort == NULL) 405 return B_NO_MEMORY; 406 if (analogPort->IsConnected()) { 407 gInfo->ports[gInfo->port_count++] = analogPort; 408 gInfo->head_mode |= HEAD_MODE_A_ANALOG; 409 } else 410 delete analogPort; 411 } 412 413 if (gInfo->port_count == 0) 414 return B_ERROR; 415 416 // Activate reference clocks if needed 417 if (gInfo->shared_info->pch_info == INTEL_PCH_IBX 418 || gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 419 TRACE("Activating clocks\n"); 420 refclk_activate_ilk(foundLVDS || foundDP || foundDDI); 421 } 422 /* 423 } else if (gInfo->shared_info->pch_info == INTEL_PCH_LPT) { 424 // TODO: Some kind of stepped bend thing? 425 // only needed for vga 426 refclk_activate_lpt(foundLVDS); 427 } 428 */ 429 430 TRACE("Probing complete.\n"); 431 return B_OK; 432 } 433 434 435 static status_t 436 assign_pipes() 437 { 438 // TODO: At some point we should "group" ports to pipes with the same mode. 439 // You can drive multiple ports from a single pipe as long as the mode is 440 // the same. For the moment we could get displays with the wrong pipes 441 // assigned when the count is > 1; 442 443 uint32 current = 0; 444 445 bool assigned[gInfo->pipe_count]; 446 memset(assigned, 0, gInfo->pipe_count); 447 448 // Some ports need to be assigned to a fixed pipe on old hardware (or due 449 // to limitations in the current driver on current hardware). Assign those 450 // first 451 for (uint32 i = 0; i < gInfo->port_count; i++) { 452 if (!gInfo->ports[i]->IsConnected()) 453 continue; 454 455 pipe_index preference = gInfo->ports[i]->PipePreference(); 456 if (preference != INTEL_PIPE_ANY) { 457 int index = (int)preference - 1; 458 if (assigned[index]) { 459 TRACE("Pipe %d is already assigned, it will drive multiple " 460 "displays\n", index); 461 } 462 gInfo->ports[i]->SetPipe(gInfo->pipes[index]); 463 assigned[index] = true; 464 continue; 465 } 466 } 467 468 // In a second pass, assign the remaining ports to the remaining pipes 469 for (uint32 i = 0; i < gInfo->port_count; i++) { 470 if (gInfo->ports[i]->IsConnected() && gInfo->ports[i]->GetPipe() == NULL) { 471 while (current < gInfo->pipe_count && assigned[current]) 472 current++; 473 474 if (current >= gInfo->pipe_count) { 475 ERROR("%s: No pipes left to assign to port %s!\n", __func__, 476 gInfo->ports[i]->PortName()); 477 continue; 478 } 479 480 gInfo->ports[i]->SetPipe(gInfo->pipes[current]); 481 assigned[current] = true; 482 } 483 } 484 485 return B_OK; 486 } 487 488 489 // #pragma mark - public accelerant functions 490 491 492 /*! Init primary accelerant */ 493 status_t 494 intel_init_accelerant(int device) 495 { 496 CALLED(); 497 498 status_t status = init_common(device, false); 499 if (status != B_OK) 500 return status; 501 502 intel_shared_info &info = *gInfo->shared_info; 503 504 init_lock(&info.accelerant_lock, "intel extreme accelerant"); 505 init_lock(&info.engine_lock, "intel extreme engine"); 506 507 setup_ring_buffer(info.primary_ring_buffer, "intel primary ring buffer"); 508 509 // Probe all ports 510 status = probe_ports(); 511 512 // On TRACE, dump ports and states 513 dump_ports(); 514 515 if (status != B_OK) 516 ERROR("Warning: zero active displays were found!\n"); 517 518 status = assign_pipes(); 519 520 if (status != B_OK) 521 ERROR("Warning: error while assigning pipes!\n"); 522 523 status = create_mode_list(); 524 if (status != B_OK) { 525 uninit_common(); 526 return status; 527 } 528 529 return B_OK; 530 } 531 532 533 ssize_t 534 intel_accelerant_clone_info_size(void) 535 { 536 CALLED(); 537 // clone info is device name, so return its maximum size 538 return B_PATH_NAME_LENGTH; 539 } 540 541 542 void 543 intel_get_accelerant_clone_info(void* info) 544 { 545 CALLED(); 546 ioctl(gInfo->device, INTEL_GET_DEVICE_NAME, info, B_PATH_NAME_LENGTH); 547 } 548 549 550 status_t 551 intel_clone_accelerant(void* info) 552 { 553 CALLED(); 554 555 // create full device name 556 char path[B_PATH_NAME_LENGTH]; 557 strcpy(path, "/dev/"); 558 #ifdef __HAIKU__ 559 strlcat(path, (const char*)info, sizeof(path)); 560 #else 561 strcat(path, (const char*)info); 562 #endif 563 564 int fd = open(path, B_READ_WRITE); 565 if (fd < 0) 566 return errno; 567 568 status_t status = init_common(fd, true); 569 if (status != B_OK) 570 goto err1; 571 572 // get read-only clone of supported display modes 573 status = gInfo->mode_list_area = clone_area( 574 "intel extreme cloned modes", (void**)&gInfo->mode_list, 575 B_ANY_ADDRESS, B_READ_AREA, gInfo->shared_info->mode_list_area); 576 if (status < B_OK) 577 goto err2; 578 579 return B_OK; 580 581 err2: 582 uninit_common(); 583 err1: 584 close(fd); 585 return status; 586 } 587 588 589 /*! This function is called for both, the primary accelerant and all of 590 its clones. 591 */ 592 void 593 intel_uninit_accelerant(void) 594 { 595 CALLED(); 596 597 // delete accelerant instance data 598 delete_area(gInfo->mode_list_area); 599 gInfo->mode_list = NULL; 600 601 if (!gInfo->is_clone) { 602 intel_shared_info &info = *gInfo->shared_info; 603 uninit_lock(&info.accelerant_lock); 604 uninit_lock(&info.engine_lock); 605 uninit_ring_buffer(info.primary_ring_buffer); 606 } 607 uninit_common(); 608 } 609 610 611 status_t 612 intel_get_accelerant_device_info(accelerant_device_info* info) 613 { 614 CALLED(); 615 616 info->version = B_ACCELERANT_VERSION; 617 618 DeviceType* type = &gInfo->shared_info->device_type; 619 620 if (type->InFamily(INTEL_FAMILY_8xx)) 621 strcpy(info->name, "Intel Extreme"); 622 else if (type->InFamily(INTEL_FAMILY_9xx)) 623 strcpy(info->name, "Intel GMA"); 624 else if (type->InFamily(INTEL_FAMILY_SOC0)) 625 strcpy(info->name, "Intel Atom"); 626 else if (type->InFamily(INTEL_FAMILY_SER5)) 627 strcpy(info->name, "Intel HD/Iris"); 628 else 629 strcpy(info->name, "Intel"); 630 631 strcpy(info->chipset, gInfo->shared_info->device_identifier); 632 strcpy(info->serial_no, "None"); 633 634 info->memory = gInfo->shared_info->graphics_memory_size; 635 info->dac_speed = gInfo->shared_info->pll_info.max_frequency; 636 637 return B_OK; 638 } 639 640 641 sem_id 642 intel_accelerant_retrace_semaphore() 643 { 644 CALLED(); 645 return gInfo->shared_info->vblank_sem; 646 } 647