1 /* 2 * Copyright 2006-2018, 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 * Adrien Destugues, pulkomandy@pulkomandy.tk 9 */ 10 11 12 #include "pll.h" 13 14 #include <math.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include <Debug.h> 19 20 #include <create_display_modes.h> 21 #include <ddc.h> 22 #include <edid.h> 23 #include <validate_display_mode.h> 24 25 #include "accelerant_protos.h" 26 #include "accelerant.h" 27 #include "utility.h" 28 29 30 #undef TRACE 31 #define TRACE_MODE 32 #ifdef TRACE_MODE 33 # define TRACE(x...) _sPrintf("intel_extreme: " x) 34 #else 35 # define TRACE(x...) 36 #endif 37 38 #define ERROR(x...) _sPrintf("intel_extreme: " x) 39 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 40 41 42 // PLL limits, taken from i915 DRM driver. However, note that we use the values of 43 // N+2, M1+2 and M2+2 here, the - 2 being applied when we write the values to the registers. 44 45 static pll_limits kLimits85x = { 46 // p, p1, p2, n, m, m1, m2 47 { 4, 2, 2, 4, 96, 20, 8}, 48 {128, 33, 4, 18, 140, 28, 18}, 49 165000, 908000, 1512000 50 }; 51 52 // For Iron Lake, a new set of timings is introduced along with the FDI system, 53 // and carried on to later cards with just one further change (to the P2 cutoff 54 // frequency) in Sandy Bridge. 55 56 static pll_limits kLimits9xxSdvo = { 57 // p, p1, p2, n, m, m1, m2 58 { 5, 1, 5, 3, 70, 10, 5}, // min 59 { 80, 8, 10, 8, 120, 20, 9}, // max 60 200000, 1400000, 2800000 61 }; 62 63 static pll_limits kLimits9xxLvds = { 64 // p, p1, p2, n, m, m1, m2 65 { 7, 1, 7, 3, 70, 10, 5}, // min 66 { 98, 8, 14, 8, 120, 20, 9}, // max 67 112000, 1400000, 2800000 68 }; 69 70 // Limits for G45 cards taken from i915 DRM driver, mixed with old setup 71 // plus tests to accomodate lower resolutions with still correct refresh. 72 // Note that n here is actually n+2, same applies to m1 and m2. 73 74 static pll_limits kLimitsG4xSdvo = { 75 // p, p1, p2, n, m, m1, m2 76 { 10, 1, 10, 3, 104, 19, 7}, // min 77 { 80, 8, 10, 8, 138, 25, 13}, // max 78 270000, 1750000, 3500000 79 }; 80 81 #if 0 82 static pll_limits kLimitsG4xHdmi = { 83 // p, p1, p2, n, m, m1, m2 84 { 5, 1, 5, 3, 104, 18, 7}, // min 85 { 80, 8, 10, 8, 138, 25, 13}, // max 86 165000, 1750000, 3500000 87 }; 88 #endif 89 90 static pll_limits kLimitsG4xLvdsSingle = { 91 // p, p1, p2, n, m, m1, m2 92 { 28, 2, 14, 3, 104, 19, 7}, // min 93 {112, 8, 14, 8, 138, 25, 13}, // max 94 0, 1750000, 3500000 95 }; 96 97 static pll_limits kLimitsG4xLvdsDual = { 98 // p, p1, p2, n, m, m1, m2 99 { 14, 2, 7, 3, 104, 19, 7}, // min 100 { 42, 6, 7, 8, 138, 25, 13}, // max 101 0, 1750000, 3500000 102 }; 103 104 static pll_limits kLimitsIlkDac = { 105 // p, p1, p2, n, m, m1, m2 106 { 5, 1, 5, 3, 79, 14, 7}, // min 107 { 80, 8, 10, 7, 127, 24, 11}, // max 108 225000, 1760000, 3510000 109 }; 110 111 static pll_limits kLimitsIlkLvdsSingle = { 112 // p, p1, p2, n, m, m1, m2 113 { 28, 2, 14, 3, 79, 14, 7}, // min 114 {112, 8, 14, 5, 118, 24, 11}, // max 115 225000, 1760000, 3510000 116 }; 117 118 static pll_limits kLimitsIlkLvdsDual = { 119 // p, p1, p2, n, m, m1, m2 120 { 14, 2, 7, 3, 79, 14, 7}, // min 121 { 56, 8, 7, 5, 127, 24, 11}, // max 122 225000, 1760000, 3510000 123 }; 124 125 // 100Mhz RefClock 126 static pll_limits kLimitsIlkLvdsSingle100 = { 127 // p, p1, p2, n, m, m1, m2 128 { 28, 2, 14, 3, 79, 14, 7}, // min 129 {112, 8, 14, 4, 126, 24, 11}, // max 130 225000, 1760000, 3510000 131 }; 132 133 static pll_limits kLimitsIlkLvdsDual100 = { 134 // p, p1, p2, n, m, m1, m2 135 { 14, 2, 7, 3, 79, 14, 7}, // min 136 { 42, 6, 7, 5, 126, 24, 11}, // max 137 225000, 1760000, 3510000 138 }; 139 140 // TODO From haswell onwards, a completely different PLL design is used 141 // (intel_gfx-prm-osrc-hsw-display_0.pdf, page 268 for VGA). It uses a "virtual 142 // root frequency" and one just has to set a single divider (integer and 143 // fractional parts), so it makes no sense to reuse the same code and limit 144 // structures there. 145 // 146 // For other display connections, the clock is handled differently, as there is 147 // no need for a precise timing to send things in sync with the display. 148 #if 0 149 static pll_limits kLimitsChv = { 150 // p, p1, p2, n, m, m1, m2 151 { 0, 2, 1, 1, 79, 2, 24 << 22}, // min 152 { 0, 4, 14, 1, 127, 2, 175 << 22}, // max 153 0, 4800000, 6480000 154 }; 155 156 static pll_limits kLimitsVlv = { 157 // p, p1, p2, n, m, m1, m2 158 { 0, 2, 2, 1, 79, 2, 11}, // min 159 { 0, 3, 20, 7, 127, 3, 156}, // max 160 0, 4000000, 6000000 161 }; 162 163 static pll_limits kLimitsBxt = { 164 // p, p1, p2, n, m, m1, m2 165 { 0, 2, 1, 1, 0, 2, 2 << 22}, // min 166 { 0, 4, 20, 1, 0, 2, 255 << 22}, // max 167 0, 4800000, 6700000 168 }; 169 #endif 170 171 static pll_limits kLimitsPinSdvo = { 172 // p, p1, p2, n, m, m1, m2 173 { 5, 1, 5, 3, 2, 0, 0}, // min 174 { 80, 8, 10, 6, 256, 0, 254}, // max 175 200000, 1700000, 3500000 176 }; 177 178 static pll_limits kLimitsPinLvds = { 179 // p, p1, p2, n, m, m1, m2 180 { 7, 1, 14, 3, 2, 0, 0}, // min 181 {112, 8, 14, 6, 256, 0, 254}, // max 182 112000, 1700000, 3500000 183 }; 184 185 186 static bool 187 lvds_dual_link(display_mode* current) 188 { 189 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 190 if (requestedPixelClock > 112.999) 191 return true; 192 193 // TODO: Force dual link on MacBookPro6,2 MacBookPro8,2 MacBookPro9,1 194 195 return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) 196 == LVDS_CLKB_POWER_UP); 197 } 198 199 200 bool 201 valid_pll_divisors(pll_divisors* divisors, pll_limits* limits) 202 { 203 pll_info &info = gInfo->shared_info->pll_info; 204 uint32 vco = info.reference_frequency * divisors->m / divisors->n; 205 uint32 frequency = vco / divisors->p; 206 207 if (divisors->p < limits->min.p || divisors->p > limits->max.p 208 || divisors->m < limits->min.m || divisors->m > limits->max.m 209 || vco < limits->min_vco || vco > limits->max_vco 210 || frequency < info.min_frequency || frequency > info.max_frequency) 211 return false; 212 213 return true; 214 } 215 216 217 static void 218 compute_pll_p2(display_mode* current, pll_divisors* divisors, 219 pll_limits* limits, bool isLVDS) 220 { 221 if (isLVDS) { 222 if (lvds_dual_link(current)) { 223 // fast DAC timing via 2 channels (dual link LVDS) 224 divisors->p2 = limits->min.p2; 225 } else { 226 // slow DAC timing 227 divisors->p2 = limits->max.p2; 228 } 229 } else { 230 if (current->timing.pixel_clock < limits->dot_limit) { 231 // slow DAC timing 232 divisors->p2 = limits->max.p2; 233 } else { 234 // fast DAC timing 235 divisors->p2 = limits->min.p2; 236 } 237 } 238 } 239 240 241 // TODO we can simplify this computation, with the way the dividers are set, we 242 // know that all values in the valid range for M are reachable. M1 allows to 243 // generate any multiple of 5 in the range and M2 allows to reach the 4 next 244 // values. Therefore, we don't need to loop over the range of values for M1 and 245 // M2 separately, we could instead just loop over possible values for M. 246 // For this to work, the logic of this function must be reversed: for a given M, 247 // it should give the resulting M1 and M2 values for programming the registers. 248 static uint32 249 compute_pll_m(pll_divisors* divisors) 250 { 251 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV) 252 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 253 return divisors->m1 * divisors->m2; 254 } 255 256 // Pineview, m1 is reserved 257 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) 258 return divisors->m2; 259 260 return 5 * divisors->m1 + divisors->m2; 261 } 262 263 264 static uint32 265 compute_pll_p(pll_divisors* divisors) 266 { 267 return divisors->p1 * divisors->p2; 268 } 269 270 271 static void 272 compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS) 273 { 274 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 275 float referenceClock 276 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 277 278 TRACE("%s: required MHz: %g, reference clock: %g\n", __func__, 279 requestedPixelClock, referenceClock); 280 281 pll_limits limits; 282 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) { 283 // TODO: Pass port type via video_configuration 284 if (isLVDS) { 285 if (lvds_dual_link(current)) 286 memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits)); 287 else 288 memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits)); 289 //} else if (type == INTEL_PORT_TYPE_HDMI) { 290 // memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits)); 291 } else 292 memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits)); 293 } else { 294 // There must be a PCH, so this is ivy bridge or later 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 for (divisors->n = limits.min.n; divisors->n <= limits.max.n; 331 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) 346 / (divisors->n * divisors->p)); 347 if (error < best) { 348 best = error; 349 bestDivisors = *divisors; 350 351 if (error == 0) 352 break; 353 } 354 } 355 } 356 } 357 } 358 *divisors = bestDivisors; 359 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 360 (referenceClock * divisors->m) / (divisors->n * divisors->p), 361 best); 362 } 363 364 365 static void 366 compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS) 367 { 368 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 369 float referenceClock 370 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 371 372 TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); 373 374 pll_limits limits; 375 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 376 if (isLVDS) 377 memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits)); 378 else 379 memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits)); 380 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_85x)) { 381 memcpy(&limits, &kLimits85x, sizeof(pll_limits)); 382 } else { 383 if (isLVDS) 384 memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits)); 385 else 386 memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits)); 387 } 388 389 compute_pll_p2(current, divisors, &limits, isLVDS); 390 391 TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " 392 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 393 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, 394 limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, 395 limits.min.m1, limits.min.m2); 396 TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " 397 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 398 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, 399 limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, 400 limits.max.m1, limits.max.m2); 401 402 bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN); 403 404 float best = requestedPixelClock; 405 pll_divisors bestDivisors; 406 memset(&bestDivisors, 0, sizeof(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) 424 / (divisors->n * 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 if (best == requestedPixelClock) 440 debugger("No valid PLL configuration found"); 441 else { 442 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 443 (referenceClock * divisors->m) / (divisors->n * divisors->p), 444 best); 445 } 446 } 447 448 449 void 450 compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) 451 { 452 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x) 453 || (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) { 454 compute_dpll_g4x(current, divisors, isLVDS); 455 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { 456 ERROR("%s: TODO: CherryView\n", __func__); 457 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 458 ERROR("%s: TODO: VallyView\n", __func__); 459 } else 460 compute_dpll_9xx(current, divisors, isLVDS); 461 462 TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", " 463 "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " " 464 "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__, 465 divisors->p, divisors->p1, divisors->p2, divisors->n, 466 divisors->m, divisors->m1, divisors->m2); 467 } 468 469 470 void 471 refclk_activate_ilk(bool hasPanel) 472 { 473 CALLED(); 474 475 // aka, our engineers hate you 476 477 bool wantsSSC; 478 bool hasCK505; 479 if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) { 480 //XXX: This should be == vbt display_clock_mode 481 hasCK505 = false; 482 wantsSSC = hasCK505; 483 } else { 484 hasCK505 = false; 485 wantsSSC = true; 486 } 487 488 uint32 clkRef = read32(PCH_DREF_CONTROL); 489 uint32 newRef = clkRef; 490 491 newRef &= ~DREF_NONSPREAD_SOURCE_MASK; 492 493 if (hasCK505) 494 newRef |= DREF_NONSPREAD_CK505_ENABLE; 495 else 496 newRef |= DREF_NONSPREAD_SOURCE_ENABLE; 497 498 newRef &= ~DREF_SSC_SOURCE_MASK; 499 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 500 newRef &= ~DREF_SSC1_ENABLE; 501 502 if (newRef == clkRef) { 503 TRACE("%s: No changes to reference clock.\n", __func__); 504 return; 505 } 506 507 if (hasPanel) { 508 newRef &= ~DREF_SSC_SOURCE_MASK; 509 newRef |= DREF_SSC_SOURCE_ENABLE; 510 511 if (wantsSSC) 512 newRef |= DREF_SSC1_ENABLE; 513 else 514 newRef &= ~DREF_SSC1_ENABLE; 515 516 // Power up SSC before enabling outputs 517 write32(PCH_DREF_CONTROL, newRef); 518 read32(PCH_DREF_CONTROL); 519 spin(200); 520 521 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 522 523 bool hasEDP = true; 524 if (hasEDP) { 525 if (wantsSSC) 526 newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; 527 else 528 newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; 529 } else 530 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 531 532 write32(PCH_DREF_CONTROL, newRef); 533 read32(PCH_DREF_CONTROL); 534 spin(200); 535 } else { 536 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 537 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 538 539 write32(PCH_DREF_CONTROL, newRef); 540 read32(PCH_DREF_CONTROL); 541 spin(200); 542 543 if (!wantsSSC) { 544 newRef &= ~DREF_SSC_SOURCE_MASK; 545 newRef |= DREF_SSC_SOURCE_DISABLE; 546 newRef &= ~DREF_SSC1_ENABLE; 547 548 write32(PCH_DREF_CONTROL, newRef); 549 read32(PCH_DREF_CONTROL); 550 spin(200); 551 } 552 } 553 } 554 555