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 "accelerant_protos.h" 14 #include "accelerant.h" 15 #include "utility.h" 16 17 #include <stdio.h> 18 #include <string.h> 19 #include <math.h> 20 21 #include <create_display_modes.h> 22 #include <ddc.h> 23 #include <edid.h> 24 25 26 #define TRACE_MODE 27 #ifdef TRACE_MODE 28 extern "C" void _sPrintf(const char *format, ...); 29 # define TRACE(x) _sPrintf x 30 #else 31 # define TRACE(x) ; 32 #endif 33 34 35 struct display_registers { 36 uint32 pll; 37 uint32 divisors; 38 uint32 control; 39 uint32 pipe_config; 40 uint32 horiz_total; 41 uint32 horiz_blank; 42 uint32 horiz_sync; 43 uint32 vert_total; 44 uint32 vert_blank; 45 uint32 vert_sync; 46 uint32 size; 47 uint32 stride; 48 uint32 position; 49 uint32 pipe_source; 50 }; 51 52 struct pll_divisors { 53 uint32 post; 54 uint32 post1; 55 uint32 post2; 56 bool post2_high; 57 uint32 n; 58 uint32 m; 59 uint32 m1; 60 uint32 m2; 61 }; 62 63 struct pll_limits { 64 pll_divisors min; 65 pll_divisors max; 66 uint32 min_post2_frequency; 67 uint32 min_vco; 68 uint32 max_vco; 69 }; 70 71 72 static status_t 73 get_i2c_signals(void* cookie, int* _clock, int* _data) 74 { 75 uint32 ioRegister = (uint32)cookie; 76 uint32 value = read32(ioRegister); 77 78 *_clock = (value & I2C_CLOCK_VALUE_IN) != 0; 79 *_data = (value & I2C_DATA_VALUE_IN) != 0; 80 81 return B_OK; 82 } 83 84 85 static status_t 86 set_i2c_signals(void* cookie, int clock, int data) 87 { 88 uint32 ioRegister = (uint32)cookie; 89 uint32 value; 90 91 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_83x)) { 92 // on these chips, the reserved values are fixed 93 value = 0; 94 } else { 95 // on all others, we have to preserve them manually 96 value = read32(ioRegister) & I2C_RESERVED; 97 } 98 99 if (data != 0) 100 value |= I2C_DATA_DIRECTION_MASK; 101 else 102 value |= I2C_DATA_DIRECTION_MASK | I2C_DATA_DIRECTION_OUT | I2C_DATA_VALUE_MASK; 103 104 if (clock != 0) 105 value |= I2C_CLOCK_DIRECTION_MASK; 106 else 107 value |= I2C_CLOCK_DIRECTION_MASK | I2C_CLOCK_DIRECTION_OUT | I2C_CLOCK_VALUE_MASK; 108 109 write32(ioRegister, value); 110 read32(ioRegister); 111 // make sure the PCI bus has flushed the write 112 113 return B_OK; 114 } 115 116 117 void 118 set_frame_buffer_base() 119 { 120 intel_shared_info &sharedInfo = *gInfo->shared_info; 121 display_mode &mode = sharedInfo.current_mode; 122 uint32 baseRegister; 123 uint32 surfaceRegister; 124 125 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) { 126 baseRegister = INTEL_DISPLAY_A_BASE; 127 surfaceRegister = INTEL_DISPLAY_A_SURFACE; 128 } else { 129 baseRegister = INTEL_DISPLAY_B_BASE; 130 surfaceRegister = INTEL_DISPLAY_B_SURFACE; 131 } 132 133 if (sharedInfo.device_type.InGroup(INTEL_TYPE_96x) 134 || sharedInfo.device_type.InGroup(INTEL_TYPE_G4x)) { 135 write32(baseRegister, mode.v_display_start * sharedInfo.bytes_per_row 136 + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); 137 read32(baseRegister); 138 write32(surfaceRegister, sharedInfo.frame_buffer_offset); 139 read32(surfaceRegister); 140 } else { 141 write32(baseRegister, sharedInfo.frame_buffer_offset 142 + mode.v_display_start * sharedInfo.bytes_per_row 143 + mode.h_display_start * (sharedInfo.bits_per_pixel + 7) / 8); 144 read32(baseRegister); 145 } 146 } 147 148 149 /*! Creates the initial mode list of the primary accelerant. 150 It's called from intel_init_accelerant(). 151 */ 152 status_t 153 create_mode_list(void) 154 { 155 i2c_bus bus; 156 bus.cookie = (void*)INTEL_I2C_IO_A; 157 bus.set_signals = &set_i2c_signals; 158 bus.get_signals = &get_i2c_signals; 159 ddc2_init_timing(&bus); 160 161 status_t error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL); 162 if (error == B_OK) { 163 edid_dump(&gInfo->edid_info); 164 gInfo->has_edid = true; 165 } else { 166 TRACE(("intel_extreme: getting EDID on port A (analog) failed : %s. " 167 "Trying on port C (lvds)\n", strerror(error))); 168 bus.cookie = (void*)INTEL_I2C_IO_C; 169 error = ddc2_read_edid1(&bus, &gInfo->edid_info, NULL, NULL); 170 if (error == B_OK) { 171 edid_dump(&gInfo->edid_info); 172 gInfo->has_edid = true; 173 } else { 174 TRACE(("intel_extreme: getting EDID on port C failed : %s\n", 175 strerror(error))); 176 177 // We could not read any EDID info. Fallback to creating a list with 178 // only the mode set up by the BIOS. 179 // TODO: support lower modes via scaling and windowing 180 if (gInfo->head_mode & HEAD_MODE_LVDS_PANEL 181 && ((gInfo->head_mode & HEAD_MODE_A_ANALOG) == 0)) { 182 size_t size = (sizeof(display_mode) + B_PAGE_SIZE - 1) 183 & ~(B_PAGE_SIZE - 1); 184 185 display_mode *list; 186 area_id area = create_area("intel extreme modes", 187 (void **)&list, B_ANY_ADDRESS, size, B_NO_LOCK, 188 B_READ_AREA | B_WRITE_AREA); 189 if (area < B_OK) 190 return area; 191 192 memcpy(list, &gInfo->lvds_panel_mode, sizeof(display_mode)); 193 194 gInfo->mode_list_area = area; 195 gInfo->mode_list = list; 196 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 197 gInfo->shared_info->mode_count = 1; 198 return B_OK; 199 } 200 } 201 } 202 203 // Otherwise return the 'real' list of modes 204 display_mode *list; 205 uint32 count = 0; 206 gInfo->mode_list_area = create_display_modes("intel extreme modes", 207 gInfo->has_edid ? &gInfo->edid_info : NULL, NULL, 0, NULL, 0, NULL, 208 &list, &count); 209 if (gInfo->mode_list_area < B_OK) 210 return gInfo->mode_list_area; 211 212 gInfo->mode_list = list; 213 gInfo->shared_info->mode_list_area = gInfo->mode_list_area; 214 gInfo->shared_info->mode_count = count; 215 216 return B_OK; 217 } 218 219 220 void 221 wait_for_vblank(void) 222 { 223 acquire_sem_etc(gInfo->shared_info->vblank_sem, 1, B_RELATIVE_TIMEOUT, 224 25000); 225 // With the output turned off via DPMS, we might not get any interrupts 226 // anymore that's why we don't wait forever for it. 227 } 228 229 230 static void 231 get_pll_limits(pll_limits &limits) 232 { 233 // Note, the limits are taken from the X driver; they have not yet been 234 // tested 235 236 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_G4x)) { 237 // TODO: support LVDS output limits as well 238 static const pll_limits kLimits = { 239 // p, p1, p2, high, n, m, m1, m2 240 { 10, 1, 10, false, 1, 104, 17, 5}, // min 241 { 30, 3, 10, true, 4, 138, 23, 11}, // max 242 270000, 1750000, 3500000 243 }; 244 limits = kLimits; 245 } else if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 246 // TODO: support LVDS output limits as well 247 // m1 is reserved and must be 0 248 static const pll_limits kLimits = { 249 // p, p1, p2, high, n, m, m1, m2 250 { 5, 1, 10, false, 3, 2, 0, 2}, // min 251 { 80, 8, 5, true, 6, 256, 0, 256}, // max 252 200000, 1700000, 3500000 253 }; 254 limits = kLimits; 255 } else if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { 256 // TODO: support LVDS output limits as well 257 // (Update: Output limits are adjusted in the computation (post2=7/14)) 258 // Should move them here! 259 static const pll_limits kLimits = { 260 // p, p1, p2, high, n, m, m1, m2 261 { 5, 1, 10, false, 5, 70, 12, 7}, // min 262 { 80, 8, 5, true, 10, 120, 22, 11}, // max 263 200000, 1400000, 2800000 264 }; 265 limits = kLimits; 266 } else { 267 // TODO: support LVDS output limits as well 268 static const pll_limits kLimits = { 269 // p, p1, p2, high, n, m, m1, m2 270 { 4, 2, 4, false, 5, 96, 20, 8}, 271 {128, 33, 2, true, 18, 140, 28, 18}, 272 165000, 930000, 1400000 273 }; 274 limits = kLimits; 275 } 276 277 TRACE(("PLL limits, min: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n", 278 limits.min.post, limits.min.post1, limits.min.post2, limits.min.n, 279 limits.min.m, limits.min.m1, limits.min.m2)); 280 TRACE(("PLL limits, max: p %lu (p1 %lu, p2 %lu), n %lu, m %lu (m1 %lu, m2 %lu)\n", 281 limits.max.post, limits.max.post1, limits.max.post2, limits.max.n, 282 limits.max.m, limits.max.m1, limits.max.m2)); 283 } 284 285 286 static bool 287 valid_pll_divisors(const pll_divisors& divisors, const pll_limits& limits) 288 { 289 pll_info &info = gInfo->shared_info->pll_info; 290 uint32 vco = info.reference_frequency * divisors.m / divisors.n; 291 uint32 frequency = vco / divisors.post; 292 293 if (divisors.post < limits.min.post || divisors.post > limits.max.post 294 || divisors.m < limits.min.m || divisors.m > limits.max.m 295 || vco < limits.min_vco || vco > limits.max_vco 296 || frequency < info.min_frequency || frequency > info.max_frequency) 297 return false; 298 299 return true; 300 } 301 302 303 static void 304 compute_pll_divisors(const display_mode ¤t, pll_divisors& divisors, 305 bool isLVDS) 306 { 307 float requestedPixelClock = current.timing.pixel_clock / 1000.0f; 308 float referenceClock = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 309 pll_limits limits; 310 get_pll_limits(limits); 311 312 TRACE(("required MHz: %g\n", requestedPixelClock)); 313 314 if (isLVDS) { 315 if ((read32(INTEL_DISPLAY_LVDS_PORT) & LVDS_CLKB_POWER_MASK) 316 == LVDS_CLKB_POWER_UP) 317 divisors.post2 = LVDS_POST2_RATE_FAST; 318 else 319 divisors.post2 = LVDS_POST2_RATE_SLOW; 320 } else { 321 if (current.timing.pixel_clock < limits.min_post2_frequency) { 322 // slow DAC timing 323 divisors.post2 = limits.min.post2; 324 divisors.post2_high = limits.min.post2_high; 325 } else { 326 // fast DAC timing 327 divisors.post2 = limits.max.post2; 328 divisors.post2_high = limits.max.post2_high; 329 } 330 } 331 332 float best = requestedPixelClock; 333 pll_divisors bestDivisors; 334 335 bool is_igd = gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD); 336 for (divisors.m1 = limits.min.m1; divisors.m1 <= limits.max.m1; divisors.m1++) { 337 for (divisors.m2 = limits.min.m2; divisors.m2 <= limits.max.m2 338 && ((divisors.m2 < divisors.m1) || is_igd); divisors.m2++) { 339 for (divisors.n = limits.min.n; divisors.n <= limits.max.n; 340 divisors.n++) { 341 for (divisors.post1 = limits.min.post1; 342 divisors.post1 <= limits.max.post1; divisors.post1++) { 343 divisors.m = 5 * divisors.m1 + divisors.m2; 344 divisors.post = divisors.post1 * divisors.post2; 345 346 if (!valid_pll_divisors(divisors, limits)) 347 continue; 348 349 float error = fabs(requestedPixelClock 350 - ((referenceClock * divisors.m) / divisors.n) / divisors.post); 351 if (error < best) { 352 best = error; 353 bestDivisors = divisors; 354 355 if (error == 0) 356 break; 357 } 358 } 359 } 360 } 361 } 362 363 divisors = bestDivisors; 364 365 TRACE(("found: %g MHz, p = %lu (p1 = %lu, p2 = %lu), n = %lu, m = %lu (m1 = %lu, m2 = %lu)\n", 366 ((referenceClock * divisors.m) / divisors.n) / divisors.post, 367 divisors.post, divisors.post1, divisors.post2, divisors.n, 368 divisors.m, divisors.m1, divisors.m2)); 369 } 370 371 372 void 373 retrieve_current_mode(display_mode& mode, uint32 pllRegister) 374 { 375 uint32 pll = read32(pllRegister); 376 uint32 pllDivisor; 377 uint32 hTotalRegister; 378 uint32 vTotalRegister; 379 uint32 hSyncRegister; 380 uint32 vSyncRegister; 381 uint32 imageSizeRegister; 382 uint32 controlRegister; 383 384 if (pllRegister == INTEL_DISPLAY_A_PLL) { 385 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0 386 ? INTEL_DISPLAY_A_PLL_DIVISOR_1 : INTEL_DISPLAY_A_PLL_DIVISOR_0); 387 388 hTotalRegister = INTEL_DISPLAY_A_HTOTAL; 389 vTotalRegister = INTEL_DISPLAY_A_VTOTAL; 390 hSyncRegister = INTEL_DISPLAY_A_HSYNC; 391 vSyncRegister = INTEL_DISPLAY_A_VSYNC; 392 imageSizeRegister = INTEL_DISPLAY_A_IMAGE_SIZE; 393 controlRegister = INTEL_DISPLAY_A_CONTROL; 394 } else if (pllRegister == INTEL_DISPLAY_B_PLL) { 395 pllDivisor = read32((pll & DISPLAY_PLL_DIVISOR_1) != 0 396 ? INTEL_DISPLAY_B_PLL_DIVISOR_1 : INTEL_DISPLAY_B_PLL_DIVISOR_0); 397 398 hTotalRegister = INTEL_DISPLAY_B_HTOTAL; 399 vTotalRegister = INTEL_DISPLAY_B_VTOTAL; 400 hSyncRegister = INTEL_DISPLAY_B_HSYNC; 401 vSyncRegister = INTEL_DISPLAY_B_VSYNC; 402 imageSizeRegister = INTEL_DISPLAY_B_IMAGE_SIZE; 403 controlRegister = INTEL_DISPLAY_B_CONTROL; 404 } else { 405 // TODO: not supported 406 return; 407 } 408 409 pll_divisors divisors; 410 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 411 divisors.m1 = 0; 412 divisors.m2 = (pllDivisor & DISPLAY_PLL_IGD_M2_DIVISOR_MASK) 413 >> DISPLAY_PLL_M2_DIVISOR_SHIFT; 414 divisors.n = ((pllDivisor & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 415 >> DISPLAY_PLL_N_DIVISOR_SHIFT) - 1; 416 } else { 417 divisors.m1 = (pllDivisor & DISPLAY_PLL_M1_DIVISOR_MASK) 418 >> DISPLAY_PLL_M1_DIVISOR_SHIFT; 419 divisors.m2 = (pllDivisor & DISPLAY_PLL_M2_DIVISOR_MASK) 420 >> DISPLAY_PLL_M2_DIVISOR_SHIFT; 421 divisors.n = (pllDivisor & DISPLAY_PLL_N_DIVISOR_MASK) 422 >> DISPLAY_PLL_N_DIVISOR_SHIFT; 423 } 424 425 pll_limits limits; 426 get_pll_limits(limits); 427 428 if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { 429 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 430 divisors.post1 = (pll & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK) 431 >> DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT; 432 } else { 433 divisors.post1 = (pll & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK) 434 >> DISPLAY_PLL_POST1_DIVISOR_SHIFT; 435 } 436 437 if (pllRegister == INTEL_DISPLAY_B_PLL 438 && !gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { 439 // TODO: Fix this? Need to support dual channel LVDS. 440 divisors.post2 = LVDS_POST2_RATE_SLOW; 441 } else { 442 if ((pll & DISPLAY_PLL_DIVIDE_HIGH) != 0) 443 divisors.post2 = limits.max.post2; 444 else 445 divisors.post2 = limits.min.post2; 446 } 447 } else { 448 // 8xx 449 divisors.post1 = (pll & DISPLAY_PLL_POST1_DIVISOR_MASK) 450 >> DISPLAY_PLL_POST1_DIVISOR_SHIFT; 451 452 if ((pll & DISPLAY_PLL_DIVIDE_4X) != 0) 453 divisors.post2 = limits.max.post2; 454 else 455 divisors.post2 = limits.min.post2; 456 } 457 458 divisors.m = 5 * divisors.m1 + divisors.m2; 459 divisors.post = divisors.post1 * divisors.post2; 460 461 float referenceClock 462 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 463 float pixelClock 464 = ((referenceClock * divisors.m) / divisors.n) / divisors.post; 465 466 // timing 467 468 mode.timing.pixel_clock = uint32(pixelClock * 1000); 469 mode.timing.flags = 0; 470 471 uint32 value = read32(hTotalRegister); 472 mode.timing.h_total = (value >> 16) + 1; 473 mode.timing.h_display = (value & 0xffff) + 1; 474 475 value = read32(hSyncRegister); 476 mode.timing.h_sync_end = (value >> 16) + 1; 477 mode.timing.h_sync_start = (value & 0xffff) + 1; 478 479 value = read32(vTotalRegister); 480 mode.timing.v_total = (value >> 16) + 1; 481 mode.timing.v_display = (value & 0xffff) + 1; 482 483 value = read32(vSyncRegister); 484 mode.timing.v_sync_end = (value >> 16) + 1; 485 mode.timing.v_sync_start = (value & 0xffff) + 1; 486 487 // image size and color space 488 489 value = read32(imageSizeRegister); 490 mode.virtual_width = (value >> 16) + 1; 491 mode.virtual_height = (value & 0xffff) + 1; 492 493 // using virtual size based on image size is the 'proper' way to do it, 494 // however the bios appears to be suggesting scaling or somesuch, so ignore 495 // the proper virtual dimension for now if they'd suggest a smaller size. 496 if (mode.virtual_width < mode.timing.h_display) 497 mode.virtual_width = mode.timing.h_display; 498 if (mode.virtual_height < mode.timing.v_display) 499 mode.virtual_height = mode.timing.v_display; 500 501 value = read32(controlRegister); 502 switch (value & DISPLAY_CONTROL_COLOR_MASK) { 503 case DISPLAY_CONTROL_RGB32: 504 default: 505 mode.space = B_RGB32; 506 break; 507 case DISPLAY_CONTROL_RGB16: 508 mode.space = B_RGB16; 509 break; 510 case DISPLAY_CONTROL_RGB15: 511 mode.space = B_RGB15; 512 break; 513 case DISPLAY_CONTROL_CMAP8: 514 mode.space = B_CMAP8; 515 break; 516 } 517 518 mode.h_display_start = 0; 519 mode.v_display_start = 0; 520 mode.flags = B_8_BIT_DAC | B_HARDWARE_CURSOR | B_PARALLEL_ACCESS 521 | B_DPMS | B_SUPPORTS_OVERLAYS; 522 } 523 524 525 /*! Store away panel information if identified on startup 526 (used for pipe B->lvds). 527 */ 528 void 529 save_lvds_mode(void) 530 { 531 // dump currently programmed mode. 532 display_mode biosMode; 533 retrieve_current_mode(biosMode, INTEL_DISPLAY_B_PLL); 534 gInfo->lvds_panel_mode = biosMode; 535 } 536 537 538 static void 539 get_color_space_format(const display_mode &mode, uint32 &colorMode, 540 uint32 &bytesPerRow, uint32 &bitsPerPixel) 541 { 542 uint32 bytesPerPixel; 543 544 switch (mode.space) { 545 case B_RGB32_LITTLE: 546 colorMode = DISPLAY_CONTROL_RGB32; 547 bytesPerPixel = 4; 548 bitsPerPixel = 32; 549 break; 550 case B_RGB16_LITTLE: 551 colorMode = DISPLAY_CONTROL_RGB16; 552 bytesPerPixel = 2; 553 bitsPerPixel = 16; 554 break; 555 case B_RGB15_LITTLE: 556 colorMode = DISPLAY_CONTROL_RGB15; 557 bytesPerPixel = 2; 558 bitsPerPixel = 15; 559 break; 560 case B_CMAP8: 561 default: 562 colorMode = DISPLAY_CONTROL_CMAP8; 563 bytesPerPixel = 1; 564 bitsPerPixel = 8; 565 break; 566 } 567 568 bytesPerRow = mode.virtual_width * bytesPerPixel; 569 570 // Make sure bytesPerRow is a multiple of 64 571 // TODO: check if the older chips have the same restriction! 572 if ((bytesPerRow & 63) != 0) 573 bytesPerRow = (bytesPerRow + 63) & ~63; 574 } 575 576 577 // #pragma mark - 578 579 580 uint32 581 intel_accelerant_mode_count(void) 582 { 583 TRACE(("intel_accelerant_mode_count()\n")); 584 return gInfo->shared_info->mode_count; 585 } 586 587 588 status_t 589 intel_get_mode_list(display_mode *modeList) 590 { 591 TRACE(("intel_get_mode_info()\n")); 592 memcpy(modeList, gInfo->mode_list, 593 gInfo->shared_info->mode_count * sizeof(display_mode)); 594 return B_OK; 595 } 596 597 598 status_t 599 intel_propose_display_mode(display_mode *target, const display_mode *low, 600 const display_mode *high) 601 { 602 TRACE(("intel_propose_display_mode()\n")); 603 604 // just search for the specified mode in the list 605 606 for (uint32 i = 0; i < gInfo->shared_info->mode_count; i++) { 607 display_mode *mode = &gInfo->mode_list[i]; 608 609 // TODO: improve this, ie. adapt pixel clock to allowed values!!! 610 611 if (target->virtual_width != mode->virtual_width 612 || target->virtual_height != mode->virtual_height 613 || target->space != mode->space) 614 continue; 615 616 *target = *mode; 617 return B_OK; 618 } 619 return B_BAD_VALUE; 620 } 621 622 623 status_t 624 intel_set_display_mode(display_mode *mode) 625 { 626 TRACE(("intel_set_display_mode(%ldx%ld)\n", mode->virtual_width, 627 mode->virtual_height)); 628 629 if (mode == NULL) 630 return B_BAD_VALUE; 631 632 display_mode target = *mode; 633 634 // TODO: it may be acceptable to continue when using panel fitting or 635 // centering, since the data from propose_display_mode will not actually be 636 // used as is in this case. 637 if (intel_propose_display_mode(&target, mode, mode)) 638 return B_BAD_VALUE; 639 640 uint32 colorMode, bytesPerRow, bitsPerPixel; 641 get_color_space_format(target, colorMode, bytesPerRow, bitsPerPixel); 642 643 // TODO: do not go further if the mode is identical to the current one. 644 // This would avoid the screen being off when switching workspaces when they 645 // have the same resolution. 646 647 #if 0 648 static bool first = true; 649 if (first) { 650 int fd = open("/boot/home/ie_.regs", O_CREAT | O_WRONLY, 0644); 651 if (fd >= 0) { 652 for (int32 i = 0; i < 0x80000; i += 16) { 653 char line[512]; 654 int length = sprintf(line, "%05lx: %08lx %08lx %08lx %08lx\n", 655 i, read32(i), read32(i + 4), read32(i + 8), read32(i + 12)); 656 write(fd, line, length); 657 } 658 close(fd); 659 sync(); 660 } 661 first = false; 662 } 663 #endif 664 665 intel_shared_info &sharedInfo = *gInfo->shared_info; 666 Autolock locker(sharedInfo.accelerant_lock); 667 668 // TODO: This may not be neccesary 669 set_display_power_mode(B_DPMS_OFF); 670 671 // free old and allocate new frame buffer in graphics memory 672 673 intel_free_memory(sharedInfo.frame_buffer); 674 675 uint32 base; 676 if (intel_allocate_memory(bytesPerRow * target.virtual_height, 0, 677 base) < B_OK) { 678 // oh, how did that happen? Unfortunately, there is no really good way 679 // back 680 if (intel_allocate_memory(sharedInfo.current_mode.virtual_height 681 * sharedInfo.bytes_per_row, 0, base) == B_OK) { 682 sharedInfo.frame_buffer = base; 683 sharedInfo.frame_buffer_offset = base 684 - (addr_t)sharedInfo.graphics_memory; 685 set_frame_buffer_base(); 686 } 687 688 TRACE(("intel_extreme : Failed to allocate framebuffer !\n")); 689 return B_NO_MEMORY; 690 } 691 692 // clear frame buffer before using it 693 memset((uint8 *)base, 0, bytesPerRow * target.virtual_height); 694 sharedInfo.frame_buffer = base; 695 sharedInfo.frame_buffer_offset = base - (addr_t)sharedInfo.graphics_memory; 696 697 // make sure VGA display is disabled 698 write32(INTEL_VGA_DISPLAY_CONTROL, VGA_DISPLAY_DISABLED); 699 read32(INTEL_VGA_DISPLAY_CONTROL); 700 701 if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) { 702 // For LVDS panels, we actually always set the native mode in hardware 703 // Then we use the panel fitter to scale the picture to that. 704 display_mode hardwareTarget; 705 bool needsScaling = false; 706 707 // Try to get the panel preferred screen mode from EDID info 708 if (gInfo->has_edid) { 709 hardwareTarget.space = target.space; 710 hardwareTarget.virtual_width 711 = gInfo->edid_info.std_timing[0].h_size; 712 hardwareTarget.virtual_height 713 = gInfo->edid_info.std_timing[0].v_size; 714 for (int i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; i++) { 715 if (gInfo->edid_info.detailed_monitor[i].monitor_desc_type 716 == EDID1_IS_DETAILED_TIMING) { 717 hardwareTarget.virtual_width = gInfo->edid_info 718 .detailed_monitor[i].data.detailed_timing.h_active; 719 hardwareTarget.virtual_height = gInfo->edid_info 720 .detailed_monitor[i].data.detailed_timing.v_active; 721 break; 722 } 723 } 724 TRACE(("intel_extreme : hardware mode will actually be %dx%d\n", 725 hardwareTarget.virtual_width, hardwareTarget.virtual_height)); 726 if ((hardwareTarget.virtual_width <= target.virtual_width 727 && hardwareTarget.virtual_height <= target.virtual_height 728 && hardwareTarget.space <= target.space) 729 || intel_propose_display_mode(&hardwareTarget, mode, mode)) { 730 hardwareTarget = target; 731 } else 732 needsScaling = true; 733 } else { 734 // We don't have EDID data, try to set the requested mode directly 735 hardwareTarget = target; 736 } 737 738 pll_divisors divisors; 739 if (needsScaling) 740 compute_pll_divisors(hardwareTarget, divisors, true); 741 else 742 compute_pll_divisors(target, divisors, true); 743 744 uint32 dpll = DISPLAY_PLL_NO_VGA_CONTROL | DISPLAY_PLL_ENABLED; 745 if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { 746 dpll |= LVDS_PLL_MODE_LVDS; 747 // DPLL mode LVDS for i915+ 748 } 749 750 // Compute bitmask from p1 value 751 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 752 dpll |= (1 << (divisors.post1 - 1)) << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT; 753 } else { 754 dpll |= (1 << (divisors.post1 - 1)) << DISPLAY_PLL_POST1_DIVISOR_SHIFT; 755 } 756 switch (divisors.post2) { 757 case 5: 758 case 7: 759 dpll |= DISPLAY_PLL_DIVIDE_HIGH; 760 break; 761 } 762 763 // Disable panel fitting, but enable 8 to 6-bit dithering 764 write32(INTEL_PANEL_FIT_CONTROL, 0x4); 765 // TODO: do not do this if the connected panel is 24-bit 766 // (I don't know how to detect that) 767 768 if ((dpll & DISPLAY_PLL_ENABLED) != 0) { 769 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 770 write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, 771 (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) 772 & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 773 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 774 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); 775 } else { 776 write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, 777 (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) 778 & DISPLAY_PLL_N_DIVISOR_MASK) 779 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) 780 & DISPLAY_PLL_M1_DIVISOR_MASK) 781 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 782 & DISPLAY_PLL_M2_DIVISOR_MASK)); 783 } 784 write32(INTEL_DISPLAY_B_PLL, dpll & ~DISPLAY_PLL_ENABLED); 785 read32(INTEL_DISPLAY_B_PLL); 786 spin(150); 787 } 788 789 uint32 lvds = read32(INTEL_DISPLAY_LVDS_PORT) 790 | LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP | LVDS_PIPEB_SELECT; 791 792 lvds |= LVDS_18BIT_DITHER; 793 // TODO: do not do this if the connected panel is 24-bit 794 // (I don't know how to detect that) 795 796 float referenceClock = gInfo->shared_info->pll_info.reference_frequency 797 / 1000.0f; 798 799 // Set the B0-B3 data pairs corresponding to whether we're going to 800 // set the DPLLs for dual-channel mode or not. 801 if (divisors.post2 == LVDS_POST2_RATE_FAST) 802 lvds |= LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP; 803 else 804 lvds &= ~( LVDS_B0B3PAIRS_POWER_UP | LVDS_CLKB_POWER_UP); 805 806 write32(INTEL_DISPLAY_LVDS_PORT, lvds); 807 read32(INTEL_DISPLAY_LVDS_PORT); 808 809 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 810 write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, 811 (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) 812 & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 813 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 814 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); 815 } else { 816 write32(INTEL_DISPLAY_B_PLL_DIVISOR_0, 817 (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) 818 & DISPLAY_PLL_N_DIVISOR_MASK) 819 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) 820 & DISPLAY_PLL_M1_DIVISOR_MASK) 821 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 822 & DISPLAY_PLL_M2_DIVISOR_MASK)); 823 } 824 825 write32(INTEL_DISPLAY_B_PLL, dpll); 826 read32(INTEL_DISPLAY_B_PLL); 827 828 // Wait for the clocks to stabilize 829 spin(150); 830 831 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) { 832 float adjusted = ((referenceClock * divisors.m) / divisors.n) 833 / divisors.post; 834 uint32 pixelMultiply; 835 if (needsScaling) { 836 pixelMultiply = uint32(adjusted 837 / (hardwareTarget.timing.pixel_clock / 1000.0f)); 838 } else { 839 pixelMultiply = uint32(adjusted 840 / (target.timing.pixel_clock / 1000.0f)); 841 } 842 843 write32(INTEL_DISPLAY_B_PLL_MULTIPLIER_DIVISOR, (0 << 24) 844 | ((pixelMultiply - 1) << 8)); 845 } else 846 write32(INTEL_DISPLAY_B_PLL, dpll); 847 848 read32(INTEL_DISPLAY_B_PLL); 849 spin(150); 850 851 // update timing parameters 852 if (needsScaling) { 853 // TODO: Alternatively, it should be possible to use the panel 854 // fitter and scale the picture. 855 856 // TODO: Perform some sanity check, for example if the target is 857 // wider than the hardware mode we end up with negative borders and 858 // broken timings 859 uint32 borderWidth = hardwareTarget.timing.h_display 860 - target.timing.h_display; 861 862 uint32 syncWidth = hardwareTarget.timing.h_sync_end 863 - hardwareTarget.timing.h_sync_start; 864 865 uint32 syncCenter = target.timing.h_display 866 + (hardwareTarget.timing.h_total 867 - target.timing.h_display) / 2; 868 869 write32(INTEL_DISPLAY_B_HTOTAL, 870 ((uint32)(hardwareTarget.timing.h_total - 1) << 16) 871 | ((uint32)target.timing.h_display - 1)); 872 write32(INTEL_DISPLAY_B_HBLANK, 873 ((uint32)(hardwareTarget.timing.h_total - borderWidth / 2 - 1) 874 << 16) 875 | ((uint32)target.timing.h_display + borderWidth / 2 - 1)); 876 write32(INTEL_DISPLAY_B_HSYNC, 877 ((uint32)(syncCenter + syncWidth / 2 - 1) << 16) 878 | ((uint32)syncCenter - syncWidth / 2 - 1)); 879 880 uint32 borderHeight = hardwareTarget.timing.v_display 881 - target.timing.v_display; 882 883 uint32 syncHeight = hardwareTarget.timing.v_sync_end 884 - hardwareTarget.timing.v_sync_start; 885 886 syncCenter = target.timing.v_display 887 + (hardwareTarget.timing.v_total 888 - target.timing.v_display) / 2; 889 890 write32(INTEL_DISPLAY_B_VTOTAL, 891 ((uint32)(hardwareTarget.timing.v_total - 1) << 16) 892 | ((uint32)target.timing.v_display - 1)); 893 write32(INTEL_DISPLAY_B_VBLANK, 894 ((uint32)(hardwareTarget.timing.v_total - borderHeight / 2 - 1) 895 << 16) 896 | ((uint32)target.timing.v_display 897 + borderHeight / 2 - 1)); 898 write32(INTEL_DISPLAY_B_VSYNC, ((uint32)(syncCenter 899 + syncHeight / 2 - 1) << 16) 900 | ((uint32)syncCenter - syncHeight / 2 - 1)); 901 902 // This is useful for debugging: it sets the border to red, so you 903 // can see what is border and what is porch (black area around the 904 // sync) 905 // write32(0x61020, 0x00FF0000); 906 } else { 907 write32(INTEL_DISPLAY_B_HTOTAL, 908 ((uint32)(target.timing.h_total - 1) << 16) 909 | ((uint32)target.timing.h_display - 1)); 910 write32(INTEL_DISPLAY_B_HBLANK, 911 ((uint32)(target.timing.h_total - 1) << 16) 912 | ((uint32)target.timing.h_display - 1)); 913 write32(INTEL_DISPLAY_B_HSYNC, ( 914 (uint32)(target.timing.h_sync_end - 1) << 16) 915 | ((uint32)target.timing.h_sync_start - 1)); 916 917 write32(INTEL_DISPLAY_B_VTOTAL, 918 ((uint32)(target.timing.v_total - 1) << 16) 919 | ((uint32)target.timing.v_display - 1)); 920 write32(INTEL_DISPLAY_B_VBLANK, 921 ((uint32)(target.timing.v_total - 1) << 16) 922 | ((uint32)target.timing.v_display - 1)); 923 write32(INTEL_DISPLAY_B_VSYNC, ( 924 (uint32)(target.timing.v_sync_end - 1) << 16) 925 | ((uint32)target.timing.v_sync_start - 1)); 926 } 927 928 write32(INTEL_DISPLAY_B_IMAGE_SIZE, 929 ((uint32)(target.timing.h_display - 1) << 16) 930 | ((uint32)target.timing.v_display - 1)); 931 932 write32(INTEL_DISPLAY_B_POS, 0); 933 write32(INTEL_DISPLAY_B_PIPE_SIZE, 934 ((uint32)(target.timing.v_display - 1) << 16) 935 | ((uint32)target.timing.h_display - 1)); 936 937 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) 938 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) 939 | colorMode); 940 941 write32(INTEL_DISPLAY_B_PIPE_CONTROL, 942 read32(INTEL_DISPLAY_B_PIPE_CONTROL) | DISPLAY_PIPE_ENABLED); 943 read32(INTEL_DISPLAY_B_PIPE_CONTROL); 944 } 945 946 if ((gInfo->head_mode & HEAD_MODE_A_ANALOG) != 0) { 947 pll_divisors divisors; 948 compute_pll_divisors(target, divisors, false); 949 950 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 951 write32(INTEL_DISPLAY_A_PLL_DIVISOR_0, 952 (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) 953 & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 954 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 955 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); 956 } else { 957 write32(INTEL_DISPLAY_A_PLL_DIVISOR_0, 958 (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) 959 & DISPLAY_PLL_N_DIVISOR_MASK) 960 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) 961 & DISPLAY_PLL_M1_DIVISOR_MASK) 962 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 963 & DISPLAY_PLL_M2_DIVISOR_MASK)); 964 } 965 966 uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL; 967 if (gInfo->shared_info->device_type.InFamily(INTEL_TYPE_9xx)) { 968 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_IGD)) { 969 pll |= ((1 << (divisors.post1 - 1)) 970 << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT) 971 & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK; 972 } else { 973 pll |= ((1 << (divisors.post1 - 1)) 974 << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 975 & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; 976 // pll |= ((divisors.post1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 977 // & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; 978 } 979 if (divisors.post2_high) 980 pll |= DISPLAY_PLL_DIVIDE_HIGH; 981 982 pll |= DISPLAY_PLL_MODE_ANALOG; 983 984 if (gInfo->shared_info->device_type.InGroup(INTEL_TYPE_96x)) 985 pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT; 986 } else { 987 if (!divisors.post2_high) 988 pll |= DISPLAY_PLL_DIVIDE_4X; 989 990 pll |= DISPLAY_PLL_2X_CLOCK; 991 992 if (divisors.post1 > 2) { 993 pll |= ((divisors.post1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 994 & DISPLAY_PLL_POST1_DIVISOR_MASK; 995 } else 996 pll |= DISPLAY_PLL_POST1_DIVIDE_2; 997 } 998 999 write32(INTEL_DISPLAY_A_PLL, pll); 1000 read32(INTEL_DISPLAY_A_PLL); 1001 spin(150); 1002 write32(INTEL_DISPLAY_A_PLL, pll); 1003 read32(INTEL_DISPLAY_A_PLL); 1004 spin(150); 1005 1006 // update timing parameters 1007 write32(INTEL_DISPLAY_A_HTOTAL, 1008 ((uint32)(target.timing.h_total - 1) << 16) 1009 | ((uint32)target.timing.h_display - 1)); 1010 write32(INTEL_DISPLAY_A_HBLANK, 1011 ((uint32)(target.timing.h_total - 1) << 16) 1012 | ((uint32)target.timing.h_display - 1)); 1013 write32(INTEL_DISPLAY_A_HSYNC, 1014 ((uint32)(target.timing.h_sync_end - 1) << 16) 1015 | ((uint32)target.timing.h_sync_start - 1)); 1016 1017 write32(INTEL_DISPLAY_A_VTOTAL, 1018 ((uint32)(target.timing.v_total - 1) << 16) 1019 | ((uint32)target.timing.v_display - 1)); 1020 write32(INTEL_DISPLAY_A_VBLANK, 1021 ((uint32)(target.timing.v_total - 1) << 16) 1022 | ((uint32)target.timing.v_display - 1)); 1023 write32(INTEL_DISPLAY_A_VSYNC, 1024 ((uint32)(target.timing.v_sync_end - 1) << 16) 1025 | ((uint32)target.timing.v_sync_start - 1)); 1026 1027 write32(INTEL_DISPLAY_A_IMAGE_SIZE, 1028 ((uint32)(target.timing.h_display - 1) << 16) 1029 | ((uint32)target.timing.v_display - 1)); 1030 1031 write32(INTEL_DISPLAY_A_ANALOG_PORT, 1032 (read32(INTEL_DISPLAY_A_ANALOG_PORT) 1033 & ~(DISPLAY_MONITOR_POLARITY_MASK 1034 | DISPLAY_MONITOR_VGA_POLARITY)) 1035 | ((target.timing.flags & B_POSITIVE_HSYNC) != 0 1036 ? DISPLAY_MONITOR_POSITIVE_HSYNC : 0) 1037 | ((target.timing.flags & B_POSITIVE_VSYNC) != 0 1038 ? DISPLAY_MONITOR_POSITIVE_VSYNC : 0)); 1039 1040 // TODO: verify the two comments below: the X driver doesn't seem to 1041 // care about both of them! 1042 1043 // These two have to be set for display B, too - this obviously means 1044 // that the second head always must adopt the color space of the first 1045 // head. 1046 write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL) 1047 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) 1048 | colorMode); 1049 1050 if ((gInfo->head_mode & HEAD_MODE_B_DIGITAL) != 0) { 1051 write32(INTEL_DISPLAY_B_IMAGE_SIZE, 1052 ((uint32)(target.timing.h_display - 1) << 16) 1053 | ((uint32)target.timing.v_display - 1)); 1054 1055 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) 1056 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) 1057 | colorMode); 1058 } 1059 } 1060 1061 set_display_power_mode(sharedInfo.dpms_mode); 1062 1063 // Changing bytes per row seems to be ignored if the plane/pipe is turned 1064 // off 1065 1066 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) 1067 write32(INTEL_DISPLAY_A_BYTES_PER_ROW, bytesPerRow); 1068 if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) 1069 write32(INTEL_DISPLAY_B_BYTES_PER_ROW, bytesPerRow); 1070 1071 set_frame_buffer_base(); 1072 // triggers writing back double-buffered registers 1073 1074 // update shared info 1075 sharedInfo.bytes_per_row = bytesPerRow; 1076 sharedInfo.current_mode = target; 1077 sharedInfo.bits_per_pixel = bitsPerPixel; 1078 1079 return B_OK; 1080 } 1081 1082 1083 status_t 1084 intel_get_display_mode(display_mode *_currentMode) 1085 { 1086 TRACE(("intel_get_display_mode()\n")); 1087 1088 retrieve_current_mode(*_currentMode, INTEL_DISPLAY_A_PLL); 1089 return B_OK; 1090 } 1091 1092 1093 status_t 1094 intel_get_edid_info(void* info, size_t size, uint32* _version) 1095 { 1096 TRACE(("intel_get_edid_info()\n")); 1097 1098 if (!gInfo->has_edid) 1099 return B_ERROR; 1100 if (size < sizeof(struct edid1_info)) 1101 return B_BUFFER_OVERFLOW; 1102 1103 memcpy(info, &gInfo->edid_info, sizeof(struct edid1_info)); 1104 *_version = EDID_VERSION_1; 1105 return B_OK; 1106 } 1107 1108 1109 status_t 1110 intel_get_frame_buffer_config(frame_buffer_config *config) 1111 { 1112 TRACE(("intel_get_frame_buffer_config()\n")); 1113 1114 uint32 offset = gInfo->shared_info->frame_buffer_offset; 1115 1116 config->frame_buffer = gInfo->shared_info->graphics_memory + offset; 1117 config->frame_buffer_dma 1118 = (uint8 *)gInfo->shared_info->physical_graphics_memory + offset; 1119 config->bytes_per_row = gInfo->shared_info->bytes_per_row; 1120 1121 return B_OK; 1122 } 1123 1124 1125 status_t 1126 intel_get_pixel_clock_limits(display_mode *mode, uint32 *_low, uint32 *_high) 1127 { 1128 TRACE(("intel_get_pixel_clock_limits()\n")); 1129 1130 if (_low != NULL) { 1131 // lower limit of about 48Hz vertical refresh 1132 uint32 totalClocks = (uint32)mode->timing.h_total * (uint32)mode->timing.v_total; 1133 uint32 low = (totalClocks * 48L) / 1000L; 1134 if (low < gInfo->shared_info->pll_info.min_frequency) 1135 low = gInfo->shared_info->pll_info.min_frequency; 1136 else if (low > gInfo->shared_info->pll_info.max_frequency) 1137 return B_ERROR; 1138 1139 *_low = low; 1140 } 1141 1142 if (_high != NULL) 1143 *_high = gInfo->shared_info->pll_info.max_frequency; 1144 1145 return B_OK; 1146 } 1147 1148 1149 status_t 1150 intel_move_display(uint16 horizontalStart, uint16 verticalStart) 1151 { 1152 TRACE(("intel_move_display()\n")); 1153 1154 intel_shared_info &sharedInfo = *gInfo->shared_info; 1155 Autolock locker(sharedInfo.accelerant_lock); 1156 1157 display_mode &mode = sharedInfo.current_mode; 1158 1159 if (horizontalStart + mode.timing.h_display > mode.virtual_width 1160 || verticalStart + mode.timing.v_display > mode.virtual_height) 1161 return B_BAD_VALUE; 1162 1163 mode.h_display_start = horizontalStart; 1164 mode.v_display_start = verticalStart; 1165 1166 set_frame_buffer_base(); 1167 1168 return B_OK; 1169 } 1170 1171 1172 status_t 1173 intel_get_timing_constraints(display_timing_constraints *constraints) 1174 { 1175 TRACE(("intel_get_timing_contraints()\n")); 1176 return B_ERROR; 1177 } 1178 1179 1180 void 1181 intel_set_indexed_colors(uint count, uint8 first, uint8 *colors, uint32 flags) 1182 { 1183 TRACE(("intel_set_indexed_colors(colors = %p, first = %u)\n", colors, first)); 1184 1185 if (colors == NULL) 1186 return; 1187 1188 Autolock locker(gInfo->shared_info->accelerant_lock); 1189 1190 for (; count-- > 0; first++) { 1191 uint32 color = colors[0] << 16 | colors[1] << 8 | colors[2]; 1192 colors += 3; 1193 1194 if (gInfo->head_mode & HEAD_MODE_A_ANALOG) 1195 write32(INTEL_DISPLAY_A_PALETTE + first * sizeof(uint32), color); 1196 if (gInfo->head_mode & HEAD_MODE_B_DIGITAL) 1197 write32(INTEL_DISPLAY_B_PALETTE + first * sizeof(uint32), color); 1198 } 1199 } 1200 1201