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