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