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