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