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