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