1 /* 2 * Copyright 2006-2010, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Support for i915 chipset and up based on the X driver, 6 * Copyright 2006-2007 Intel Corporation. 7 * 8 * Authors: 9 * Axel Dörfler, axeld@pinc-software.de 10 */ 11 12 13 #include <math.h> 14 #include <stdio.h> 15 #include <string.h> 16 17 #include <Debug.h> 18 19 #include <create_display_modes.h> 20 #include <ddc.h> 21 #include <edid.h> 22 #include <validate_display_mode.h> 23 24 #include "accelerant_protos.h" 25 #include "accelerant.h" 26 #include "pll.h" 27 #include "Ports.h" 28 #include "utility.h" 29 30 31 #undef TRACE 32 #define TRACE_MODE 33 #ifdef TRACE_MODE 34 # define TRACE(x...) _sPrintf("intel_extreme: " x) 35 #else 36 # define TRACE(x...) 37 #endif 38 39 #define ERROR(x...) _sPrintf("intel_extreme: " x) 40 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 41 42 43 static void 44 get_color_space_format(const display_mode &mode, uint32 &colorMode, 45 uint32 &bytesPerRow, uint32 &bitsPerPixel) 46 { 47 uint32 bytesPerPixel; 48 49 switch (mode.space) { 50 case B_RGB32_LITTLE: 51 colorMode = DISPLAY_CONTROL_RGB32; 52 bytesPerPixel = 4; 53 bitsPerPixel = 32; 54 break; 55 case B_RGB16_LITTLE: 56 colorMode = DISPLAY_CONTROL_RGB16; 57 bytesPerPixel = 2; 58 bitsPerPixel = 16; 59 break; 60 case B_RGB15_LITTLE: 61 colorMode = DISPLAY_CONTROL_RGB15; 62 bytesPerPixel = 2; 63 bitsPerPixel = 15; 64 break; 65 case B_CMAP8: 66 default: 67 colorMode = DISPLAY_CONTROL_CMAP8; 68 bytesPerPixel = 1; 69 bitsPerPixel = 8; 70 break; 71 } 72 73 bytesPerRow = mode.virtual_width * bytesPerPixel; 74 75 // Make sure bytesPerRow is a multiple of 64 76 if ((bytesPerRow & 63) != 0) 77 bytesPerRow = (bytesPerRow + 63) & ~63; 78 } 79 80 81 static bool 82 sanitize_display_mode(display_mode& mode) 83 { 84 uint16 pixelCount = 1; 85 // Older cards require pixel count to be even 86 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_Gxx) 87 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x) 88 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_94x) 89 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_91x) 90 || gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_8xx)) { 91 pixelCount = 2; 92 } 93 94 display_constraints constraints = { 95 // resolution 96 320, 4096, 200, 4096, 97 // pixel clock 98 gInfo->shared_info->pll_info.min_frequency, 99 gInfo->shared_info->pll_info.max_frequency, 100 // horizontal 101 {pixelCount, 0, 8160, 32, 8192, 0, 8192}, 102 {1, 1, 8190, 2, 8192, 1, 8192} 103 }; 104 105 return sanitize_display_mode(mode, constraints, 106 gInfo->has_edid ? &gInfo->edid_info : NULL); 107 } 108 109 110 // #pragma mark - 111 112 113 static void 114 set_frame_buffer_registers(uint32 offset) 115 { 116 intel_shared_info &sharedInfo = *gInfo->shared_info; 117 display_mode &mode = sharedInfo.current_mode; 118 uint32 bytes_per_pixel = (sharedInfo.bits_per_pixel + 7) / 8; 119 120 if (sharedInfo.device_type.InGroup(INTEL_GROUP_96x) 121 || sharedInfo.device_type.InGroup(INTEL_GROUP_G4x) 122 || sharedInfo.device_type.InGroup(INTEL_GROUP_ILK) 123 || sharedInfo.device_type.InFamily(INTEL_FAMILY_SER5) 124 || sharedInfo.device_type.InFamily(INTEL_FAMILY_SOC0)) { 125 if (sharedInfo.device_type.InGroup(INTEL_GROUP_HAS)) { 126 write32(INTEL_DISPLAY_A_OFFSET_HAS + offset, 127 ((uint32)mode.v_display_start << 16) 128 | (uint32)mode.h_display_start); 129 read32(INTEL_DISPLAY_A_OFFSET_HAS + offset); 130 } else { 131 write32(INTEL_DISPLAY_A_BASE + offset, 132 mode.v_display_start * sharedInfo.bytes_per_row 133 + mode.h_display_start * bytes_per_pixel); 134 read32(INTEL_DISPLAY_A_BASE + offset); 135 } 136 write32(INTEL_DISPLAY_A_SURFACE + offset, sharedInfo.frame_buffer_offset); 137 read32(INTEL_DISPLAY_A_SURFACE + offset); 138 } else { 139 write32(INTEL_DISPLAY_A_BASE + offset, sharedInfo.frame_buffer_offset 140 + mode.v_display_start * sharedInfo.bytes_per_row 141 + mode.h_display_start * bytes_per_pixel); 142 read32(INTEL_DISPLAY_A_BASE + offset); 143 } 144 } 145 146 147 void 148 set_frame_buffer_base() 149 { 150 // TODO we always set both displays to the same address. When we support 151 // multiple framebuffers, they should get different addresses here. 152 set_frame_buffer_registers(0); 153 set_frame_buffer_registers(INTEL_DISPLAY_OFFSET); 154 } 155 156 157 static bool 158 limit_modes_for_gen3_lvds(display_mode* mode) 159 { 160 // Filter out modes with resolution higher than the internal LCD can 161 // display. 162 // FIXME do this only for that display. The whole display mode logic 163 // needs to be adjusted to know which display we're talking about. 164 if (gInfo->shared_info->panel_mode.timing.h_display < mode->timing.h_display) 165 return false; 166 if (gInfo->shared_info->panel_mode.timing.v_display < mode->timing.v_display) 167 return false; 168 169 return true; 170 } 171 172 /*! Creates the initial mode list of the primary accelerant. 173 It's called from intel_init_accelerant(). 174 */ 175 status_t 176 create_mode_list(void) 177 { 178 CALLED(); 179 180 for (uint32 i = 0; i < gInfo->port_count; i++) { 181 if (gInfo->ports[i] == NULL) 182 continue; 183 184 status_t status = gInfo->ports[i]->GetEDID(&gInfo->edid_info); 185 if (status == B_OK) 186 gInfo->has_edid = true; 187 } 188 189 display_mode* list; 190 uint32 count = 0; 191 192 const color_space kSupportedSpaces[] = {B_RGB32_LITTLE, B_RGB16_LITTLE, 193 B_CMAP8}; 194 const color_space* supportedSpaces; 195 int colorSpaceCount; 196 197 if (gInfo->shared_info->device_type.Generation() >= 4) { 198 // No B_RGB15, use our custom colorspace list 199 supportedSpaces = kSupportedSpaces; 200 colorSpaceCount = B_COUNT_OF(kSupportedSpaces); 201 } else { 202 supportedSpaces = NULL; 203 colorSpaceCount = 0; 204 } 205 206 // If no EDID, but have vbt from driver, use that mode 207 if (!gInfo->has_edid && gInfo->shared_info->got_vbt) { 208 // We could not read any EDID info. Fallback to creating a list with 209 // only the mode set up by the BIOS. 210 211 check_display_mode_hook limitModes = NULL; 212 if (gInfo->shared_info->device_type.Generation() < 4) 213 limitModes = limit_modes_for_gen3_lvds; 214 215 // TODO: support lower modes via scaling and windowing 216 gInfo->mode_list_area = create_display_modes("intel extreme modes", 217 NULL, &gInfo->shared_info->panel_mode, 1, 218 supportedSpaces, colorSpaceCount, limitModes, &list, &count); 219 } else { 220 // Otherwise return the 'real' list of modes 221 gInfo->mode_list_area = create_display_modes("intel extreme modes", 222 gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, 223 supportedSpaces, colorSpaceCount, NULL, &list, &count); 224 } 225 226 if (gInfo->mode_list_area < B_OK) 227 return gInfo->mode_list_area; 228 229 gInfo->mode_list = list; 230 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 231 gInfo->shared_info->mode_count = count; 232 233 return B_OK; 234 } 235 236 237 void 238 wait_for_vblank(void) 239 { 240 acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT, 241 21000); 242 // With the output turned off via DPMS, we might not get any interrupts 243 // anymore that's why we don't wait forever for it. At 50Hz, we're sure 244 // to get a vblank in at most 20ms, so there is no need to wait longer 245 // than that. 246 } 247 248 249 // #pragma mark - 250 251 252 uint32 253 intel_accelerant_mode_count(void) 254 { 255 CALLED(); 256 return gInfo->shared_info->mode_count; 257 } 258 259 260 status_t 261 intel_get_mode_list(display_mode* modeList) 262 { 263 CALLED(); 264 memcpy(modeList, gInfo->mode_list, 265 gInfo->shared_info->mode_count * sizeof(display_mode)); 266 return B_OK; 267 } 268 269 270 status_t 271 intel_propose_display_mode(display_mode* target, const display_mode* low, 272 const display_mode* high) 273 { 274 CALLED(); 275 276 display_mode mode = *target; 277 278 if (sanitize_display_mode(*target)) { 279 TRACE("Video mode was adjusted by sanitize_display_mode\n"); 280 TRACE("Initial mode: Hd %d Hs %d He %d Ht %d Vd %d Vs %d Ve %d Vt %d\n", 281 mode.timing.h_display, mode.timing.h_sync_start, 282 mode.timing.h_sync_end, mode.timing.h_total, 283 mode.timing.v_display, mode.timing.v_sync_start, 284 mode.timing.v_sync_end, mode.timing.v_total); 285 TRACE("Sanitized: Hd %d Hs %d He %d Ht %d Vd %d Vs %d Ve %d Vt %d\n", 286 target->timing.h_display, target->timing.h_sync_start, 287 target->timing.h_sync_end, target->timing.h_total, 288 target->timing.v_display, target->timing.v_sync_start, 289 target->timing.v_sync_end, target->timing.v_total); 290 } 291 // (most) modeflags are outputs from us (the driver). So we should 292 // set them depending on the mode and the current hardware config 293 target->flags |= B_SCROLL; 294 295 return is_display_mode_within_bounds(*target, *low, *high) 296 ? B_OK : B_BAD_VALUE; 297 } 298 299 300 status_t 301 intel_set_display_mode(display_mode* mode) 302 { 303 if (mode == NULL) 304 return B_BAD_VALUE; 305 306 TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ", virtual: %" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, 307 mode->timing.h_display, mode->timing.v_display, mode->virtual_width, mode->virtual_height); 308 309 display_mode target = *mode; 310 311 if (intel_propose_display_mode(&target, &target, &target) != B_OK) 312 return B_BAD_VALUE; 313 314 uint32 colorMode, bytesPerRow, bitsPerPixel; 315 get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); 316 317 // TODO: do not go further if the mode is identical to the current one. 318 // This would avoid the screen being off when switching workspaces when they 319 // have the same resolution. 320 321 intel_shared_info &sharedInfo = *gInfo->shared_info; 322 Autolock locker(sharedInfo.accelerant_lock); 323 324 // First register dump 325 //dump_registers(); 326 327 // TODO: This may not be neccesary 328 set_display_power_mode(B_DPMS_OFF); 329 330 // free old and allocate new frame buffer in graphics memory 331 332 intel_free_memory(sharedInfo.frame_buffer); 333 334 addr_t base; 335 if (intel_allocate_memory(bytesPerRow * target.virtual_height, 0, 336 base) < B_OK) { 337 // oh, how did that happen? Unfortunately, there is no really good way 338 // back. Try to restore a framebuffer for the previous mode, at least. 339 if (intel_allocate_memory(sharedInfo.current_mode.virtual_height 340 * sharedInfo.bytes_per_row, 0, base) == B_OK) { 341 sharedInfo.frame_buffer = base; 342 sharedInfo.frame_buffer_offset = base 343 - (addr_t)sharedInfo.graphics_memory; 344 set_frame_buffer_base(); 345 } 346 347 ERROR("%s: Failed to allocate framebuffer !\n", __func__); 348 return B_NO_MEMORY; 349 } 350 351 // clear frame buffer before using it 352 memset((uint8*)base, 0, bytesPerRow * target.virtual_height); 353 sharedInfo.frame_buffer = base; 354 sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory; 355 356 #if 0 357 if ((gInfo->head_mode & HEAD_MODE_TESTING) != 0) { 358 // 1. Enable panel power as needed to retrieve panel configuration 359 // (use AUX VDD enable bit) 360 // skip, did detection already, might need that before that though 361 362 // 2. Enable PCH clock reference source and PCH SSC modulator, 363 // wait for warmup (Can be done anytime before enabling port) 364 // skip, most certainly already set up by bios to use other ports, 365 // will need for coldstart though 366 367 // 3. If enabling CPU embedded DisplayPort A: (Can be done anytime 368 // before enabling CPU pipe or port) 369 // a. Enable PCH 120MHz clock source output to CPU, wait for DMI 370 // latency 371 // b. Configure and enable CPU DisplayPort PLL in the DisplayPort A 372 // register, wait for warmup 373 // skip, not doing eDP right now, should go into 374 // EmbeddedDisplayPort class though 375 376 // 4. If enabling port on PCH: (Must be done before enabling CPU pipe 377 // or FDI) 378 // a. Enable PCH FDI Receiver PLL, wait for warmup plus DMI latency 379 // b. Switch from Rawclk to PCDclk in FDI Receiver (FDI A OR FDI B) 380 // c. [DevSNB] Enable CPU FDI Transmitter PLL, wait for warmup 381 // d. [DevILK] CPU FDI PLL is always on and does not need to be 382 // enabled 383 FDILink* link = pipe->FDILink(); 384 if (link != NULL) { 385 link->Receiver().EnablePLL(); 386 link->Receiver().SwitchClock(true); 387 link->Transmitter().EnablePLL(); 388 } 389 390 // 5. Enable CPU panel fitter if needed for hires, required for VGA 391 // (Can be done anytime before enabling CPU pipe) 392 PanelFitter* fitter = pipe->PanelFitter(); 393 if (fitter != NULL) 394 fitter->Enable(mode); 395 396 // 6. Configure CPU pipe timings, M/N/TU, and other pipe settings 397 // (Can be done anytime before enabling CPU pipe) 398 pll_divisors divisors; 399 compute_pll_divisors(target, divisors, false); 400 pipe->ConfigureTimings(divisors); 401 402 // 7. Enable CPU pipe 403 pipe->Enable(); 404 405 8. Configure and enable CPU planes (VGA or hires) 406 9. If enabling port on PCH: 407 // a. Program PCH FDI Receiver TU size same as Transmitter TU size for TU error checking 408 // b. Train FDI 409 // i. Set pre-emphasis and voltage (iterate if training steps fail) 410 ii. Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled. 411 iii. Wait for FDI training pattern 1 time 412 iv. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for bit lock in bit 8 (retry at least once if no lock) 413 v. Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver 414 vi. Wait for FDI training pattern 2 time 415 vii. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for symbol lock in bit 9 (retry at least once if no 416 lock) 417 viii. Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver 418 ix. Wait for FDI idle pattern time for link to become active 419 c. Configure and enable PCH DPLL, wait for PCH DPLL warmup (Can be done anytime before enabling 420 PCH transcoder) 421 d. [DevCPT] Configure DPLL SEL to set the DPLL to transcoder mapping and enable DPLL to the 422 transcoder. 423 e. [DevCPT] Configure DPLL_CTL DPLL_HDMI_multipler. 424 f. Configure PCH transcoder timings, M/N/TU, and other transcoder settings (should match CPU settings). 425 g. [DevCPT] Configure and enable Transcoder DisplayPort Control if DisplayPort will be used 426 h. Enable PCH transcoder 427 10. Enable ports (DisplayPort must enable in training pattern 1) 428 11. Enable panel power through panel power sequencing 429 12. Wait for panel power sequencing to reach enabled steady state 430 13. Disable panel power override 431 14. If DisplayPort, complete link training 432 15. Enable panel backlight 433 } 434 #endif 435 436 // make sure VGA display is disabled 437 write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); 438 read32(INTEL_VGA_DISPLAY_CONTROL); 439 440 // Go over each port and set the display mode 441 for (uint32 i = 0; i < gInfo->port_count; i++) { 442 if (gInfo->ports[i] == NULL) 443 continue; 444 if (!gInfo->ports[i]->IsConnected()) 445 continue; 446 447 status_t status = gInfo->ports[i]->SetDisplayMode(&target, colorMode); 448 if (status != B_OK) 449 ERROR("%s: Unable to set display mode!\n", __func__); 450 } 451 452 TRACE("%s: Port configuration completed successfully!\n", __func__); 453 454 // We set the same color mode across all pipes 455 program_pipe_color_modes(colorMode); 456 457 // TODO: This may not be neccesary (see DPMS OFF at top) 458 set_display_power_mode(sharedInfo.dpms_mode); 459 460 // Changing bytes per row seems to be ignored if the plane/pipe is turned 461 // off 462 463 // Always set both pipes, just in case 464 // TODO rework this when we get multiple head support with different 465 // resolutions 466 write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); 467 write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); 468 469 // update shared info 470 sharedInfo.current_mode = target; 471 sharedInfo.bytes_per_row = bytesPerRow; 472 sharedInfo.bits_per_pixel = bitsPerPixel; 473 474 set_frame_buffer_base(); 475 // triggers writing back double-buffered registers 476 // which is INTEL_DISPLAY_X_BYTES_PER_ROW only apparantly 477 478 // Second register dump 479 //dump_registers(); 480 481 return B_OK; 482 } 483 484 485 status_t 486 intel_get_display_mode(display_mode* _currentMode) 487 { 488 CALLED(); 489 490 *_currentMode = gInfo->shared_info->current_mode; 491 492 // This seems unreliable. We should always know the current_mode 493 //retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL); 494 return B_OK; 495 } 496 497 498 status_t 499 intel_get_edid_info(void* info, size_t size, uint32* _version) 500 { 501 if (!gInfo->has_edid) 502 return B_ERROR; 503 if (size < sizeof(struct edid1_info)) 504 return B_BUFFER_OVERFLOW; 505 506 memcpy(info, &gInfo->edid_info, sizeof(struct edid1_info)); 507 *_version = EDID_VERSION_1; 508 return B_OK; 509 } 510 511 512 static int32_t 513 intel_get_backlight_register(bool read) 514 { 515 if (gInfo->shared_info->pch_info == INTEL_PCH_NONE) 516 return MCH_BLC_PWM_CTL; 517 518 if (read) 519 return PCH_SBLC_PWM_CTL2; 520 else 521 return PCH_BLC_PWM_CTL; 522 } 523 524 525 status_t 526 intel_set_brightness(float brightness) 527 { 528 CALLED(); 529 530 if (brightness < 0 || brightness > 1) 531 return B_BAD_VALUE; 532 533 uint32_t period = read32(intel_get_backlight_register(true)) >> 16; 534 535 // The "duty cycle" is a proportion of the period (0 = backlight off, 536 // period = maximum brightness). The low bit must be masked out because 537 // it is apparently used for something else on some Atom machines (no 538 // reference to that in the documentation that I know of). 539 // Additionally we don't want it to be completely 0 here, because then 540 // it becomes hard to turn the display on again (at least until we get 541 // working ACPI keyboard shortcuts for this). So always keep the backlight 542 // at least a little bit on for now. 543 uint32_t duty = (uint32_t)(period * brightness) & 0xfffe; 544 if (duty == 0 && period != 0) 545 duty = 2; 546 547 write32(intel_get_backlight_register(false), duty | (period << 16)); 548 549 return B_OK; 550 } 551 552 553 status_t 554 intel_get_brightness(float* brightness) 555 { 556 CALLED(); 557 558 if (brightness == NULL) 559 return B_BAD_VALUE; 560 561 uint16_t period = read32(intel_get_backlight_register(true)) >> 16; 562 uint16_t duty = read32(intel_get_backlight_register(false)) & 0xffff; 563 *brightness = (float)duty / period; 564 565 return B_OK; 566 } 567 568 569 status_t 570 intel_get_frame_buffer_config(frame_buffer_config* config) 571 { 572 CALLED(); 573 574 uint32 offset = gInfo->shared_info->frame_buffer_offset; 575 576 config->frame_buffer = gInfo->shared_info->graphics_memory + offset; 577 config->frame_buffer_dma 578 = (uint8*)gInfo->shared_info->physical_graphics_memory + offset; 579 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 580 581 return B_OK; 582 } 583 584 585 status_t 586 intel_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 587 { 588 CALLED(); 589 590 if (_low != NULL) { 591 // lower limit of about 48Hz vertical refresh 592 uint32 totalClocks = (uint32)mode->timing.h_total 593 * (uint32)mode->timing.v_total; 594 uint32 low = (totalClocks * 48L) / 1000L; 595 if (low < gInfo->shared_info->pll_info.min_frequency) 596 low = gInfo->shared_info->pll_info.min_frequency; 597 else if (low > gInfo->shared_info->pll_info.max_frequency) 598 return B_ERROR; 599 600 *_low = low; 601 } 602 603 if (_high != NULL) 604 *_high = gInfo->shared_info->pll_info.max_frequency; 605 606 return B_OK; 607 } 608 609 610 status_t 611 intel_move_display(uint16 horizontalStart, uint16 verticalStart) 612 { 613 intel_shared_info &sharedInfo = *gInfo->shared_info; 614 Autolock locker(sharedInfo.accelerant_lock); 615 616 display_mode &mode = sharedInfo.current_mode; 617 618 if (horizontalStart + mode.timing.h_display > mode.virtual_width 619 || verticalStart + mode.timing.v_display > mode.virtual_height) 620 return B_BAD_VALUE; 621 622 mode.h_display_start = horizontalStart; 623 mode.v_display_start = verticalStart; 624 625 set_frame_buffer_base(); 626 627 return B_OK; 628 } 629 630 631 status_t 632 intel_get_timing_constraints(display_timing_constraints* constraints) 633 { 634 CALLED(); 635 return B_ERROR; 636 } 637 638 639 void 640 intel_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 641 { 642 TRACE("%s(colors = %p, first = %u)\n", __func__, colors, first); 643 644 if (colors == NULL) 645 return; 646 647 Autolock locker(gInfo->shared_info->accelerant_lock); 648 649 for (; count-- > 0; first++) { 650 uint32 color = colors[0] << 16 | colors[1] << 8 | colors[2]; 651 colors += 3; 652 653 write32(INTEL_DISPLAY_A_PALETTE + first * sizeof(uint32), color); 654 write32(INTEL_DISPLAY_B_PALETTE + first * sizeof(uint32), color); 655 } 656 } 657