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 43 // Static pll limits taken from Linux kernel KMS 44 45 static pll_limits kLimitsIlkDac = { 46 // p, p1, p2, n, m, m1, m2 47 { 5, 1, 5, 3, 79, 12, 5}, // min 48 { 80, 8, 10, 8, 118, 22, 9}, // max 49 225000, 1760000, 3510000 50 }; 51 52 static pll_limits kLimitsIlkLvdsSingle = { 53 // p, p1, p2, n, m, m1, m2 54 { 28, 2, 14, 3, 79, 12, 5}, // min 55 {112, 8, 14, 8, 118, 22, 9}, // max 56 225000, 1760000, 3510000 57 }; 58 59 static pll_limits kLimitsIlkLvdsDual = { 60 // p, p1, p2, n, m, m1, m2 61 { 14, 2, 7, 3, 79, 12, 5}, // min 62 { 56, 8, 7, 8, 127, 22, 9}, // max 63 225000, 1760000, 3510000 64 }; 65 66 // 100Mhz RefClock 67 static pll_limits kLimitsIlkLvdsSingle100 = { 68 // p, p1, p2, n, m, m1, m2 69 { 28, 2, 14, 3, 79, 12, 5}, // min 70 {112, 8, 14, 8, 126, 22, 9}, // max 71 225000, 1760000, 3510000 72 }; 73 74 static pll_limits kLimitsIlkLvdsDual100 = { 75 // p, p1, p2, n, m, m1, m2 76 { 14, 2, 7, 3, 79, 12, 5}, // min 77 { 42, 6, 7, 8, 126, 22, 9}, // max 78 225000, 1760000, 3510000 79 }; 80 81 #if 0 82 static pll_limits kLimitsChv = { 83 // p, p1, p2, n, m, m1, m2 84 { 0, 2, 14, 1, 79, 2, 24 << 22}, // min 85 { 0, 4, 1, 1, 127, 2, 175 << 22}, // max 86 0, 4800000, 6480000 87 }; 88 89 static pll_limits kLimitsVlv = { 90 // p, p1, p2, n, m, m1, m2 91 { 0, 2, 20, 1, 79, 2, 11}, // min 92 { 0, 3, 2, 7, 127, 3, 156}, // max 93 0, 4000000, 6000000 94 }; 95 96 static pll_limits kLimitsBxt = { 97 // p, p1, p2, n, m, m1, m2 98 { 0, 2, 1, 1, 0, 2, 2 << 22}, // min 99 { 0, 4, 20, 1, 0, 2, 255 << 22}, // max 100 0, 4800000, 6700000 101 }; 102 #endif 103 104 static pll_limits kLimits9xxSdvo = { 105 // p, p1, p2, n, m, m1, m2 106 { 5, 1, 10, 5, 70, 12, 7}, // min 107 { 80, 8, 5, 10, 120, 22, 11}, // max 108 200000, 1400000, 2800000 109 }; 110 111 static pll_limits kLimits9xxLvds = { 112 // p, p1, p2, n, m, m1, m2 113 { 7, 1, 14, 1, 70, 8, 3}, // min 114 { 98, 8, 7, 6, 120, 18, 7}, // max 115 112000, 1400000, 2800000 116 }; 117 118 static pll_limits kLimitsG4xSdvo = { 119 // p, p1, p2, n, m, m1, m2 120 { 10, 1, 10, 1, 104, 17, 5}, // min 121 { 30, 3, 10, 4, 138, 23, 11}, // max 122 270000, 1750000, 3500000 123 }; 124 125 #if 0 126 static pll_limits kLimitsG4xHdmi = { 127 // p, p1, p2, n, m, m1, m2 128 { 5, 1, 10, 1, 104, 16, 5}, // min 129 { 80, 8, 5, 4, 138, 23, 11}, // max 130 165000, 1750000, 3500000 131 }; 132 #endif 133 134 static pll_limits kLimitsG4xLvdsSingle = { 135 // p, p1, p2, n, m, m1, m2 136 { 28, 2, 14, 1, 104, 17, 5}, // min 137 { 112, 8, 14, 3, 138, 23, 11}, // max 138 0, 1750000, 3500000 139 }; 140 141 static pll_limits kLimitsG4xLvdsDual = { 142 // p, p1, p2, n, m, m1, m2 143 { 14, 2, 7, 1, 104, 17, 5}, // min 144 { 42, 6, 7, 3, 138, 23, 11}, // max 145 0, 1750000, 3500000 146 }; 147 148 static pll_limits kLimitsPinSdvo = { 149 // p, p1, p2, n, m, m1, m2 150 { 5, 1, 10, 3, 2, 0, 0}, // min 151 { 80, 8, 5, 6, 256, 0, 254}, // max 152 200000, 1700000, 3500000 153 }; 154 155 static pll_limits kLimitsPinLvds = { 156 // p, p1, p2, n, m, m1, m2 157 { 7, 1, 14, 3, 2, 0, 0}, // min 158 {112, 8, 14, 6, 256, 0, 254}, // max 159 112000, 1700000, 3500000 160 }; 161 162 static pll_limits kLimits85x = { 163 // p, p1, p2, n, m, m1, m2 164 { 4, 2, 4, 5, 96, 20, 8}, 165 {128, 33, 2, 18, 140, 28, 18}, 166 165000, 930000, 1400000 167 }; 168 169 170 static bool 171 lvds_dual_link(display_mode* current) 172 { 173 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 174 if (requestedPixelClock > 112.999) 175 return true; 176 177 // TODO: Force dual link on MacBookPro6,2 MacBookPro8,2 MacBookPro9,1 178 179 return ((read32(INTEL_DIGITAL_LVDS_PORT) & LVDS_CLKB_POWER_MASK) 180 == LVDS_CLKB_POWER_UP); 181 } 182 183 184 bool 185 valid_pll_divisors(pll_divisors* divisors, pll_limits* limits) 186 { 187 pll_info &info = gInfo->shared_info->pll_info; 188 uint32 vco = info.reference_frequency * divisors->m / divisors->n; 189 uint32 frequency = vco / divisors->p; 190 191 if (divisors->p < limits->min.p || divisors->p > limits->max.p 192 || divisors->m < limits->min.m || divisors->m > limits->max.m 193 || vco < limits->min_vco || vco > limits->max_vco 194 || frequency < info.min_frequency || frequency > info.max_frequency) 195 return false; 196 197 return true; 198 } 199 200 201 static void 202 compute_pll_p2(display_mode* current, pll_divisors* divisors, 203 pll_limits* limits, bool isLVDS) 204 { 205 if (isLVDS) { 206 if (lvds_dual_link(current)) { 207 // fast DAC timing via 2 channels (dual link LVDS) 208 divisors->p2 = limits->max.p2; 209 } else { 210 // slow DAC timing 211 divisors->p2 = limits->min.p2; 212 } 213 } else { 214 if (current->timing.pixel_clock < limits->dot_limit) { 215 // slow DAC timing 216 divisors->p2 = limits->max.p2; 217 } else { 218 // fast DAC timing 219 divisors->p2 = limits->min.p2; 220 } 221 } 222 } 223 224 225 static uint32 226 compute_pll_m(pll_divisors* divisors) 227 { 228 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV) 229 || gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 230 return divisors->m1 * divisors->m2; 231 } 232 233 // Pineview, m1 is reserved 234 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) 235 return divisors->m2 + 2; 236 237 if (gInfo->shared_info->device_type.Generation() >= 3) 238 return 5 * (divisors->m1 + 2) + (divisors->m2 + 2); 239 240 // TODO: This logic needs validated... PLL's were calculated differently 241 // on 8xx chipsets 242 243 return 5 * divisors->m1 + divisors->m2; 244 } 245 246 247 static uint32 248 compute_pll_p(pll_divisors* divisors) 249 { 250 return divisors->p1 * divisors->p2; 251 } 252 253 254 static void 255 compute_dpll_g4x(display_mode* current, pll_divisors* divisors, bool isLVDS) 256 { 257 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 258 float referenceClock 259 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 260 261 TRACE("%s: required MHz: %g, reference clock: %g\n", __func__, 262 requestedPixelClock, referenceClock); 263 264 pll_limits limits; 265 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x)) { 266 // TODO: Pass port type via video_configuration 267 if (isLVDS) { 268 if (lvds_dual_link(current)) 269 memcpy(&limits, &kLimitsG4xLvdsDual, sizeof(pll_limits)); 270 else 271 memcpy(&limits, &kLimitsG4xLvdsSingle, sizeof(pll_limits)); 272 //} else if (type == INTEL_PORT_TYPE_HDMI) { 273 // memcpy(&limits, &kLimitsG4xHdmi, sizeof(pll_limits)); 274 } else 275 memcpy(&limits, &kLimitsG4xSdvo, sizeof(pll_limits)); 276 } else { 277 // There must be a PCH, so this is ivy bridge or later 278 if (isLVDS) { 279 if (lvds_dual_link(current)) { 280 if (referenceClock == 100.0) 281 memcpy(&limits, &kLimitsIlkLvdsDual100, sizeof(pll_limits)); 282 else 283 memcpy(&limits, &kLimitsIlkLvdsDual, sizeof(pll_limits)); 284 } else { 285 if (referenceClock == 100.0) { 286 memcpy(&limits, &kLimitsIlkLvdsSingle100, 287 sizeof(pll_limits)); 288 } else { 289 memcpy(&limits, &kLimitsIlkLvdsSingle, sizeof(pll_limits)); 290 } 291 } 292 } else { 293 memcpy(&limits, &kLimitsIlkDac, sizeof(pll_limits)); 294 } 295 } 296 297 compute_pll_p2(current, divisors, &limits, isLVDS); 298 299 TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " 300 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 301 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, 302 limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, 303 limits.min.m1, limits.min.m2); 304 TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " 305 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 306 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, 307 limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, 308 limits.max.m1, limits.max.m2); 309 310 float best = requestedPixelClock; 311 pll_divisors bestDivisors; 312 313 for (divisors->n = limits.min.n; divisors->n <= limits.max.n; 314 divisors->n++) { 315 for (divisors->m1 = limits.max.m1; divisors->m1 >= limits.min.m1; 316 divisors->m1--) { 317 for (divisors->m2 = limits.max.m2; divisors->m2 >= limits.min.m2; 318 divisors->m2--) { 319 for (divisors->p1 = limits.max.p1; 320 divisors->p1 >= limits.min.p1; divisors->p1--) { 321 divisors->m = compute_pll_m(divisors); 322 divisors->p = compute_pll_p(divisors); 323 324 if (!valid_pll_divisors(divisors, &limits)) 325 continue; 326 327 float error = fabs(requestedPixelClock 328 - ((referenceClock * divisors->m) / divisors->n) 329 / divisors->p); 330 if (error < best) { 331 best = error; 332 bestDivisors = *divisors; 333 334 if (error == 0) 335 break; 336 } 337 } 338 } 339 } 340 } 341 *divisors = bestDivisors; 342 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 343 ((referenceClock * divisors->m) / divisors->n) / divisors->p, 344 best); 345 } 346 347 348 static void 349 compute_dpll_9xx(display_mode* current, pll_divisors* divisors, bool isLVDS) 350 { 351 float requestedPixelClock = current->timing.pixel_clock / 1000.0f; 352 float referenceClock 353 = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 354 355 TRACE("%s: required MHz: %g\n", __func__, requestedPixelClock); 356 357 pll_limits limits; 358 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 359 if (isLVDS) 360 memcpy(&limits, &kLimitsPinLvds, sizeof(pll_limits)); 361 else 362 memcpy(&limits, &kLimitsPinSdvo, sizeof(pll_limits)); 363 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_85x)) { 364 memcpy(&limits, &kLimits85x, sizeof(pll_limits)); 365 } else { 366 if (isLVDS) 367 memcpy(&limits, &kLimits9xxLvds, sizeof(pll_limits)); 368 else 369 memcpy(&limits, &kLimits9xxSdvo, sizeof(pll_limits)); 370 } 371 372 compute_pll_p2(current, divisors, &limits, isLVDS); 373 374 TRACE("PLL limits, min: p %" B_PRId32 " (p1 %" B_PRId32 ", " 375 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 376 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.min.p, 377 limits.min.p1, limits.min.p2, limits.min.n, limits.min.m, 378 limits.min.m1, limits.min.m2); 379 TRACE("PLL limits, max: p %" B_PRId32 " (p1 %" B_PRId32 ", " 380 "p2 %" B_PRId32 "), n %" B_PRId32 ", m %" B_PRId32 " " 381 "(m1 %" B_PRId32 ", m2 %" B_PRId32 ")\n", limits.max.p, 382 limits.max.p1, limits.max.p2, limits.max.n, limits.max.m, 383 limits.max.m1, limits.max.m2); 384 385 bool is_pine = gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN); 386 387 float best = requestedPixelClock; 388 pll_divisors bestDivisors; 389 390 for (divisors->m1 = limits.min.m1; divisors->m1 <= limits.max.m1; 391 divisors->m1++) { 392 for (divisors->m2 = limits.min.m2; divisors->m2 <= limits.max.m2 393 && ((divisors->m2 < divisors->m1) || is_pine); divisors->m2++) { 394 for (divisors->n = limits.min.n; divisors->n <= limits.max.n; 395 divisors->n++) { 396 for (divisors->p1 = limits.min.p1; 397 divisors->p1 <= limits.max.p1; divisors->p1++) { 398 divisors->m = compute_pll_m(divisors); 399 divisors->p = compute_pll_p(divisors); 400 401 if (!valid_pll_divisors(divisors, &limits)) 402 continue; 403 404 float error = fabs(requestedPixelClock 405 - ((referenceClock * divisors->m) / divisors->n) 406 / divisors->p); 407 if (error < best) { 408 best = error; 409 bestDivisors = *divisors; 410 411 if (error == 0) 412 break; 413 } 414 } 415 } 416 } 417 } 418 419 *divisors = bestDivisors; 420 421 TRACE("%s: best MHz: %g (error: %g)\n", __func__, 422 ((referenceClock * divisors->m) / divisors->n) / divisors->p, 423 best); 424 } 425 426 427 void 428 compute_pll_divisors(display_mode* current, pll_divisors* divisors, bool isLVDS) 429 { 430 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_G4x) 431 || (gInfo->shared_info->pch_info != INTEL_PCH_NONE)) { 432 compute_dpll_g4x(current, divisors, isLVDS); 433 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_CHV)) { 434 ERROR("%s: TODO: CherryView\n", __func__); 435 } else if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_VLV)) { 436 ERROR("%s: TODO: VallyView\n", __func__); 437 } else 438 compute_dpll_9xx(current, divisors, isLVDS); 439 440 TRACE("%s: found: p = %" B_PRId32 " (p1 = %" B_PRId32 ", " 441 "p2 = %" B_PRId32 "), n = %" B_PRId32 ", m = %" B_PRId32 " " 442 "(m1 = %" B_PRId32 ", m2 = %" B_PRId32 ")\n", __func__, 443 divisors->p, divisors->p1, divisors->p2, divisors->n, 444 divisors->m, divisors->m1, divisors->m2); 445 } 446 447 448 void 449 refclk_activate_ilk(bool hasPanel) 450 { 451 CALLED(); 452 453 // aka, our engineers hate you 454 455 bool wantsSSC; 456 bool hasCK505; 457 if (gInfo->shared_info->pch_info == INTEL_PCH_IBX) { 458 //XXX: This should be == vbt display_clock_mode 459 hasCK505 = true; 460 wantsSSC = hasCK505; 461 } else { 462 hasCK505 = false; 463 wantsSSC = true; 464 } 465 466 uint32 clkRef = read32(PCH_DREF_CONTROL); 467 uint32 newRef = clkRef; 468 469 newRef &= ~DREF_NONSPREAD_SOURCE_MASK; 470 471 if (hasCK505) 472 newRef |= DREF_NONSPREAD_CK505_ENABLE; 473 else 474 newRef |= DREF_NONSPREAD_SOURCE_ENABLE; 475 476 newRef &= ~DREF_SSC_SOURCE_MASK; 477 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 478 newRef &= ~DREF_SSC1_ENABLE; 479 480 if (newRef == clkRef) { 481 TRACE("%s: No changes to reference clock.\n", __func__); 482 return; 483 } 484 485 if (hasPanel) { 486 newRef &= ~DREF_SSC_SOURCE_MASK; 487 newRef |= DREF_SSC_SOURCE_ENABLE; 488 489 if (wantsSSC) 490 newRef |= DREF_SSC1_ENABLE; 491 else 492 newRef &= ~DREF_SSC1_ENABLE; 493 494 // Power up SSC before enabling outputs 495 write32(PCH_DREF_CONTROL, newRef); 496 read32(PCH_DREF_CONTROL); 497 spin(200); 498 499 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 500 501 bool hasEDP = true; 502 if (hasEDP) { 503 if (wantsSSC) 504 newRef |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; 505 else 506 newRef |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; 507 } else 508 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 509 510 write32(PCH_DREF_CONTROL, newRef); 511 read32(PCH_DREF_CONTROL); 512 spin(200); 513 } else { 514 newRef &= ~DREF_CPU_SOURCE_OUTPUT_MASK; 515 newRef |= DREF_CPU_SOURCE_OUTPUT_DISABLE; 516 517 write32(PCH_DREF_CONTROL, newRef); 518 read32(PCH_DREF_CONTROL); 519 spin(200); 520 521 if (!wantsSSC) { 522 newRef &= ~DREF_SSC_SOURCE_MASK; 523 newRef |= DREF_SSC_SOURCE_DISABLE; 524 newRef &= ~DREF_SSC1_ENABLE; 525 526 write32(PCH_DREF_CONTROL, newRef); 527 read32(PCH_DREF_CONTROL); 528 spin(200); 529 } 530 } 531 } 532 533