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