1 /* 2 * Copyright 2006-2016, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 * Alexander von Gluck IV, kallisti5@unixzen.com 8 * 9 * PLL TEST MODE 10 * pll's on Intel can be extremely difficult. After 11 * making any changes, it is advised to run PLL_TEST_MODE 12 * to simulate your pll calculations on every card. 13 * Example: 14 * gcc pll.cpp \ 15 * -I $TOP/headers/private/graphics/intel_extreme/ 16 * -I $TOP/headers/private/graphics/common/ 17 * -I $TOP/headers/private/graphics/ -D PLL_TEST_MODE 18 */ 19 20 21 #include "pll.h" 22 23 #include <math.h> 24 #include <stdio.h> 25 #include <string.h> 26 27 #include <Debug.h> 28 29 #include <create_display_modes.h> 30 #include <ddc.h> 31 #include <edid.h> 32 #include <validate_display_mode.h> 33 34 #include "accelerant_protos.h" 35 #include "accelerant.h" 36 #include "utility.h" 37 38 39 #undef TRACE 40 #define TRACE_MODE 41 #ifdef TRACE_MODE 42 # define TRACE(x...) _sPrintf("intel_extreme: " x) 43 #else 44 # define TRACE(x...) 45 #endif 46 47 #define ERROR(x...) _sPrintf("intel_extreme: " x) 48 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 49 50 51 #ifdef PLL_TEST_MODE 52 #undef ERROR 53 #undef CALLED 54 #undef TRACE 55 56 #define TRACE(x...) printf("intel_extreme: " x) 57 #define ERROR(x...) printf("intel_extreme: " x) 58 #define CALLED(X...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 59 struct accelerant_info* gInfo; 60 #endif 61 62 // Static pll limits taken from Linux kernel KMS 63 64 static pll_limits kLimitsIlkDac = { 65 // p, p1, p2, n, m, m1, m2 66 { 5, 2, 14, 1, 79, 12, 5}, // min 67 { 80, 8, 14, 3, 118, 22, 9}, // max 68 225000, 1760000, 3510000 69 }; 70 71 static pll_limits kLimitsIlkLvdsSingle = { 72 // p, p1, p2, n, m, m1, m2 73 { 28, 2, 14, 1, 79, 12, 5}, // min 74 {112, 8, 14, 3, 118, 22, 9}, // max 75 225000, 1760000, 3510000 76 }; 77 78 static pll_limits kLimitsIlkLvdsDual = { 79 // p, p1, p2, n, m, m1, m2 80 { 14, 2, 7, 1, 79, 12, 5}, // min 81 { 56, 8, 7, 3, 127, 22, 9}, // max 82 225000, 1760000, 3510000 83 }; 84 85 // 100Mhz RefClock 86 static pll_limits kLimitsIlkLvdsSingle100 = { 87 // p, p1, p2, n, m, m1, m2 88 { 28, 2, 14, 1, 79, 12, 5}, // min 89 {112, 8, 14, 2, 126, 22, 9}, // max 90 225000, 1760000, 3510000 91 }; 92 93 static pll_limits kLimitsIlkLvdsDual100 = { 94 // p, p1, p2, n, m, m1, m2 95 { 14, 2, 7, 1, 79, 12, 5}, // min 96 { 42, 6, 7, 3, 126, 22, 9}, // max 97 225000, 1760000, 3510000 98 }; 99 100 #if 0 101 static pll_limits kLimitsChv = { 102 // p, p1, p2, n, m, m1, m2 103 { 0, 2, 14, 1, 79, 2, 24 << 22}, // min 104 { 0, 4, 1, 1, 127, 2, 175 << 22}, // max 105 0, 4800000, 6480000 106 }; 107 108 static pll_limits kLimitsVlv = { 109 // p, p1, p2, n, m, m1, m2 110 { 0, 2, 20, 1, 79, 2, 11}, // min 111 { 0, 3, 2, 7, 127, 3, 156}, // max 112 0, 4000000, 6000000 113 }; 114 115 static pll_limits kLimitsBxt = { 116 // p, p1, p2, n, m, m1, m2 117 { 0, 2, 1, 1, 0, 2, 2 << 22}, // min 118 { 0, 4, 20, 1, 0, 2, 255 << 22}, // max 119 0, 4800000, 6700000 120 }; 121 #endif 122 123 static pll_limits kLimits9xxSdvo = { 124 // p, p1, p2, n, m, m1, m2 125 { 5, 1, 10, 5, 70, 12, 7}, // min 126 { 80, 8, 5, 10, 120, 22, 11}, // max 127 200000, 1400000, 2800000 128 }; 129 130 static pll_limits kLimits9xxLvds = { 131 // p, p1, p2, n, m, m1, m2 132 { 7, 1, 14, 1, 70, 8, 3}, // min 133 { 98, 8, 7, 6, 120, 18, 7}, // max 134 112000, 1400000, 2800000 135 }; 136 137 static pll_limits kLimitsG4xSdvo = { 138 // p, p1, p2, n, m, m1, m2 139 { 10, 1, 10, 1, 104, 17, 5}, // min 140 { 30, 3, 10, 4, 138, 23, 11}, // max 141 270000, 1750000, 3500000 142 }; 143 144 #if 0 145 static pll_limits kLimitsG4xHdmi = { 146 // p, p1, p2, n, m, m1, m2 147 { 5, 1, 10, 1, 104, 16, 5}, // min 148 { 80, 8, 5, 4, 138, 23, 11}, // max 149 165000, 1750000, 3500000 150 }; 151 #endif 152 153 static pll_limits kLimitsG4xLvdsSingle = { 154 // p, p1, p2, n, m, m1, m2 155 { 28, 2, 14, 1, 104, 17, 5}, // min 156 { 112, 8, 14, 3, 138, 23, 11}, // max 157 0, 1750000, 3500000 158 }; 159 160 static pll_limits kLimitsG4xLvdsDual = { 161 // p, p1, p2, n, m, m1, m2 162 { 14, 2, 7, 1, 104, 17, 5}, // min 163 { 42, 6, 7, 3, 138, 23, 11}, // max 164 0, 1750000, 3500000 165 }; 166 167 static pll_limits kLimitsPinSdvo = { 168 // p, p1, p2, n, m, m1, m2 169 { 5, 1, 10, 3, 2, 0, 0}, // min 170 { 80, 8, 5, 6, 256, 0, 254}, // max 171 200000, 1700000, 3500000 172 }; 173 174 static pll_limits kLimitsPinLvds = { 175 // p, p1, p2, n, m, m1, m2 176 { 7, 1, 14, 3, 2, 0, 0}, // min 177 {112, 8, 14, 6, 256, 0, 254}, // max 178 112000, 1700000, 3500000 179 }; 180 181 static pll_limits kLimits85x = { 182 // p, p1, p2, n, m, m1, m2 183 { 4, 2, 4, 5, 96, 20, 8}, 184 {128, 33, 2, 18, 140, 28, 18}, 185 165000, 930000, 1400000 186 }; 187 188 189 static bool 190 lvds_dual_link(display_mode* current) 191 { 192 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 193 if (requestedPixelClock > 112.999) 194 return true; 195 196 // TODO: Force dual link on MacBookPro6,2 MacBookPro8,2 MacBookPro9,1 197 198 return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) 199 == LVDS_CLKB_POWER_UP); 200 } 201 202 203 bool 204 valid_pll_divisors(pll_divisors* divisors, pll_limits* limits) 205 { 206 pll_info &info = gInfo->shared_info->pll_info; 207 uint32 vco = info.reference_frequency * divisors->m / divisors->n; 208 uint32 frequency = vco / divisors->p; 209 210 if (divisors->p < limits->min.p || divisors->p > limits->max.p 211 || divisors->m < limits->min.m || divisors->m > limits->max.m 212 || vco < limits->min_vco || vco > limits->max_vco 213 || frequency < info.min_frequency || frequency > info.max_frequency) 214 return false; 215 216 return true; 217 } 218 219 220 static void 221 compute_pll_p2(display_mode* current, pll_divisors* divisors, 222 pll_limits* limits, bool isLVDS) 223 { 224 if (isLVDS) { 225 if (lvds_dual_link(current)) { 226 // fast DAC timing via 2 channels (dual link LVDS) 227 divisors->p2 = limits->max.p2; 228 } else { 229 // slow DAC timing 230 divisors->p2 = limits->min.p2; 231 } 232 } else { 233 if (current->timing.pixel_clock < limits->dot_limit) { 234 // slow DAC timing 235 divisors->p2 = limits->min.p2; 236 } else { 237 // fast DAC timing 238 divisors->p2 = limits->max.p2; 239 } 240 } 241 } 242 243 244 static uint32 245 compute_pll_m(pll_divisors* divisors) 246 { 247 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV) 248 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 249 return divisors->m1 * divisors->m2; 250 } 251 252 // Pineview, m1 is reserved 253 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) 254 return divisors->m2 + 2; 255 256 if (gInfo->shared_info->device_type.Generation() >= 3) 257 return 5 * (divisors->m1 + 2) + (divisors->m2 + 2); 258 259 // TODO: This logic needs validated... PLL's were calculated differently 260 // on 8xx chipsets 261 262 return 5 * divisors->m1 + divisors->m2; 263 } 264 265 266 static uint32 267 compute_pll_p(pll_divisors* divisors) 268 { 269 return divisors->p1 * divisors->p2; 270 } 271 272 273 static void 274 compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS) 275 { 276 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 277 float referenceClock 278 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 279 280 TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); 281 282 pll_limits limits; 283 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) { 284 // TODO: Pass port type via video_configuration 285 if (isLVDS) { 286 if (lvds_dual_link(current)) 287 memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits)); 288 else 289 memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits)); 290 //} else if (type == INTEL_PORT_TYPE_HDMI) { 291 // memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits)); 292 } else 293 memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits)); 294 } else { 295 if (isLVDS) { 296 if (lvds_dual_link(current)) { 297 if (referenceClock == 100.0) 298 memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits)); 299 else 300 memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits)); 301 } else { 302 if (referenceClock == 100.0) { 303 memcpy(&limits, &kLimitsIlkLvdsSingle100, 304 sizeof(pll_limits)); 305 } else { 306 memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits)); 307 } 308 } 309 } else { 310 memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits)); 311 } 312 } 313 314 compute_pll_p2(current, divisors, &limits, isLVDS); 315 316 TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " 317 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 318 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, 319 limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, 320 limits.min.m1, limits.min.m2); 321 TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " 322 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 323 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, 324 limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, 325 limits.max.m1, limits.max.m2); 326 327 float best = requestedPixelClock; 328 pll_divisors bestDivisors; 329 330 uint32 maxn = limits.max.n; 331 for (divisors->n = limits.min.n; divisors->n <= maxn; divisors->n++) { 332 for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1; 333 divisors->m1--) { 334 for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2; 335 divisors->m2--) { 336 for (divisors->p1 = limits.max.p1; 337 divisors->p1 >= limits.min.p1; divisors->p1--) { 338 divisors->m = compute_pll_m(divisors); 339 divisors->p = compute_pll_p(divisors); 340 341 if (!valid_pll_divisors(divisors, &limits)) 342 continue; 343 344 float error = fabs(requestedPixelClock 345 - ((referenceClock * divisors->m) / divisors->n) 346 / divisors->p); 347 if (error < best) { 348 best = error; 349 bestDivisors = *divisors; 350 maxn = divisors->n; 351 352 if (error == 0) 353 break; 354 } 355 } 356 } 357 } 358 } 359 *divisors = bestDivisors; 360 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 361 ((referenceClock * divisors->m) / divisors->n) / divisors->p, 362 best); 363 } 364 365 366 static void 367 compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS) 368 { 369 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 370 float referenceClock 371 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 372 373 TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); 374 375 pll_limits limits; 376 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 377 if (isLVDS) 378 memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits)); 379 else 380 memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits)); 381 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_85x)) { 382 memcpy(&limits, &kLimits85x, sizeof(pll_limits)); 383 } else { 384 if (isLVDS) 385 memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits)); 386 else 387 memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits)); 388 } 389 390 compute_pll_p2(current, divisors, &limits, isLVDS); 391 392 TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " 393 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 394 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, 395 limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, 396 limits.min.m1, limits.min.m2); 397 TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " 398 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 399 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, 400 limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, 401 limits.max.m1, limits.max.m2); 402 403 bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN); 404 405 float best = requestedPixelClock; 406 pll_divisors bestDivisors; 407 408 for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1; 409 divisors->m1++) { 410 for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2 411 && ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) { 412 for (divisors->n = limits.min.n; divisors->n <= limits.max.n; 413 divisors->n++) { 414 for (divisors->p1 = limits.min.p1; 415 divisors->p1 <= limits.max.p1; divisors->p1++) { 416 divisors->m = compute_pll_m(divisors); 417 divisors->p = compute_pll_p(divisors); 418 419 if (!valid_pll_divisors(divisors, &limits)) 420 continue; 421 422 float error = fabs(requestedPixelClock 423 - ((referenceClock * divisors->m) / divisors->n) 424 / divisors->p); 425 if (error < best) { 426 best = error; 427 bestDivisors = *divisors; 428 429 if (error == 0) 430 break; 431 } 432 } 433 } 434 } 435 } 436 437 *divisors = bestDivisors; 438 439 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 440 ((referenceClock * divisors->m) / divisors->n) / divisors->p, 441 best); 442 } 443 444 445 void 446 compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) 447 { 448 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x) 449 || (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) { 450 compute_dpll_g4x(current, divisors, isLVDS); 451 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { 452 ERROR("%s: TODO: CherryView\n", __func__); 453 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 454 ERROR("%s: TODO: VallyView\n", __func__); 455 } else 456 compute_dpll_9xx(current, divisors, isLVDS); 457 458 TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", " 459 "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " " 460 "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__, 461 divisors->p, divisors->p1, divisors->p2, divisors->n, 462 divisors->m, divisors->m1, divisors->m2); 463 } 464 465 466 void 467 refclk_activate_ilk(bool hasPanel) 468 { 469 CALLED(); 470 471 // aka, our engineers hate you 472 473 bool wantsSSC; 474 bool hasCK505; 475 if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) { 476 //XXX: This should be == vbt display_clock_mode 477 hasCK505 = true; 478 wantsSSC = hasCK505; 479 } else { 480 hasCK505 = false; 481 wantsSSC = true; 482 } 483 484 uint32 clkRef = read32(PCH_DREF_CONTROL); 485 uint32 newRef = clkRef; 486 487 newRef &= ~DREF_NONSPREAD_SOURCE_MASK; 488 489 if (hasCK505) 490 newRef |= DREF_NONSPREAD_CK505_ENABLE; 491 else 492 newRef |= DREF_NONSPREAD_SOURCE_ENABLE; 493 494 newRef &= ~DREF_SSC_SOURCE_MASK; 495 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 496 newRef &= ~DREF_SSC1_ENABLE; 497 498 if (newRef == clkRef) { 499 TRACE("%s: No changes to reference clock.\n", __func__); 500 return; 501 } 502 503 if (hasPanel) { 504 newRef &= ~DREF_SSC_SOURCE_MASK; 505 newRef |= DREF_SSC_SOURCE_ENABLE; 506 507 if (wantsSSC) 508 newRef |= DREF_SSC1_ENABLE; 509 else 510 newRef &= ~DREF_SSC1_ENABLE; 511 512 // Power up SSC before enabling outputs 513 write32(PCH_DREF_CONTROL, newRef); 514 read32(PCH_DREF_CONTROL); 515 spin(200); 516 517 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 518 519 bool hasEDP = true; 520 if (hasEDP) { 521 if (wantsSSC) 522 newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; 523 else 524 newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; 525 } else 526 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 527 528 write32(PCH_DREF_CONTROL, newRef); 529 read32(PCH_DREF_CONTROL); 530 spin(200); 531 } else { 532 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 533 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 534 535 write32(PCH_DREF_CONTROL, newRef); 536 read32(PCH_DREF_CONTROL); 537 spin(200); 538 539 if (!wantsSSC) { 540 newRef &= ~DREF_SSC_SOURCE_MASK; 541 newRef |= DREF_SSC_SOURCE_DISABLE; 542 newRef &= ~DREF_SSC1_ENABLE; 543 544 write32(PCH_DREF_CONTROL, newRef); 545 read32(PCH_DREF_CONTROL); 546 spin(200); 547 } 548 } 549 } 550 551 552 #ifdef PLL_TEST_MODE 553 554 const struct test_device { 555 uint32 type; 556 const char* name; 557 } kTestDevices[] = { 558 {INTEL_MODEL_915, "915"}, 559 {INTEL_MODEL_945, "945"}, 560 {INTEL_MODEL_965, "965"}, 561 {INTEL_MODEL_G33, "G33"}, 562 {INTEL_MODEL_G45, "G45"}, 563 {INTEL_MODEL_PINE, "PineView"}, 564 {INTEL_MODEL_ILKG, "IronLake"}, 565 {INTEL_MODEL_SNBG, "SandyBridge"}, 566 {INTEL_MODEL_IVBG, "IvyBridge"} 567 }; 568 569 570 static void 571 simulate_mode(display_mode* mode) 572 { 573 mode->timing.flags = 0; 574 mode->timing.pixel_clock = uint32(75.2 * 1000); 575 mode->timing.h_display = 1366; 576 mode->timing.h_sync_start = 1414; 577 mode->timing.h_sync_end = 1478; 578 mode->timing.h_total = 1582; 579 580 mode->timing.v_display = 768; 581 mode->timing.v_sync_start = 772; 582 mode->timing.v_sync_end = 779; 583 mode->timing.v_total = 792; 584 585 mode->virtual_width = 1366; 586 mode->virtual_height = 768; 587 } 588 589 590 int 591 main(void) 592 { 593 display_mode fakeMode; 594 simulate_mode(&fakeMode); 595 596 // First we simulate our global card info structs 597 gInfo = (accelerant_info*)malloc(sizeof(accelerant_info)); 598 if (gInfo == NULL) { 599 ERROR("Unable to malloc artificial gInfo!\n"); 600 return 1; 601 } 602 gInfo->shared_info = (intel_shared_info*)malloc(sizeof(intel_shared_info)); 603 604 for (uint32 index = 0; index < (sizeof(kTestDevices) / sizeof(test_device)); 605 index++) { 606 gInfo->shared_info->device_type = kTestDevices[index].type; 607 ERROR("=== %s (Generation %d)\n", kTestDevices[index].name, 608 gInfo->shared_info->device_type.Generation()); 609 610 if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_9xx) 611 | gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_SER5)) { 612 gInfo->shared_info->pll_info.reference_frequency = 96000; 613 gInfo->shared_info->pll_info.max_frequency = 400000; 614 gInfo->shared_info->pll_info.min_frequency = 20000; 615 } else { 616 gInfo->shared_info->pll_info.reference_frequency = 96000; 617 gInfo->shared_info->pll_info.max_frequency = 400000; 618 gInfo->shared_info->pll_info.min_frequency = 20000; 619 } 620 621 pll_divisors output; 622 compute_pll_divisors(&fakeMode, &output, false); 623 } 624 625 free(gInfo->shared_info); 626 free(gInfo); 627 return 0; 628 } 629 #endif 630