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