1 /* 2 * Copyright 2011-2015, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz, mmlr@mlotz.ch 7 * Alexander von Gluck IV, kallisti5@unixzen.com 8 */ 9 #include "Pipes.h" 10 11 #include "accelerant.h" 12 #include "accelerant_protos.h" 13 #include "intel_extreme.h" 14 15 #include <stdlib.h> 16 #include <string.h> 17 18 #include <new> 19 20 21 #undef TRACE 22 #define TRACE_PIPE 23 #ifdef TRACE_PIPE 24 # define TRACE(x...) _sPrintf("intel_extreme: " x) 25 #else 26 # define TRACE(x...) ; 27 #endif 28 29 #define ERROR(x...) _sPrintf("intel_extreme: " x) 30 #define CALLED(x...) TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 31 32 33 // PIPE: 6 34 // PLANE: 7 35 36 37 void 38 program_pipe_color_modes(uint32 colorMode) 39 { 40 // All pipes get the same color mode 41 if (gInfo->shared_info->device_type.InFamily(INTEL_FAMILY_LAKE)) { 42 write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL) 43 & ~(DISPLAY_CONTROL_COLOR_MASK_SKY | DISPLAY_CONTROL_GAMMA)) 44 | colorMode); 45 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) 46 & ~(DISPLAY_CONTROL_COLOR_MASK_SKY | DISPLAY_CONTROL_GAMMA)) 47 | colorMode); 48 } else { 49 write32(INTEL_DISPLAY_A_CONTROL, (read32(INTEL_DISPLAY_A_CONTROL) 50 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) 51 | colorMode); 52 write32(INTEL_DISPLAY_B_CONTROL, (read32(INTEL_DISPLAY_B_CONTROL) 53 & ~(DISPLAY_CONTROL_COLOR_MASK | DISPLAY_CONTROL_GAMMA)) 54 | colorMode); 55 } 56 } 57 58 59 // #pragma mark - Pipe 60 61 62 Pipe::Pipe(pipe_index pipeIndex) 63 : 64 fHasTranscoder(false), 65 fFDILink(NULL), 66 fPanelFitter(NULL), 67 fPipeIndex(pipeIndex), 68 fPipeOffset(0), 69 fPlaneOffset(0) 70 { 71 switch (pipeIndex) { 72 case INTEL_PIPE_B: 73 TRACE("Pipe B.\n"); 74 fPipeOffset = 0x1000; 75 fPlaneOffset = INTEL_PLANE_OFFSET; 76 break; 77 case INTEL_PIPE_C: 78 TRACE("Pipe C.\n"); 79 fPipeOffset = 0x2000; 80 fPlaneOffset = INTEL_PLANE_OFFSET * 2; 81 break; 82 case INTEL_PIPE_D: 83 TRACE("Pipe D.\n"); 84 fPipeOffset = 0xf000; 85 //no fPlaneOffset.. 86 break; 87 default: 88 TRACE("Pipe A.\n"); 89 break; 90 } 91 92 // IvyBridge: Analog + Digital Ports behind FDI (on northbridge) 93 // Haswell: Only VGA behind FDI (on northbridge) 94 // SkyLake: FDI gone. No more northbridge video. 95 if ((gInfo->shared_info->pch_info != INTEL_PCH_NONE) && 96 (gInfo->shared_info->device_type.Generation() <= 8)) { 97 TRACE("%s: Pipe is routed through FDI\n", __func__); 98 99 // Program FDILink if PCH 100 fFDILink = new(std::nothrow) FDILink(pipeIndex); 101 } 102 if (gInfo->shared_info->pch_info != INTEL_PCH_NONE) { 103 // DDI also has transcoders 104 fHasTranscoder = true; 105 // Program gen5(+) style panelfitter as well (DDI has this as well..) 106 fPanelFitter = new(std::nothrow) PanelFitter(pipeIndex); 107 } 108 109 TRACE("Pipe Base: 0x%" B_PRIxADDR " Plane Base: 0x%" B_PRIxADDR "\n", 110 fPipeOffset, fPlaneOffset); 111 } 112 113 114 Pipe::~Pipe() 115 { 116 } 117 118 119 bool 120 Pipe::IsEnabled() 121 { 122 CALLED(); 123 124 return (read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset) 125 & INTEL_PIPE_ENABLED) != 0; 126 } 127 128 129 void 130 Pipe::Configure(display_mode* mode) 131 { 132 uint32 pipeControl = read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset); 133 134 // TODO: Haswell+ dithering changes. 135 //if (gInfo->shared_info->device_type.Generation() >= 4) { 136 // pipeControl |= (INTEL_PIPE_DITHER_EN | INTEL_PIPE_DITHER_TYPE_SP); 137 138 //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) 139 //currently using BIOS preconfigured setup 140 //pipeControl = (pipeControl & ~INTEL_PIPE_BPC_MASK) | INTEL_PIPE_BPC(INTEL_PIPE_8BPC); 141 142 // TODO: CxSR downclocking? 143 144 // TODO: Interlaced modes 145 pipeControl = (pipeControl & ~(0x7 << 21)) | INTEL_PIPE_PROGRESSIVE; 146 147 write32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset, pipeControl); 148 read32(INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset); 149 150 if (gInfo->shared_info->device_type.Generation() >= 6) { 151 // According to SandyBridge modesetting sequence, pipe must be enabled 152 // before PLL are configured. 153 addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset; 154 write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED); 155 } 156 } 157 158 159 void 160 Pipe::_ConfigureTranscoder(display_mode* target) 161 { 162 CALLED(); 163 164 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR"\n", __func__, fPipeOffset); 165 166 if (gInfo->shared_info->device_type.Generation() < 9) { 167 // update timing (fPipeOffset bumps the DISPLAY_A to B when needed) 168 write32(INTEL_TRANSCODER_A_HTOTAL + fPipeOffset, 169 ((uint32)(target->timing.h_total - 1) << 16) 170 | ((uint32)target->timing.h_display - 1)); 171 write32(INTEL_TRANSCODER_A_HBLANK + fPipeOffset, 172 ((uint32)(target->timing.h_total - 1) << 16) 173 | ((uint32)target->timing.h_display - 1)); 174 write32(INTEL_TRANSCODER_A_HSYNC + fPipeOffset, 175 ((uint32)(target->timing.h_sync_end - 1) << 16) 176 | ((uint32)target->timing.h_sync_start - 1)); 177 178 write32(INTEL_TRANSCODER_A_VTOTAL + fPipeOffset, 179 ((uint32)(target->timing.v_total - 1) << 16) 180 | ((uint32)target->timing.v_display - 1)); 181 write32(INTEL_TRANSCODER_A_VBLANK + fPipeOffset, 182 ((uint32)(target->timing.v_total - 1) << 16) 183 | ((uint32)target->timing.v_display - 1)); 184 write32(INTEL_TRANSCODER_A_VSYNC + fPipeOffset, 185 ((uint32)(target->timing.v_sync_end - 1) << 16) 186 | ((uint32)target->timing.v_sync_start - 1)); 187 188 #if 0 189 // XXX: Is it ok to do these on non-digital? 190 write32(INTEL_TRANSCODER_A_POS + fPipeOffset, 0); 191 write32(INTEL_TRANSCODER_A_IMAGE_SIZE + fPipeOffset, 192 ((uint32)(target->timing.h_display - 1) << 16) 193 | ((uint32)target->timing.v_display - 1)); 194 #endif 195 } else { 196 // on Skylake and later, timing is already done in ConfigureTimings() 197 } 198 } 199 200 201 uint32 202 Pipe::TranscoderMode() 203 { 204 if (gInfo->shared_info->device_type.Generation() < 9) { 205 ERROR("%s: Don't know how to get transcoder mode on older generations\n", __func__); 206 return 0; 207 } 208 209 TRACE("%s: trans conf reg: 0x%" B_PRIx32 "\n", __func__, 210 read32(DDI_SKL_TRANS_CONF_A + fPipeOffset)); 211 TRACE("%s: trans DDI func ctl reg: 0x%" B_PRIx32 "\n", __func__, 212 read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset)); 213 uint32 value = (read32(PIPE_DDI_FUNC_CTL_A + fPipeOffset) & PIPE_DDI_MODESEL_MASK) 214 >> PIPE_DDI_MODESEL_SHIFT; 215 switch (value) { 216 case PIPE_DDI_MODE_DVI: 217 TRACE("%s: Transcoder uses DVI mode\n", __func__); 218 break; 219 case PIPE_DDI_MODE_DP_SST: 220 TRACE("%s: Transcoder uses DP SST mode\n", __func__); 221 break; 222 case PIPE_DDI_MODE_DP_MST: 223 TRACE("%s: Transcoder uses DP MST mode\n", __func__); 224 break; 225 default: 226 TRACE("%s: Transcoder uses HDMI mode\n", __func__); 227 break; 228 } 229 return value; 230 } 231 232 233 status_t 234 Pipe::SetFDILink(const display_timing& timing, uint32 linkBandwidth, uint32 lanes, uint32 bitsPerPixel) 235 { 236 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset); 237 TRACE("%s: FDI/PIPE link reference clock is %gMhz\n", __func__, linkBandwidth / 1000.0f); 238 TRACE("%s: FDI/PIPE M1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset)); 239 TRACE("%s: FDI/PIPE N1 data before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset)); 240 TRACE("%s: FDI/PIPE M1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset)); 241 TRACE("%s: FDI/PIPE N1 link before: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset)); 242 243 if ((bitsPerPixel < 18) || (bitsPerPixel > 36)) { 244 ERROR("%s: FDI/PIPE illegal colordepth set.\n", __func__); 245 return B_ERROR; 246 } 247 TRACE("%s: FDI/PIPE link colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); 248 249 if (lanes > 4) { 250 ERROR("%s: FDI/PIPE illegal number of lanes set.\n", __func__); 251 return B_ERROR; 252 } 253 TRACE("%s: FDI/PIPE link with %" B_PRIx32 " lane(s) in use\n", __func__, lanes); 254 255 //Setup Data M/N 256 uint64 linkspeed = lanes * linkBandwidth * 8; 257 uint64 ret_n = 1; 258 while(ret_n < linkspeed) { 259 ret_n *= 2; 260 } 261 if (ret_n > 0x800000) { 262 ret_n = 0x800000; 263 } 264 uint64 ret_m = timing.pixel_clock * ret_n * bitsPerPixel / linkspeed; 265 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { 266 ret_m >>= 1; 267 ret_n >>= 1; 268 } 269 //Set TU size bits (to default, max) before link training so that error detection works 270 write32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset, ret_m | FDI_PIPE_MN_TU_SIZE_MASK); 271 write32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset, ret_n); 272 273 //Setup Link M/N 274 linkspeed = linkBandwidth; 275 ret_n = 1; 276 while(ret_n < linkspeed) { 277 ret_n *= 2; 278 } 279 if (ret_n > 0x800000) { 280 ret_n = 0x800000; 281 } 282 ret_m = timing.pixel_clock * ret_n / linkspeed; 283 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { 284 ret_m >>= 1; 285 ret_n >>= 1; 286 } 287 write32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset, ret_m); 288 //Writing Link N triggers all four registers to be activated also (on next VBlank) 289 write32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset, ret_n); 290 291 TRACE("%s: FDI/PIPE M1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_M1 + fPipeOffset)); 292 TRACE("%s: FDI/PIPE N1 data after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_DATA_N1 + fPipeOffset)); 293 TRACE("%s: FDI/PIPE M1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_M1 + fPipeOffset)); 294 TRACE("%s: FDI/PIPE N1 link after: 0x%" B_PRIx32 "\n", __func__, read32(PCH_FDI_PIPE_A_LINK_N1 + fPipeOffset)); 295 296 return B_OK; 297 } 298 299 300 void 301 Pipe::ConfigureScalePos(display_mode* target) 302 { 303 CALLED(); 304 305 TRACE("%s: fPipeOffset: 0x%" B_PRIxADDR "\n", __func__, fPipeOffset); 306 307 if (target == NULL) { 308 ERROR("%s: Invalid display mode!\n", __func__); 309 return; 310 } 311 312 if (gInfo->shared_info->device_type.Generation() < 6) { 313 // FIXME check on which generations this register exists 314 // (it appears it would be available only for cursor planes, not 315 // display planes) 316 // Since we set the plane to be the same size as the display, we can 317 // just show it starting at top-left. 318 write32(INTEL_DISPLAY_A_POS + fPipeOffset, 0); 319 } 320 321 // The only thing that really matters: set the image size and let the 322 // panel fitter or the transcoder worry about the rest 323 write32(INTEL_DISPLAY_A_PIPE_SIZE + fPipeOffset, 324 ((uint32)(target->timing.h_display - 1) << 16) 325 | ((uint32)target->timing.v_display - 1)); 326 327 // Set the plane size as well while we're at it (this is independant, we 328 // could have a larger plane and scroll through it). 329 if ((gInfo->shared_info->device_type.Generation() <= 4) 330 || gInfo->shared_info->device_type.HasDDI()) { 331 // This is "reserved" on G35 and GMA965, but needed on 945 (for which 332 // there is no public documentation), and I assume earlier devices as 333 // well. 334 // 335 // IMPORTANT WARNING: height and width are swapped when compared to the other registers! 336 // Be careful when editing this code and don't accidentally swap them! 337 write32(INTEL_DISPLAY_A_IMAGE_SIZE + fPipeOffset, 338 ((uint32)(target->timing.v_display - 1) << 16) 339 | ((uint32)target->timing.h_display - 1)); 340 } 341 } 342 343 344 void 345 Pipe::ConfigureTimings(display_mode* target, bool hardware, port_index portIndex) 346 { 347 CALLED(); 348 349 TRACE("%s(%d): fPipeOffset: 0x%" B_PRIxADDR"\n", __func__, hardware, 350 fPipeOffset); 351 352 if (target == NULL) { 353 ERROR("%s: Invalid display mode!\n", __func__); 354 return; 355 } 356 357 /* If using the transcoder, leave the display at its native resolution, 358 * and configure only the transcoder (panel fitting will match them 359 * together). */ 360 if (!fHasTranscoder || hardware) 361 { 362 // update timing (fPipeOffset bumps the DISPLAY_A to B when needed) 363 // Note: on Skylake below registers are part of the transcoder 364 write32(INTEL_DISPLAY_A_HTOTAL + fPipeOffset, 365 ((uint32)(target->timing.h_total - 1) << 16) 366 | ((uint32)target->timing.h_display - 1)); 367 write32(INTEL_DISPLAY_A_HBLANK + fPipeOffset, 368 ((uint32)(target->timing.h_total - 1) << 16) 369 | ((uint32)target->timing.h_display - 1)); 370 write32(INTEL_DISPLAY_A_HSYNC + fPipeOffset, 371 ((uint32)(target->timing.h_sync_end - 1) << 16) 372 | ((uint32)target->timing.h_sync_start - 1)); 373 374 write32(INTEL_DISPLAY_A_VTOTAL + fPipeOffset, 375 ((uint32)(target->timing.v_total - 1) << 16) 376 | ((uint32)target->timing.v_display - 1)); 377 write32(INTEL_DISPLAY_A_VBLANK + fPipeOffset, 378 ((uint32)(target->timing.v_total - 1) << 16) 379 | ((uint32)target->timing.v_display - 1)); 380 write32(INTEL_DISPLAY_A_VSYNC + fPipeOffset, 381 ((uint32)(target->timing.v_sync_end - 1) << 16) 382 | ((uint32)target->timing.v_sync_start - 1)); 383 } 384 385 ConfigureScalePos(target); 386 387 // transcoder is not applicable if eDP is targeted on Sandy- and IvyBridge 388 if ((gInfo->shared_info->device_type.InGroup(INTEL_GROUP_SNB) || 389 gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) && 390 (portIndex == INTEL_PORT_A)) { 391 return; 392 } 393 394 if (fHasTranscoder && hardware) { 395 _ConfigureTranscoder(target); 396 } 397 } 398 399 400 void 401 Pipe::ConfigureClocks(const pll_divisors& divisors, uint32 pixelClock, 402 uint32 extraFlags) 403 { 404 CALLED(); 405 406 addr_t pllDivisorA = INTEL_DISPLAY_A_PLL_DIVISOR_0; 407 addr_t pllDivisorB = INTEL_DISPLAY_A_PLL_DIVISOR_1; 408 addr_t pllControl = INTEL_DISPLAY_A_PLL; 409 addr_t pllMD = INTEL_DISPLAY_A_PLL_MD; 410 411 if (fPipeIndex == INTEL_PIPE_B) { 412 pllDivisorA = INTEL_DISPLAY_B_PLL_DIVISOR_0; 413 pllDivisorB = INTEL_DISPLAY_B_PLL_DIVISOR_1; 414 pllControl = INTEL_DISPLAY_B_PLL; 415 pllMD = INTEL_DISPLAY_B_PLL_MD; 416 } 417 418 // Disable DPLL first 419 write32(pllControl, read32(pllControl) & ~DISPLAY_PLL_ENABLED); 420 spin(150); 421 422 float refFreq = gInfo->shared_info->pll_info.reference_frequency / 1000.0f; 423 424 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) { 425 float adjusted = ((refFreq * divisors.m) / divisors.n) / divisors.p; 426 uint32 pixelMultiply = uint32(adjusted / (pixelClock / 1000.0f)); 427 write32(pllMD, (0 << 24) | ((pixelMultiply - 1) << 8)); 428 } 429 430 // XXX: For now we assume no LVDS downclocking and program the same divisor 431 // value to both divisor 0 (standard) and 1 (reduced divisor) 432 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 433 write32(pllDivisorA, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) 434 & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 435 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 436 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); 437 write32(pllDivisorB, (((1 << divisors.n) << DISPLAY_PLL_N_DIVISOR_SHIFT) 438 & DISPLAY_PLL_IGD_N_DIVISOR_MASK) 439 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 440 & DISPLAY_PLL_IGD_M2_DIVISOR_MASK)); 441 } else { 442 write32(pllDivisorA, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) 443 & DISPLAY_PLL_N_DIVISOR_MASK) 444 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) 445 & DISPLAY_PLL_M1_DIVISOR_MASK) 446 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 447 & DISPLAY_PLL_M2_DIVISOR_MASK)); 448 write32(pllDivisorB, (((divisors.n - 2) << DISPLAY_PLL_N_DIVISOR_SHIFT) 449 & DISPLAY_PLL_N_DIVISOR_MASK) 450 | (((divisors.m1 - 2) << DISPLAY_PLL_M1_DIVISOR_SHIFT) 451 & DISPLAY_PLL_M1_DIVISOR_MASK) 452 | (((divisors.m2 - 2) << DISPLAY_PLL_M2_DIVISOR_SHIFT) 453 & DISPLAY_PLL_M2_DIVISOR_MASK)); 454 } 455 456 //note: bit DISPLAY_PLL_NO_VGA_CONTROL does not exist on IvyBridge and should be left 457 // zero there. It does not influence it though. 458 uint32 pll = DISPLAY_PLL_ENABLED | DISPLAY_PLL_NO_VGA_CONTROL | extraFlags; 459 460 if (gInfo->shared_info->device_type.Generation() >= 3) { 461 // p1 divisor << 1 , 1-8 462 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_PIN)) { 463 pll |= ((1 << (divisors.p1 - 1)) 464 << DISPLAY_PLL_IGD_POST1_DIVISOR_SHIFT) 465 & DISPLAY_PLL_IGD_POST1_DIVISOR_MASK; 466 } else { 467 pll |= ((1 << (divisors.p1 - 1)) 468 << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 469 & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; 470 // pll |= ((divisors.p1 - 1) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 471 // & DISPLAY_PLL_9xx_POST1_DIVISOR_MASK; 472 } 473 474 // Also configure the FP0 divisor on SandyBridge 475 if (gInfo->shared_info->device_type.Generation() == 6) { 476 pll |= ((1 << (divisors.p1 - 1)) 477 << DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_SHIFT) 478 & DISPLAY_PLL_SNB_FP0_POST1_DIVISOR_MASK; 479 } 480 481 if (divisors.p2 == 5 || divisors.p2 == 7) 482 pll |= DISPLAY_PLL_DIVIDE_HIGH; 483 484 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_96x)) 485 pll |= 6 << DISPLAY_PLL_PULSE_PHASE_SHIFT; 486 } else { 487 if (divisors.p2 != 5 && divisors.p2 != 7) 488 pll |= DISPLAY_PLL_DIVIDE_4X; 489 490 pll |= DISPLAY_PLL_2X_CLOCK; 491 492 // TODO: Is this supposed to be DISPLAY_PLL_IGD_POST1_DIVISOR_MASK?? 493 if (divisors.p1 > 2) { 494 pll |= ((divisors.p1 - 2) << DISPLAY_PLL_POST1_DIVISOR_SHIFT) 495 & DISPLAY_PLL_POST1_DIVISOR_MASK; 496 } else 497 pll |= DISPLAY_PLL_POST1_DIVIDE_2; 498 } 499 500 // Configure PLL while -keeping- it disabled 501 //note: on older chipsets DISPLAY_PLL_NO_VGA_CONTROL probably enables the PLL and locks regs; 502 // on newer chipsets DISPLAY_PLL_ENABLED does this. 503 write32(pllControl, pll & ~DISPLAY_PLL_ENABLED & ~DISPLAY_PLL_NO_VGA_CONTROL); 504 read32(pllControl); 505 spin(150); 506 507 // enable pre-configured PLL (locks PLL settings directly blocking changes in this write even) 508 write32(pllControl, pll); 509 read32(pllControl); 510 511 // Allow the PLL to warm up. 512 spin(150); 513 514 if (gInfo->shared_info->device_type.Generation() >= 6) { 515 // SandyBridge has 3 transcoders, but only 2 PLLs. So there is a new 516 // register which routes the PLL output to the transcoder that we need 517 // to configure 518 uint32 pllSel = read32(SNB_DPLL_SEL); 519 TRACE("Old PLL selection: 0x%" B_PRIx32 "\n", pllSel); 520 uint32 shift = 0; 521 uint32 pllIndex = 0; 522 523 // FIXME we assume that pipe A is used with transcoder A, and pipe B 524 // with transcoder B, that may not always be the case 525 if (fPipeIndex == INTEL_PIPE_A) { 526 shift = 0; 527 pllIndex = 0; 528 TRACE("Route PLL A to transcoder A\n"); 529 } else if (fPipeIndex == INTEL_PIPE_B) { 530 shift = 4; 531 pllIndex = 1; 532 TRACE("Route PLL B to transcoder B\n"); 533 } else { 534 ERROR("Attempting to configure PLL for unhandled pipe"); 535 return; 536 } 537 538 // Mask out the previous PLL configuration for this transcoder 539 pllSel &= ~(0xF << shift); 540 541 // Set up the new configuration for this transcoder and enable it 542 pllSel |= (8 | pllIndex) << shift; 543 544 TRACE("New PLL selection: 0x%" B_PRIx32 "\n", pllSel); 545 write32(SNB_DPLL_SEL, pllSel); 546 } 547 } 548 549 void 550 Pipe::ConfigureClocksSKL(const skl_wrpll_params& wrpll_params, uint32 pixelClock, 551 port_index pllForPort, uint32* pllSel) 552 { 553 CALLED(); 554 555 //find our PLL as set by the BIOS 556 uint32 portSel = read32(SKL_DPLL_CTRL2); 557 *pllSel = 0xff; 558 switch (pllForPort) { 559 case INTEL_PORT_A: 560 *pllSel = (portSel & 0x0006) >> 1; 561 break; 562 case INTEL_PORT_B: 563 *pllSel = (portSel & 0x0030) >> 4; 564 break; 565 case INTEL_PORT_C: 566 *pllSel = (portSel & 0x0180) >> 7; 567 break; 568 case INTEL_PORT_D: 569 *pllSel = (portSel & 0x0c00) >> 10; 570 break; 571 case INTEL_PORT_E: 572 *pllSel = (portSel & 0x6000) >> 13; 573 break; 574 default: 575 TRACE("No port selected!\n"); 576 return; 577 } 578 TRACE("PLL selected is %" B_PRIx32 "\n", *pllSel); 579 580 TRACE("Skylake DPLL_CFGCR1 0x%" B_PRIx32 "\n", 581 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8)); 582 TRACE("Skylake DPLL_CFGCR2 0x%" B_PRIx32 "\n", 583 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8)); 584 585 // only program PLL's that are in non-DP mode (otherwise the linkspeed sets refresh) 586 portSel = read32(SKL_DPLL_CTRL1); 587 if ((portSel & (1 << (*pllSel * 6 + 5))) && *pllSel) { // DPLL0 might only know DP mode 588 // enable pgm on our PLL in case that's currently disabled 589 write32(SKL_DPLL_CTRL1, portSel | (1 << (*pllSel * 6))); 590 591 write32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8, 592 1 << 31 | 593 wrpll_params.dco_fraction << 9 | 594 wrpll_params.dco_integer); 595 write32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8, 596 wrpll_params.qdiv_ratio << 8 | 597 wrpll_params.qdiv_mode << 7 | 598 wrpll_params.kdiv << 5 | 599 wrpll_params.pdiv << 2 | 600 wrpll_params.central_freq); 601 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8); 602 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8); 603 604 //assuming DPLL0 and 1 are already enabled by the BIOS if in use (LCPLL1,2 regs) 605 606 spin(5); 607 if (read32(SKL_DPLL_STATUS) & (1 << (*pllSel * 8))) { 608 TRACE("Programmed PLL; PLL is locked\n"); 609 } else { 610 TRACE("Programmed PLL; PLL did not lock\n"); 611 } 612 TRACE("Skylake DPLL_CFGCR1 now: 0x%" B_PRIx32 "\n", 613 read32(SKL_DPLL1_CFGCR1 + (*pllSel - 1) * 8)); 614 TRACE("Skylake DPLL_CFGCR2 now: 0x%" B_PRIx32 "\n", 615 read32(SKL_DPLL1_CFGCR2 + (*pllSel - 1) * 8)); 616 } else { 617 TRACE("PLL programming not needed, skipping.\n"); 618 } 619 620 TRACE("Skylake DPLL_CTRL1: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL1)); 621 TRACE("Skylake DPLL_CTRL2: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_CTRL2)); 622 TRACE("Skylake DPLL_STATUS: 0x%" B_PRIx32 "\n", read32(SKL_DPLL_STATUS)); 623 } 624 625 void 626 Pipe::Enable(bool enable) 627 { 628 CALLED(); 629 630 addr_t pipeReg = INTEL_DISPLAY_A_PIPE_CONTROL + fPipeOffset; 631 addr_t planeReg = INTEL_DISPLAY_A_CONTROL + fPlaneOffset; 632 633 // Planes always have to operate on an enabled pipe 634 635 if (enable) { 636 write32(pipeReg, read32(pipeReg) | INTEL_PIPE_ENABLED); 637 wait_for_vblank(); 638 write32(planeReg, read32(planeReg) | DISPLAY_CONTROL_ENABLED); 639 640 //Enable default display main watermarks 641 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 642 if (fPipeOffset == 0) 643 write32(INTEL_DISPLAY_A_PIPE_WATERMARK, 0x0783818); 644 else 645 write32(INTEL_DISPLAY_B_PIPE_WATERMARK, 0x0783818); 646 } 647 } else { 648 write32(planeReg, read32(planeReg) & ~DISPLAY_CONTROL_ENABLED); 649 wait_for_vblank(); 650 //Sandy+: when link training is to be done re-enable this line but otherwise don't touch! 651 //GMA(Q45): must disable PIPE or DPLL programming fails. 652 if (gInfo->shared_info->device_type.Generation() <= 5) { 653 write32(pipeReg, read32(pipeReg) & ~INTEL_PIPE_ENABLED); 654 } 655 } 656 657 // flush the eventually cached PCI bus writes 658 read32(INTEL_DISPLAY_A_BASE); 659 } 660