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