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