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 #if 0 44 // This hack needs to die. Leaving in for a little while 45 // incase we *really* need it. 46 static void 47 retrieve_current_mode(display_mode& mode, uint32 pllRegister) 48 { 49 uint32 pll = read32(pllRegister); 50 uint32 pllDivisor; 51 uint32 hTotalRegister; 52 uint32 vTotalRegister; 53 uint32 hSyncRegister; 54 uint32 vSyncRegister; 55 uint32 imageSizeRegister; 56 uint32 controlRegister; 57 58 if (pllRegister == INTEL_DISPLAY_A_PLL) { 59 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0 60 ? INTEL_DISPLAY_A_PLL_DIVISOR_1 : INTEL_DISPLAY_A_PLL_DIVISOR_0); 61 62 hTotalRegister = INTEL_DISPLAY_A_HTOTAL; 63 vTotalRegister = INTEL_DISPLAY_A_VTOTAL; 64 hSyncRegister = INTEL_DISPLAY_A_HSYNC; 65 vSyncRegister = INTEL_DISPLAY_A_VSYNC; 66 imageSizeRegister = INTEL_DISPLAY_A_IMAGE_SIZE; 67 controlRegister = INTEL_DISPLAY_A_CONTROL; 68 } else if (pllRegister == INTEL_DISPLAY_B_PLL) { 69 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0 70 ? INTEL_DISPLAY_B_PLL_DIVISOR_1 : INTEL_DISPLAY_B_PLL_DIVISOR_0); 71 72 hTotalRegister = INTEL_DISPLAY_B_HTOTAL; 73 vTotalRegister = INTEL_DISPLAY_B_VTOTAL; 74 hSyncRegister = INTEL_DISPLAY_B_HSYNC; 75 vSyncRegister = INTEL_DISPLAY_B_VSYNC; 76 imageSizeRegister = INTEL_DISPLAY_B_IMAGE_SIZE; 77 controlRegister = INTEL_DISPLAY_B_CONTROL; 78 } else { 79 ERROR("%s: PLL not supported\n", __func__); 80 return; 81 } 82 83 pll_divisors divisors; 84 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 85 divisors.m1 = 0; 86 divisors.m2 = (pllDivisor & DISPLAY_PLL_IGD_M2_DIVISOR_MASK) 87 >> DISPLAY_PLL_M2_DIVISOR_SHIFT; 88 divisors.n = ((pllDivisor & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 89 >> DISPLAY_PLL_N_DIVISOR_SHIFT) - 1; 90 } else { 91 divisors.m1 = (pllDivisor & DISPLAY_PLL_M1_DIVISOR_MASK) 92 >> DISPLAY_PLL_M1_DIVISOR_SHIFT; 93 divisors.m2 = (pllDivisor & DISPLAY_PLL_M2_DIVISOR_MASK) 94 >> DISPLAY_PLL_M2_DIVISOR_SHIFT; 95 divisors.n = (pllDivisor & DISPLAY_PLL_N_DIVISOR_MASK) 96 >> DISPLAY_PLL_N_DIVISOR_SHIFT; 97 } 98 99 pll_limits limits; 100 get_pll_limits(&limits, false); 101 // TODO: Detect LVDS connector vs assume no 102 103 if (gInfo->shared_info->device_type.Generation() >= 3) { 104 105 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 106 divisors.post1 = (pll & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK) 107 >> DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT; 108 } else { 109 divisors.post1 = (pll & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK) 110 >> DISPLAY_PLL_POST1_DIVISOR_SHIFT; 111 } 112 113 if (pllRegister == INTEL_DISPLAY_B_PLL 114 && !gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) { 115 // TODO: Fix this? Need to support dual channel LVDS. 116 divisors.post2 = LVDS_POST2_RATE_SLOW; 117 } else { 118 if ((pll & DISPLAY_PLL_DIVIDE_HIGH) != 0) 119 divisors.post2 = limits.max.post2; 120 else 121 divisors.post2 = limits.min.post2; 122 } 123 } else { 124 // 8xx 125 divisors.post1 = (pll & DISPLAY_PLL_POST1_DIVISOR_MASK) 126 >> DISPLAY_PLL_POST1_DIVISOR_SHIFT; 127 128 if ((pll & DISPLAY_PLL_DIVIDE_4X) != 0) 129 divisors.post2 = limits.max.post2; 130 else 131 divisors.post2 = limits.min.post2; 132 } 133 134 divisors.m = 5 * divisors.m1 + divisors.m2; 135 divisors.post = divisors.post1 * divisors.post2; 136 137 float referenceClock 138 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 139 float pixelClock 140 = ((referenceClock * divisors.m) / divisors.n) / divisors.post; 141 142 // timing 143 144 mode.timing.pixel_clock = uint32(pixelClock * 1000); 145 mode.timing.flags = 0; 146 147 uint32 value = read32(hTotalRegister); 148 mode.timing.h_total = (value >> 16) + 1; 149 mode.timing.h_display = (value & 0xffff) + 1; 150 151 value = read32(hSyncRegister); 152 mode.timing.h_sync_end = (value >> 16) + 1; 153 mode.timing.h_sync_start = (value & 0xffff) + 1; 154 155 value = read32(vTotalRegister); 156 mode.timing.v_total = (value >> 16) + 1; 157 mode.timing.v_display = (value & 0xffff) + 1; 158 159 value = read32(vSyncRegister); 160 mode.timing.v_sync_end = (value >> 16) + 1; 161 mode.timing.v_sync_start = (value & 0xffff) + 1; 162 163 // image size and color space 164 165 value = read32(imageSizeRegister); 166 mode.virtual_width = (value >> 16) + 1; 167 mode.virtual_height = (value & 0xffff) + 1; 168 169 // using virtual size based on image size is the 'proper' way to do it, 170 // however the bios appears to be suggesting scaling or somesuch, so ignore 171 // the proper virtual dimension for now if they'd suggest a smaller size. 172 if (mode.virtual_width < mode.timing.h_display) 173 mode.virtual_width = mode.timing.h_display; 174 if (mode.virtual_height < mode.timing.v_display) 175 mode.virtual_height = mode.timing.v_display; 176 177 value = read32(controlRegister); 178 switch (value & DISPLAY_CONTROL_COLOR_MASK) { 179 case DISPLAY_CONTROL_RGB32: 180 default: 181 mode.space = B_RGB32; 182 break; 183 case DISPLAY_CONTROL_RGB16: 184 mode.space = B_RGB16; 185 break; 186 case DISPLAY_CONTROL_RGB15: 187 mode.space = B_RGB15; 188 break; 189 case DISPLAY_CONTROL_CMAP8: 190 mode.space = B_CMAP8; 191 break; 192 } 193 194 mode.h_display_start = 0; 195 mode.v_display_start = 0; 196 mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS 197 | B_DPMS | B_SUPPORTS_OVERLAYS; 198 } 199 #endif 200 201 202 static void 203 get_color_space_format(const display_mode &mode, uint32 &colorMode, 204 uint32 &bytesPerRow, uint32 &bitsPerPixel) 205 { 206 uint32 bytesPerPixel; 207 208 switch (mode.space) { 209 case B_RGB32_LITTLE: 210 colorMode = DISPLAY_CONTROL_RGB32; 211 bytesPerPixel = 4; 212 bitsPerPixel = 32; 213 break; 214 case B_RGB16_LITTLE: 215 colorMode = DISPLAY_CONTROL_RGB16; 216 bytesPerPixel = 2; 217 bitsPerPixel = 16; 218 break; 219 case B_RGB15_LITTLE: 220 colorMode = DISPLAY_CONTROL_RGB15; 221 bytesPerPixel = 2; 222 bitsPerPixel = 15; 223 break; 224 case B_CMAP8: 225 default: 226 colorMode = DISPLAY_CONTROL_CMAP8; 227 bytesPerPixel = 1; 228 bitsPerPixel = 8; 229 break; 230 } 231 232 bytesPerRow = mode.virtual_width * bytesPerPixel; 233 234 // Make sure bytesPerRow is a multiple of 64 235 // TODO: check if the older chips have the same restriction! 236 if ((bytesPerRow & 63) != 0) 237 bytesPerRow = (bytesPerRow + 63) & ~63; 238 } 239 240 241 static bool 242 sanitize_display_mode(display_mode& mode) 243 { 244 // Some cards only support even pixel counts, while others require an odd 245 // one. 246 uint16 pixelCount = 1; 247 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_Gxx) 248 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x) 249 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_94x) 250 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_91x) 251 || gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_8xx) 252 || gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_7xx)) { 253 pixelCount = 2; 254 } 255 256 // TODO: verify constraints - these are more or less taken from the 257 // radeon driver! 258 display_constraints constraints = { 259 // resolution 260 320, 8192, 200, 4096, 261 // pixel clock 262 gInfo->shared_info->pll_info.min_frequency, 263 gInfo->shared_info->pll_info.max_frequency, 264 // horizontal 265 {pixelCount, 0, 8160, 32, 8192, 0, 8192}, 266 {1, 1, 4092, 2, 63, 1, 4096} 267 }; 268 269 return sanitize_display_mode(mode, constraints, 270 gInfo->has_edid ? &gInfo->edid_info : NULL); 271 } 272 273 274 // #pragma mark - 275 276 277 void 278 set_frame_buffer_base() 279 { 280 intel_shared_info &sharedInfo = *gInfo->shared_info; 281 display_mode &mode = gInfo->current_mode; 282 283 uint32 baseRegister; 284 uint32 surfaceRegister; 285 286 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { 287 baseRegister = INTEL_DISPLAY_A_BASE; 288 surfaceRegister = INTEL_DISPLAY_A_SURFACE; 289 } else { 290 baseRegister = INTEL_DISPLAY_B_BASE; 291 surfaceRegister = INTEL_DISPLAY_B_SURFACE; 292 } 293 294 if (sharedInfo.device_type.InGroup(INTEL_GROUP_96x) 295 || sharedInfo.device_type.InGroup(INTEL_GROUP_G4x) 296 || sharedInfo.device_type.InGroup(INTEL_GROUP_ILK) 297 || sharedInfo.device_type.InFamily(INTEL_FAMILY_SER5) 298 || sharedInfo.device_type.InFamily(INTEL_FAMILY_SOC0)) { 299 write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row 300 + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); 301 read32(baseRegister); 302 write32(surfaceRegister, sharedInfo.frame_buffer_offset); 303 read32(surfaceRegister); 304 } else { 305 write32(baseRegister, sharedInfo.frame_buffer_offset 306 + mode.v_display_start * sharedInfo.bytes_per_row 307 + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); 308 read32(baseRegister); 309 } 310 } 311 312 313 /*! Creates the initial mode list of the primary accelerant. 314 It's called from intel_init_accelerant(). 315 */ 316 status_t 317 create_mode_list(void) 318 { 319 for (uint32 i = 0; i < gInfo->port_count; i++) { 320 if (gInfo->ports[i] == NULL) 321 continue; 322 323 status_t status = gInfo->ports[i]->GetEDID(&gInfo->edid_info); 324 if (status == B_OK) 325 gInfo->has_edid = true; 326 } 327 328 // If no EDID, but have vbt from driver, use that mode 329 if (!gInfo->has_edid && gInfo->shared_info->got_vbt) { 330 // We could not read any EDID info. Fallback to creating a list with 331 // only the mode set up by the BIOS. 332 333 // TODO: support lower modes via scaling and windowing 334 size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) 335 & ~(B_PAGE_SIZE - 1); 336 337 display_mode* list; 338 area_id area = create_area("intel extreme modes", 339 (void**)&list, B_ANY_ADDRESS, size, B_NO_LOCK, 340 B_READ_AREA | B_WRITE_AREA); 341 if (area < 0) 342 return area; 343 344 memcpy(list, &gInfo->shared_info->panel_mode, sizeof(display_mode)); 345 346 gInfo->mode_list_area = area; 347 gInfo->mode_list = list; 348 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 349 gInfo->shared_info->mode_count = 1; 350 return B_OK; 351 } 352 353 // Otherwise return the 'real' list of modes 354 display_mode* list; 355 uint32 count = 0; 356 gInfo->mode_list_area = create_display_modes("intel extreme modes", 357 gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL, 358 &list, &count); 359 if (gInfo->mode_list_area < B_OK) 360 return gInfo->mode_list_area; 361 362 gInfo->mode_list = list; 363 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 364 gInfo->shared_info->mode_count = count; 365 366 return B_OK; 367 } 368 369 370 void 371 wait_for_vblank(void) 372 { 373 acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT, 374 25000); 375 // With the output turned off via DPMS, we might not get any interrupts 376 // anymore that's why we don't wait forever for it. 377 } 378 379 380 // #pragma mark - 381 382 383 uint32 384 intel_accelerant_mode_count(void) 385 { 386 CALLED(); 387 return gInfo->shared_info->mode_count; 388 } 389 390 391 status_t 392 intel_get_mode_list(display_mode* modeList) 393 { 394 CALLED(); 395 memcpy(modeList, gInfo->mode_list, 396 gInfo->shared_info->mode_count * sizeof(display_mode)); 397 return B_OK; 398 } 399 400 401 status_t 402 intel_propose_display_mode(display_mode* target, const display_mode* low, 403 const display_mode* high) 404 { 405 CALLED(); 406 407 // first search for the specified mode in the list, if no mode is found 408 // try to fix the target mode in sanitize_display_mode 409 // TODO: Only sanitize_display_mode should be used. However, at the moments 410 // the mode constraints are not optimal and do not work for all 411 // configurations. 412 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 413 display_mode *mode = &gInfo->mode_list[i]; 414 415 // TODO: improve this, ie. adapt pixel clock to allowed values!!! 416 417 if (target->virtual_width != mode->virtual_width 418 || target->virtual_height != mode->virtual_height 419 || target->space != mode->space) { 420 continue; 421 } 422 423 *target = *mode; 424 return B_OK; 425 } 426 427 sanitize_display_mode(*target); 428 429 return is_display_mode_within_bounds(*target, *low, *high) 430 ? B_OK : B_BAD_VALUE; 431 } 432 433 434 status_t 435 intel_set_display_mode(display_mode* mode) 436 { 437 TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, 438 mode->virtual_width, mode->virtual_height); 439 440 if (mode == NULL) 441 return B_BAD_VALUE; 442 443 display_mode target = *mode; 444 445 // TODO: it may be acceptable to continue when using panel fitting or 446 // centering, since the data from propose_display_mode will not actually be 447 // used as is in this case. 448 if (sanitize_display_mode(target)) { 449 TRACE("%s: invalid mode set!\n", __func__); 450 return B_BAD_VALUE; 451 } 452 453 uint32 colorMode, bytesPerRow, bitsPerPixel; 454 get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); 455 456 // TODO: do not go further if the mode is identical to the current one. 457 // This would avoid the screen being off when switching workspaces when they 458 // have the same resolution. 459 460 intel_shared_info &sharedInfo = *gInfo->shared_info; 461 Autolock locker(sharedInfo.accelerant_lock); 462 463 // First register dump 464 //dump_registers(); 465 466 // TODO: This may not be neccesary 467 set_display_power_mode(B_DPMS_OFF); 468 469 // free old and allocate new frame buffer in graphics memory 470 471 intel_free_memory(sharedInfo.frame_buffer); 472 473 addr_t base; 474 if (intel_allocate_memory(bytesPerRow * target.virtual_height, 0, 475 base) < B_OK) { 476 // oh, how did that happen? Unfortunately, there is no really good way 477 // back 478 if (intel_allocate_memory(gInfo->current_mode.virtual_height 479 * sharedInfo.bytes_per_row, 0, base) == B_OK) { 480 sharedInfo.frame_buffer = base; 481 sharedInfo.frame_buffer_offset = base 482 - (addr_t)sharedInfo.graphics_memory; 483 set_frame_buffer_base(); 484 } 485 486 TRACE("%s: Failed to allocate framebuffer !\n", __func__); 487 return B_NO_MEMORY; 488 } 489 490 // clear frame buffer before using it 491 memset((uint8*)base, 0, bytesPerRow * target.virtual_height); 492 sharedInfo.frame_buffer = base; 493 sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory; 494 495 #if 0 496 if ((gInfo->head_mode & HEAD_MODE_TESTING) != 0) { 497 // 1. Enable panel power as needed to retrieve panel configuration 498 // (use AUX VDD enable bit) 499 // skip, did detection already, might need that before that though 500 501 // 2. Enable PCH clock reference source and PCH SSC modulator, 502 // wait for warmup (Can be done anytime before enabling port) 503 // skip, most certainly already set up by bios to use other ports, 504 // will need for coldstart though 505 506 // 3. If enabling CPU embedded DisplayPort A: (Can be done anytime 507 // before enabling CPU pipe or port) 508 // a. Enable PCH 120MHz clock source output to CPU, wait for DMI 509 // latency 510 // b. Configure and enable CPU DisplayPort PLL in the DisplayPort A 511 // register, wait for warmup 512 // skip, not doing eDP right now, should go into 513 // EmbeddedDisplayPort class though 514 515 // 4. If enabling port on PCH: (Must be done before enabling CPU pipe 516 // or FDI) 517 // a. Enable PCH FDI Receiver PLL, wait for warmup plus DMI latency 518 // b. Switch from Rawclk to PCDclk in FDI Receiver (FDI A OR FDI B) 519 // c. [DevSNB] Enable CPU FDI Transmitter PLL, wait for warmup 520 // d. [DevILK] CPU FDI PLL is always on and does not need to be 521 // enabled 522 FDILink* link = pipe->FDILink(); 523 if (link != NULL) { 524 link->Receiver().EnablePLL(); 525 link->Receiver().SwitchClock(true); 526 link->Transmitter().EnablePLL(); 527 } 528 529 // 5. Enable CPU panel fitter if needed for hires, required for VGA 530 // (Can be done anytime before enabling CPU pipe) 531 PanelFitter* fitter = pipe->PanelFitter(); 532 if (fitter != NULL) 533 fitter->Enable(mode); 534 535 // 6. Configure CPU pipe timings, M/N/TU, and other pipe settings 536 // (Can be done anytime before enabling CPU pipe) 537 pll_divisors divisors; 538 compute_pll_divisors(target, divisors, false); 539 pipe->ConfigureTimings(divisors); 540 541 // 7. Enable CPU pipe 542 pipe->Enable(); 543 544 8. Configure and enable CPU planes (VGA or hires) 545 9. If enabling port on PCH: 546 // a. Program PCH FDI Receiver TU size same as Transmitter TU size for TU error checking 547 // b. Train FDI 548 // i. Set pre-emphasis and voltage (iterate if training steps fail) 549 ii. Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled. 550 iii. Wait for FDI training pattern 1 time 551 iv. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for bit lock in bit 8 (retry at least once if no lock) 552 v. Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver 553 vi. Wait for FDI training pattern 2 time 554 vii. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for symbol lock in bit 9 (retry at least once if no 555 lock) 556 viii. Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver 557 ix. Wait for FDI idle pattern time for link to become active 558 c. Configure and enable PCH DPLL, wait for PCH DPLL warmup (Can be done anytime before enabling 559 PCH transcoder) 560 d. [DevCPT] Configure DPLL SEL to set the DPLL to transcoder mapping and enable DPLL to the 561 transcoder. 562 e. [DevCPT] Configure DPLL_CTL DPLL_HDMI_multipler. 563 f. Configure PCH transcoder timings, M/N/TU, and other transcoder settings (should match CPU settings). 564 g. [DevCPT] Configure and enable Transcoder DisplayPort Control if DisplayPort will be used 565 h. Enable PCH transcoder 566 10. Enable ports (DisplayPort must enable in training pattern 1) 567 11. Enable panel power through panel power sequencing 568 12. Wait for panel power sequencing to reach enabled steady state 569 13. Disable panel power override 570 14. If DisplayPort, complete link training 571 15. Enable panel backlight 572 } 573 #endif 574 575 // make sure VGA display is disabled 576 write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); 577 read32(INTEL_VGA_DISPLAY_CONTROL); 578 579 // Go over each port and set the display mode 580 for (uint32 i = 0; i < gInfo->port_count; i++) { 581 if (gInfo->ports[i] == NULL) 582 continue; 583 if (!gInfo->ports[i]->IsConnected()) 584 continue; 585 586 status_t status = gInfo->ports[i]->SetDisplayMode(&target, colorMode); 587 if (status != B_OK) 588 ERROR("%s: Unable to set display mode!\n", __func__); 589 } 590 591 TRACE("%s: Port configuration completed successfully!\n", __func__); 592 593 // We set the same color mode across all pipes 594 program_pipe_color_modes(colorMode); 595 596 // TODO: This may not be neccesary (see DPMS OFF at top) 597 set_display_power_mode(sharedInfo.dpms_mode); 598 599 // Changing bytes per row seems to be ignored if the plane/pipe is turned 600 // off 601 602 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) 603 write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); 604 if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) 605 write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); 606 607 // update shared info 608 gInfo->current_mode = target; 609 610 // TODO: move to gInfo 611 sharedInfo.bytes_per_row = bytesPerRow; 612 sharedInfo.bits_per_pixel = bitsPerPixel; 613 614 set_frame_buffer_base(); 615 // triggers writing back double-buffered registers 616 617 // Second register dump 618 //dump_registers(); 619 620 return B_OK; 621 } 622 623 624 status_t 625 intel_get_display_mode(display_mode* _currentMode) 626 { 627 CALLED(); 628 629 *_currentMode = gInfo->current_mode; 630 631 // This seems unreliable. We should always know the current_mode 632 //retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL); 633 return B_OK; 634 } 635 636 637 status_t 638 intel_get_edid_info(void* info, size_t size, uint32* _version) 639 { 640 CALLED(); 641 642 if (!gInfo->has_edid) 643 return B_ERROR; 644 if (size < sizeof(struct edid1_info)) 645 return B_BUFFER_OVERFLOW; 646 647 memcpy(info, &gInfo->edid_info, sizeof(struct edid1_info)); 648 *_version = EDID_VERSION_1; 649 return B_OK; 650 } 651 652 653 status_t 654 intel_get_frame_buffer_config(frame_buffer_config* config) 655 { 656 CALLED(); 657 658 uint32 offset = gInfo->shared_info->frame_buffer_offset; 659 660 config->frame_buffer = gInfo->shared_info->graphics_memory + offset; 661 config->frame_buffer_dma 662 = (uint8*)gInfo->shared_info->physical_graphics_memory + offset; 663 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 664 665 return B_OK; 666 } 667 668 669 status_t 670 intel_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 671 { 672 CALLED(); 673 674 if (_low != NULL) { 675 // lower limit of about 48Hz vertical refresh 676 uint32 totalClocks = (uint32)mode->timing.h_total 677 * (uint32)mode->timing.v_total; 678 uint32 low = (totalClocks * 48L) / 1000L; 679 if (low < gInfo->shared_info->pll_info.min_frequency) 680 low = gInfo->shared_info->pll_info.min_frequency; 681 else if (low > gInfo->shared_info->pll_info.max_frequency) 682 return B_ERROR; 683 684 *_low = low; 685 } 686 687 if (_high != NULL) 688 *_high = gInfo->shared_info->pll_info.max_frequency; 689 690 return B_OK; 691 } 692 693 694 status_t 695 intel_move_display(uint16 horizontalStart, uint16 verticalStart) 696 { 697 CALLED(); 698 699 intel_shared_info &sharedInfo = *gInfo->shared_info; 700 Autolock locker(sharedInfo.accelerant_lock); 701 702 display_mode &mode = gInfo->current_mode; 703 704 if (horizontalStart + mode.timing.h_display > mode.virtual_width 705 || verticalStart + mode.timing.v_display > mode.virtual_height) 706 return B_BAD_VALUE; 707 708 mode.h_display_start = horizontalStart; 709 mode.v_display_start = verticalStart; 710 711 set_frame_buffer_base(); 712 713 return B_OK; 714 } 715 716 717 status_t 718 intel_get_timing_constraints(display_timing_constraints* constraints) 719 { 720 CALLED(); 721 return B_ERROR; 722 } 723 724 725 void 726 intel_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 727 { 728 TRACE("%s(colors = %p, first = %u)\n", __func__, colors, first); 729 730 if (colors == NULL) 731 return; 732 733 Autolock locker(gInfo->shared_info->accelerant_lock); 734 735 for (; count-- > 0; first++) { 736 uint32 color = colors[0] << 16 | colors[1] << 8 | colors[2]; 737 colors += 3; 738 739 write32(INTEL_DISPLAY_A_PALETTE + first * sizeof(uint32), color); 740 write32(INTEL_DISPLAY_B_PALETTE + first * sizeof(uint32), color); 741 } 742 } 743