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 // first search for the specified mode in the list, if no mode is found 277 // try to fix the target mode in sanitize_display_mode 278 // TODO: Only sanitize_display_mode should be used. However, at the moment 279 // the mode constraints are not optimal and do not work for all 280 // configurations. 281 uint32 VirtualWidth = target->virtual_width; 282 uint32 VirtualHeight = target->virtual_height; 283 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 284 display_mode *mode = &gInfo->mode_list[i]; 285 286 // TODO: improve this, ie. adapt pixel clock to allowed values!!! 287 288 if (target->timing.h_display != mode->timing.h_display 289 || target->timing.v_display != mode->timing.v_display 290 || target->space != mode->space) { 291 continue; 292 } 293 294 *target = *mode; 295 // retain requested virtual size 296 target->virtual_width = VirtualWidth; 297 target->virtual_height = VirtualHeight; 298 // (most) modeflags are outputs from us (the driver). So we should 299 // set them depending on the mode and the current hardware config 300 target->flags |= B_SCROLL; 301 return B_OK; 302 } 303 304 sanitize_display_mode(*target); 305 // (most) modeflags are outputs from us (the driver). So we should 306 // set them depending on the mode and the current hardware config 307 target->flags |= B_SCROLL; 308 309 return is_display_mode_within_bounds(*target, *low, *high) 310 ? B_OK : B_BAD_VALUE; 311 } 312 313 314 status_t 315 intel_set_display_mode(display_mode* mode) 316 { 317 if (mode == NULL) 318 return B_BAD_VALUE; 319 320 TRACE("%s(%" B_PRIu16 "x%" B_PRIu16 ", virtual: %" B_PRIu16 "x%" B_PRIu16 ")\n", __func__, 321 mode->timing.h_display, mode->timing.v_display, mode->virtual_width, mode->virtual_height); 322 323 display_mode target = *mode; 324 325 if (sanitize_display_mode(target)) { //should be in proposemode.. 326 TRACE("Video mode was adjusted by sanitize_display_mode\n"); 327 TRACE("Initial mode: Hd %d Hs %d He %d Ht %d Vd %d Vs %d Ve %d Vt %d\n", 328 mode->timing.h_display, mode->timing.h_sync_start, 329 mode->timing.h_sync_end, mode->timing.h_total, 330 mode->timing.v_display, mode->timing.v_sync_start, 331 mode->timing.v_sync_end, mode->timing.v_total); 332 TRACE("Sanitized: Hd %d Hs %d He %d Ht %d Vd %d Vs %d Ve %d Vt %d\n", 333 target.timing.h_display, target.timing.h_sync_start, 334 target.timing.h_sync_end, target.timing.h_total, 335 target.timing.v_display, target.timing.v_sync_start, 336 target.timing.v_sync_end, target.timing.v_total); 337 } 338 if (intel_propose_display_mode(&target, &target, &target) != B_OK) 339 return B_BAD_VALUE; 340 341 uint32 colorMode, bytesPerRow, bitsPerPixel; 342 get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); 343 344 // TODO: do not go further if the mode is identical to the current one. 345 // This would avoid the screen being off when switching workspaces when they 346 // have the same resolution. 347 348 intel_shared_info &sharedInfo = *gInfo->shared_info; 349 Autolock locker(sharedInfo.accelerant_lock); 350 351 // First register dump 352 //dump_registers(); 353 354 // TODO: This may not be neccesary 355 set_display_power_mode(B_DPMS_OFF); 356 357 // free old and allocate new frame buffer in graphics memory 358 359 intel_free_memory(sharedInfo.frame_buffer); 360 361 addr_t base; 362 if (intel_allocate_memory(bytesPerRow * target.virtual_height, 0, 363 base) < B_OK) { 364 // oh, how did that happen? Unfortunately, there is no really good way 365 // back. Try to restore a framebuffer for the previous mode, at least. 366 if (intel_allocate_memory(sharedInfo.current_mode.virtual_height 367 * sharedInfo.bytes_per_row, 0, base) == B_OK) { 368 sharedInfo.frame_buffer = base; 369 sharedInfo.frame_buffer_offset = base 370 - (addr_t)sharedInfo.graphics_memory; 371 set_frame_buffer_base(); 372 } 373 374 ERROR("%s: Failed to allocate framebuffer !\n", __func__); 375 return B_NO_MEMORY; 376 } 377 378 // clear frame buffer before using it 379 memset((uint8*)base, 0, bytesPerRow * target.virtual_height); 380 sharedInfo.frame_buffer = base; 381 sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory; 382 383 #if 0 384 if ((gInfo->head_mode & HEAD_MODE_TESTING) != 0) { 385 // 1. Enable panel power as needed to retrieve panel configuration 386 // (use AUX VDD enable bit) 387 // skip, did detection already, might need that before that though 388 389 // 2. Enable PCH clock reference source and PCH SSC modulator, 390 // wait for warmup (Can be done anytime before enabling port) 391 // skip, most certainly already set up by bios to use other ports, 392 // will need for coldstart though 393 394 // 3. If enabling CPU embedded DisplayPort A: (Can be done anytime 395 // before enabling CPU pipe or port) 396 // a. Enable PCH 120MHz clock source output to CPU, wait for DMI 397 // latency 398 // b. Configure and enable CPU DisplayPort PLL in the DisplayPort A 399 // register, wait for warmup 400 // skip, not doing eDP right now, should go into 401 // EmbeddedDisplayPort class though 402 403 // 4. If enabling port on PCH: (Must be done before enabling CPU pipe 404 // or FDI) 405 // a. Enable PCH FDI Receiver PLL, wait for warmup plus DMI latency 406 // b. Switch from Rawclk to PCDclk in FDI Receiver (FDI A OR FDI B) 407 // c. [DevSNB] Enable CPU FDI Transmitter PLL, wait for warmup 408 // d. [DevILK] CPU FDI PLL is always on and does not need to be 409 // enabled 410 FDILink* link = pipe->FDILink(); 411 if (link != NULL) { 412 link->Receiver().EnablePLL(); 413 link->Receiver().SwitchClock(true); 414 link->Transmitter().EnablePLL(); 415 } 416 417 // 5. Enable CPU panel fitter if needed for hires, required for VGA 418 // (Can be done anytime before enabling CPU pipe) 419 PanelFitter* fitter = pipe->PanelFitter(); 420 if (fitter != NULL) 421 fitter->Enable(mode); 422 423 // 6. Configure CPU pipe timings, M/N/TU, and other pipe settings 424 // (Can be done anytime before enabling CPU pipe) 425 pll_divisors divisors; 426 compute_pll_divisors(target, divisors, false); 427 pipe->ConfigureTimings(divisors); 428 429 // 7. Enable CPU pipe 430 pipe->Enable(); 431 432 8. Configure and enable CPU planes (VGA or hires) 433 9. If enabling port on PCH: 434 // a. Program PCH FDI Receiver TU size same as Transmitter TU size for TU error checking 435 // b. Train FDI 436 // i. Set pre-emphasis and voltage (iterate if training steps fail) 437 ii. Enable CPU FDI Transmitter and PCH FDI Receiver with Training Pattern 1 enabled. 438 iii. Wait for FDI training pattern 1 time 439 iv. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for bit lock in bit 8 (retry at least once if no lock) 440 v. Enable training pattern 2 on CPU FDI Transmitter and PCH FDI Receiver 441 vi. Wait for FDI training pattern 2 time 442 vii. Read PCH FDI Receiver ISR ([DevIBX-B+] IIR) for symbol lock in bit 9 (retry at least once if no 443 lock) 444 viii. Enable normal pixel output on CPU FDI Transmitter and PCH FDI Receiver 445 ix. Wait for FDI idle pattern time for link to become active 446 c. Configure and enable PCH DPLL, wait for PCH DPLL warmup (Can be done anytime before enabling 447 PCH transcoder) 448 d. [DevCPT] Configure DPLL SEL to set the DPLL to transcoder mapping and enable DPLL to the 449 transcoder. 450 e. [DevCPT] Configure DPLL_CTL DPLL_HDMI_multipler. 451 f. Configure PCH transcoder timings, M/N/TU, and other transcoder settings (should match CPU settings). 452 g. [DevCPT] Configure and enable Transcoder DisplayPort Control if DisplayPort will be used 453 h. Enable PCH transcoder 454 10. Enable ports (DisplayPort must enable in training pattern 1) 455 11. Enable panel power through panel power sequencing 456 12. Wait for panel power sequencing to reach enabled steady state 457 13. Disable panel power override 458 14. If DisplayPort, complete link training 459 15. Enable panel backlight 460 } 461 #endif 462 463 // make sure VGA display is disabled 464 write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); 465 read32(INTEL_VGA_DISPLAY_CONTROL); 466 467 // Go over each port and set the display mode 468 for (uint32 i = 0; i < gInfo->port_count; i++) { 469 if (gInfo->ports[i] == NULL) 470 continue; 471 if (!gInfo->ports[i]->IsConnected()) 472 continue; 473 474 status_t status = gInfo->ports[i]->SetDisplayMode(&target, colorMode); 475 if (status != B_OK) 476 ERROR("%s: Unable to set display mode!\n", __func__); 477 } 478 479 TRACE("%s: Port configuration completed successfully!\n", __func__); 480 481 // We set the same color mode across all pipes 482 program_pipe_color_modes(colorMode); 483 484 // TODO: This may not be neccesary (see DPMS OFF at top) 485 set_display_power_mode(sharedInfo.dpms_mode); 486 487 // Changing bytes per row seems to be ignored if the plane/pipe is turned 488 // off 489 490 // Always set both pipes, just in case 491 // TODO rework this when we get multiple head support with different 492 // resolutions 493 write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); 494 write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); 495 496 // update shared info 497 sharedInfo.current_mode = target; 498 sharedInfo.bytes_per_row = bytesPerRow; 499 sharedInfo.bits_per_pixel = bitsPerPixel; 500 501 set_frame_buffer_base(); 502 // triggers writing back double-buffered registers 503 // which is INTEL_DISPLAY_X_BYTES_PER_ROW only apparantly 504 505 // Second register dump 506 //dump_registers(); 507 508 return B_OK; 509 } 510 511 512 status_t 513 intel_get_display_mode(display_mode* _currentMode) 514 { 515 CALLED(); 516 517 *_currentMode = gInfo->shared_info->current_mode; 518 519 // This seems unreliable. We should always know the current_mode 520 //retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL); 521 return B_OK; 522 } 523 524 525 status_t 526 intel_get_edid_info(void* info, size_t size, uint32* _version) 527 { 528 if (!gInfo->has_edid) 529 return B_ERROR; 530 if (size < sizeof(struct edid1_info)) 531 return B_BUFFER_OVERFLOW; 532 533 memcpy(info, &gInfo->edid_info, sizeof(struct edid1_info)); 534 *_version = EDID_VERSION_1; 535 return B_OK; 536 } 537 538 539 static int32_t 540 intel_get_backlight_register(bool read) 541 { 542 if (gInfo->shared_info->pch_info == INTEL_PCH_NONE) 543 return MCH_BLC_PWM_CTL; 544 545 if (read) 546 return PCH_SBLC_PWM_CTL2; 547 else 548 return PCH_BLC_PWM_CTL; 549 } 550 551 552 status_t 553 intel_set_brightness(float brightness) 554 { 555 CALLED(); 556 557 if (brightness < 0 || brightness > 1) 558 return B_BAD_VALUE; 559 560 uint32_t period = read32(intel_get_backlight_register(true)) >> 16; 561 562 // The "duty cycle" is a proportion of the period (0 = backlight off, 563 // period = maximum brightness). The low bit must be masked out because 564 // it is apparently used for something else on some Atom machines (no 565 // reference to that in the documentation that I know of). 566 // Additionally we don't want it to be completely 0 here, because then 567 // it becomes hard to turn the display on again (at least until we get 568 // working ACPI keyboard shortcuts for this). So always keep the backlight 569 // at least a little bit on for now. 570 uint32_t duty = (uint32_t)(period * brightness) & 0xfffe; 571 if (duty == 0 && period != 0) 572 duty = 2; 573 574 write32(intel_get_backlight_register(false), duty | (period << 16)); 575 576 return B_OK; 577 } 578 579 580 status_t 581 intel_get_brightness(float* brightness) 582 { 583 CALLED(); 584 585 if (brightness == NULL) 586 return B_BAD_VALUE; 587 588 uint16_t period = read32(intel_get_backlight_register(true)) >> 16; 589 uint16_t duty = read32(intel_get_backlight_register(false)) & 0xffff; 590 *brightness = (float)duty / period; 591 592 return B_OK; 593 } 594 595 596 status_t 597 intel_get_frame_buffer_config(frame_buffer_config* config) 598 { 599 CALLED(); 600 601 uint32 offset = gInfo->shared_info->frame_buffer_offset; 602 603 config->frame_buffer = gInfo->shared_info->graphics_memory + offset; 604 config->frame_buffer_dma 605 = (uint8*)gInfo->shared_info->physical_graphics_memory + offset; 606 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 607 608 return B_OK; 609 } 610 611 612 status_t 613 intel_get_pixel_clock_limits(display_mode* mode, uint32* _low, uint32* _high) 614 { 615 CALLED(); 616 617 if (_low != NULL) { 618 // lower limit of about 48Hz vertical refresh 619 uint32 totalClocks = (uint32)mode->timing.h_total 620 * (uint32)mode->timing.v_total; 621 uint32 low = (totalClocks * 48L) / 1000L; 622 if (low < gInfo->shared_info->pll_info.min_frequency) 623 low = gInfo->shared_info->pll_info.min_frequency; 624 else if (low > gInfo->shared_info->pll_info.max_frequency) 625 return B_ERROR; 626 627 *_low = low; 628 } 629 630 if (_high != NULL) 631 *_high = gInfo->shared_info->pll_info.max_frequency; 632 633 return B_OK; 634 } 635 636 637 status_t 638 intel_move_display(uint16 horizontalStart, uint16 verticalStart) 639 { 640 intel_shared_info &sharedInfo = *gInfo->shared_info; 641 Autolock locker(sharedInfo.accelerant_lock); 642 643 display_mode &mode = sharedInfo.current_mode; 644 645 if (horizontalStart + mode.timing.h_display > mode.virtual_width 646 || verticalStart + mode.timing.v_display > mode.virtual_height) 647 return B_BAD_VALUE; 648 649 mode.h_display_start = horizontalStart; 650 mode.v_display_start = verticalStart; 651 652 set_frame_buffer_base(); 653 654 return B_OK; 655 } 656 657 658 status_t 659 intel_get_timing_constraints(display_timing_constraints* constraints) 660 { 661 CALLED(); 662 return B_ERROR; 663 } 664 665 666 void 667 intel_set_indexed_colors(uint count, uint8 first, uint8* colors, uint32 flags) 668 { 669 TRACE("%s(colors = %p, first = %u)\n", __func__, colors, first); 670 671 if (colors == NULL) 672 return; 673 674 Autolock locker(gInfo->shared_info->accelerant_lock); 675 676 for (; count-- > 0; first++) { 677 uint32 color = colors[0] << 16 | colors[1] << 8 | colors[2]; 678 colors += 3; 679 680 write32(INTEL_DISPLAY_A_PALETTE + first * sizeof(uint32), color); 681 write32(INTEL_DISPLAY_B_PALETTE + first * sizeof(uint32), color); 682 } 683 } 684