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