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