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 10 11 #include "FlexibleDisplayInterface.h" 12 13 #include <stdlib.h> 14 #include <string.h> 15 #include <Debug.h> 16 #include <KernelExport.h> 17 18 #include "accelerant.h" 19 #include "intel_extreme.h" 20 21 22 #undef TRACE 23 #define TRACE_FDI 24 #ifdef TRACE_FDI 25 # define TRACE(x...) _sPrintf("intel_extreme: " x) 26 #else 27 # define TRACE(x...) 28 #endif 29 30 #define ERROR(x...) _sPrintf("intel_extreme: " x) 31 #define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) 32 33 34 static const int gSnbBFDITrainParam[] = { 35 FDI_LINK_TRAIN_400MV_0DB_SNB_B, 36 FDI_LINK_TRAIN_400MV_6DB_SNB_B, 37 FDI_LINK_TRAIN_600MV_3_5DB_SNB_B, 38 FDI_LINK_TRAIN_800MV_0DB_SNB_B, 39 }; 40 41 42 // #pragma mark - FDITransmitter 43 44 45 FDITransmitter::FDITransmitter(pipe_index pipeIndex) 46 : 47 fRegisterBase(PCH_FDI_TX_BASE_REGISTER) 48 { 49 if (pipeIndex == INTEL_PIPE_B) 50 fRegisterBase += PCH_FDI_TX_PIPE_OFFSET * 1; 51 } 52 53 54 FDITransmitter::~FDITransmitter() 55 { 56 } 57 58 59 void 60 FDITransmitter::Enable() 61 { 62 CALLED(); 63 uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; 64 uint32 value = read32(targetRegister); 65 66 write32(targetRegister, value | FDI_TX_ENABLE); 67 read32(targetRegister); 68 spin(150); 69 } 70 71 72 void 73 FDITransmitter::Disable() 74 { 75 CALLED(); 76 uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; 77 uint32 value = read32(targetRegister); 78 79 write32(targetRegister, value & ~FDI_TX_ENABLE); 80 read32(targetRegister); 81 spin(150); 82 } 83 84 85 bool 86 FDITransmitter::IsPLLEnabled() 87 { 88 CALLED(); 89 return (read32(fRegisterBase + PCH_FDI_TX_CONTROL) & FDI_TX_PLL_ENABLED) 90 != 0; 91 } 92 93 94 void 95 FDITransmitter::EnablePLL(uint32 lanes) 96 { 97 CALLED(); 98 uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; 99 uint32 value = read32(targetRegister); 100 if ((value & FDI_TX_PLL_ENABLED) != 0) { 101 // already enabled, possibly IronLake where it always is 102 TRACE("%s: Already enabled.\n", __func__); 103 return; 104 } 105 106 value &= ~FDI_DP_PORT_WIDTH_MASK; 107 value |= FDI_DP_PORT_WIDTH(lanes); 108 109 //first update config, -then- enable PLL to be sure config is indeed updated 110 write32(targetRegister, value); 111 read32(targetRegister); 112 113 write32(targetRegister, value | FDI_TX_PLL_ENABLED); 114 read32(targetRegister); 115 spin(100); // warmup 10us + dmi delay 20us, be generous 116 } 117 118 119 void 120 FDITransmitter::DisablePLL() 121 { 122 CALLED(); 123 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_ILK)) { 124 // on IronLake the FDI PLL is alaways enabled, so no point in trying... 125 return; 126 } 127 128 uint32 targetRegister = fRegisterBase + PCH_FDI_TX_CONTROL; 129 write32(targetRegister, read32(targetRegister) & ~FDI_TX_PLL_ENABLED); 130 read32(targetRegister); 131 spin(100); 132 } 133 134 135 // #pragma mark - FDIReceiver 136 137 138 FDIReceiver::FDIReceiver(pipe_index pipeIndex) 139 : 140 fRegisterBase(PCH_FDI_RX_BASE_REGISTER) 141 { 142 if (pipeIndex == INTEL_PIPE_B) 143 fRegisterBase += PCH_FDI_RX_PIPE_OFFSET * 1; 144 } 145 146 147 FDIReceiver::~FDIReceiver() 148 { 149 } 150 151 152 void 153 FDIReceiver::Enable() 154 { 155 CALLED(); 156 uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; 157 uint32 value = read32(targetRegister); 158 159 write32(targetRegister, value | FDI_RX_ENABLE); 160 read32(targetRegister); 161 spin(150); 162 } 163 164 165 void 166 FDIReceiver::Disable() 167 { 168 CALLED(); 169 uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; 170 uint32 value = read32(targetRegister); 171 172 write32(targetRegister, value & ~FDI_RX_ENABLE); 173 read32(targetRegister); 174 spin(150); 175 } 176 177 178 bool 179 FDIReceiver::IsPLLEnabled() 180 { 181 CALLED(); 182 return (read32(fRegisterBase + PCH_FDI_RX_CONTROL) & FDI_RX_PLL_ENABLED) 183 != 0; 184 } 185 186 187 void 188 FDIReceiver::EnablePLL(uint32 lanes) 189 { 190 CALLED(); 191 uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; 192 uint32 value = read32(targetRegister); 193 if ((value & FDI_RX_PLL_ENABLED) != 0) { 194 // already enabled, possibly IronLake where it always is 195 TRACE("%s: Already enabled.\n", __func__); 196 return; 197 } 198 199 //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) 200 //currently using BIOS preconfigured setup 201 //value &= ~FDI_DP_PORT_WIDTH_MASK; 202 //value |= FDI_RX_LINK_BPC(INTEL_PIPE_8BPC); 203 204 value &= ~FDI_DP_PORT_WIDTH_MASK; 205 value |= FDI_DP_PORT_WIDTH(lanes); 206 207 //first update config, -then- enable PLL to be sure config is indeed updated 208 write32(targetRegister, value); 209 read32(targetRegister); 210 211 write32(targetRegister, value | FDI_RX_PLL_ENABLED); 212 read32(targetRegister); 213 spin(200); // warmup 10us + dmi delay 20us, be generous 214 } 215 216 217 void 218 FDIReceiver::DisablePLL() 219 { 220 CALLED(); 221 uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; 222 write32(targetRegister, read32(targetRegister) & ~FDI_RX_PLL_ENABLED); 223 read32(targetRegister); 224 spin(100); 225 } 226 227 228 void 229 FDIReceiver::SwitchClock(bool toPCDClock) 230 { 231 CALLED(); 232 uint32 targetRegister = fRegisterBase + PCH_FDI_RX_CONTROL; 233 write32(targetRegister, (read32(targetRegister) & ~FDI_RX_CLOCK_MASK) 234 | (toPCDClock ? FDI_RX_CLOCK_PCD : FDI_RX_CLOCK_RAW)); 235 read32(targetRegister); 236 spin(200); 237 } 238 239 240 // #pragma mark - FDILink 241 242 243 FDILink::FDILink(pipe_index pipeIndex) 244 : 245 fTransmitter(pipeIndex), 246 fReceiver(pipeIndex), 247 fPipeIndex(pipeIndex) 248 { 249 } 250 251 252 status_t 253 FDILink::Train(display_mode* target) 254 { 255 CALLED(); 256 257 status_t result = B_OK; 258 259 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 260 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 261 262 //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) 263 uint32 bitsPerPixel = ((read32(rxControl) & FDI_RX_LINK_BPC_MASK) >> FDI_RX_LINK_COLOR_SHIFT); 264 switch (bitsPerPixel) { 265 case INTEL_PIPE_8BPC: 266 bitsPerPixel = 24; 267 break; 268 case INTEL_PIPE_10BPC: 269 bitsPerPixel = 30; 270 break; 271 case INTEL_PIPE_6BPC: 272 bitsPerPixel = 18; 273 break; 274 case INTEL_PIPE_12BPC: 275 bitsPerPixel = 36; 276 break; 277 default: 278 ERROR("%s: FDI illegal link colordepth set.\n", __func__); 279 return B_ERROR; 280 } 281 TRACE("%s: FDI Link %s:\n", __func__, (fPipeIndex == INTEL_PIPE_A) ? "A" : "B"); 282 TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, bitsPerPixel); 283 284 // Khz / 10. ( each output octet encoded as 10 bits. 285 uint32 linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; 286 //Reserving 5% bandwidth for possible spread spectrum clock use 287 uint32 bps = target->timing.pixel_clock * bitsPerPixel * 21 / 20; 288 289 //use DIV_ROUND_UP: 290 uint32 lanes = (bps + (linkBandwidth * 8) - 1) / (linkBandwidth * 8); 291 //remove below line when link training is to be done 292 lanes = ((read32(txControl) & FDI_DP_PORT_WIDTH_MASK) >> FDI_DP_PORT_WIDTH_SHIFT) + 1; 293 294 TRACE("%s: FDI Link Lanes: %" B_PRIu32 "\n", __func__, lanes); 295 //assuming we'll only use link A and B (not C) 296 if (lanes > 4) { 297 result = B_ERROR; 298 } 299 if (result != B_OK) { 300 ERROR("%s: FDI not enough lanes in hardware.\n", __func__); 301 return result; 302 } 303 304 TRACE("%s: FDI TX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); 305 TRACE("%s: FDI RX ctrl: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); 306 307 #if 0 308 //when link training is to be done re-enable this code 309 310 //The order of handling things is important here.. 311 write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); 312 read32(txControl); 313 write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); 314 read32(rxControl); 315 316 write32(txControl, (read32(txControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); 317 read32(txControl); 318 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 319 write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_PATTERN_MASK_CPT) | FDI_LINK_TRAIN_PATTERN_1_CPT); 320 } else { 321 write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); 322 } 323 read32(rxControl); 324 spin(100); 325 326 // Disable FDI clocks 327 Receiver().SwitchClock(false); 328 Transmitter().DisablePLL(); 329 Receiver().DisablePLL(); 330 #endif 331 332 //Setup Data M/N 333 uint64 linkspeed = lanes * linkBandwidth * 8; 334 uint64 ret_n = 1; 335 while(ret_n < linkspeed) { 336 ret_n *= 2; 337 } 338 if (ret_n > 0x800000) { 339 ret_n = 0x800000; 340 } 341 uint64 ret_m = target->timing.pixel_clock * ret_n * bitsPerPixel / linkspeed; 342 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { 343 ret_m >>= 1; 344 ret_n >>= 1; 345 } 346 //Set TU size bits (to default, max) before link training so that error detection works 347 write32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1, ret_m | FDI_PIPE_MN_TU_SIZE_MASK); 348 write32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1, ret_n); 349 350 //Setup Link M/N 351 linkspeed = linkBandwidth; 352 ret_n = 1; 353 while(ret_n < linkspeed) { 354 ret_n *= 2; 355 } 356 if (ret_n > 0x800000) { 357 ret_n = 0x800000; 358 } 359 ret_m = target->timing.pixel_clock * ret_n / linkspeed; 360 while ((ret_n > 0xffffff) || (ret_m > 0xffffff)) { 361 ret_m >>= 1; 362 ret_n >>= 1; 363 } 364 write32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1, ret_m); 365 //Writing Link N triggers all four registers to be activated also (on next VBlank) 366 write32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1, ret_n); 367 368 TRACE("%s: FDI data M1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_M1)); 369 TRACE("%s: FDI data N1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_DATA_N1)); 370 TRACE("%s: FDI link M1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_M1)); 371 TRACE("%s: FDI link N1: 0x%" B_PRIx32 "\n", __func__, read32(Transmitter().Base() + PCH_FDI_PIPE_A_LINK_N1)); 372 373 //Set receiving end TU size bits to match sending end's setting 374 write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_1, FDI_RX_TRANS_UNIT_MASK); 375 write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_2, FDI_RX_TRANS_UNIT_MASK); 376 377 #if 0 378 //when link training is to be done re-enable this code 379 // Enable FDI clocks 380 Receiver().EnablePLL(lanes); 381 Receiver().SwitchClock(true); 382 Transmitter().EnablePLL(lanes); 383 384 // TODO: Only _AutoTrain on IVYB Stepping B or later 385 // otherwise, _ManualTrain 386 if (gInfo->shared_info->device_type.Generation() >= 7) 387 result = _AutoTrain(lanes); 388 else if (gInfo->shared_info->device_type.Generation() == 6) 389 result = _SnbTrain(lanes); 390 else if (gInfo->shared_info->device_type.Generation() == 5) 391 result = _IlkTrain(lanes); 392 else 393 result = _NormalTrain(lanes); 394 #endif 395 396 if (result != B_OK) { 397 ERROR("%s: FDI training fault.\n", __func__); 398 } 399 400 return result; 401 } 402 403 404 status_t 405 FDILink::_NormalTrain(uint32 lanes) 406 { 407 CALLED(); 408 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 409 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 410 411 // Enable normal link training 412 uint32 tmp = read32(txControl); 413 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 414 tmp &= ~FDI_LINK_TRAIN_NONE_IVB; 415 tmp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE; 416 } else { 417 tmp &= ~FDI_LINK_TRAIN_NONE; 418 tmp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; 419 } 420 write32(txControl, tmp); 421 422 tmp = read32(rxControl); 423 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 424 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 425 tmp |= FDI_LINK_TRAIN_NORMAL_CPT; 426 } else { 427 tmp &= ~FDI_LINK_TRAIN_NONE; 428 tmp |= FDI_LINK_TRAIN_NONE; 429 } 430 write32(rxControl, tmp | FDI_RX_ENHANCE_FRAME_ENABLE); 431 432 // Wait 1x idle pattern 433 read32(rxControl); 434 spin(1000); 435 436 // Enable ecc on IVB 437 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 438 write32(rxControl, read32(rxControl) 439 | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); 440 read32(rxControl); 441 } 442 443 return B_OK; 444 } 445 446 447 status_t 448 FDILink::_IlkTrain(uint32 lanes) 449 { 450 CALLED(); 451 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 452 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 453 454 // Train 1: unmask FDI RX Interrupt symbol_lock and bit_lock 455 uint32 tmp = read32(Receiver().Base() + PCH_FDI_RX_IMR); 456 tmp &= ~FDI_RX_SYMBOL_LOCK; 457 tmp &= ~FDI_RX_BIT_LOCK; 458 write32(Receiver().Base() + PCH_FDI_RX_IMR, tmp); 459 spin(150); 460 461 // Enable CPU FDI TX and RX 462 tmp = read32(txControl); 463 tmp &= ~FDI_DP_PORT_WIDTH_MASK; 464 tmp |= FDI_DP_PORT_WIDTH(lanes); 465 tmp &= ~FDI_LINK_TRAIN_NONE; 466 tmp |= FDI_LINK_TRAIN_PATTERN_1; 467 write32(txControl, tmp); 468 Transmitter().Enable(); 469 470 tmp = read32(rxControl); 471 tmp &= ~FDI_LINK_TRAIN_NONE; 472 tmp |= FDI_LINK_TRAIN_PATTERN_1; 473 write32(rxControl, tmp); 474 Receiver().Enable(); 475 476 // ILK Workaround, enable clk after FDI enable 477 if (fPipeIndex == INTEL_PIPE_B) { 478 write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); 479 write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR 480 | FDI_RX_PHASE_SYNC_POINTER_EN); 481 } else { 482 write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); 483 write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR 484 | FDI_RX_PHASE_SYNC_POINTER_EN); 485 } 486 487 uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; 488 TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); 489 490 int tries = 0; 491 for (tries = 0; tries < 5; tries++) { 492 tmp = read32(iirControl); 493 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 494 495 if ((tmp & FDI_RX_BIT_LOCK)) { 496 TRACE("%s: FDI train 1 done\n", __func__); 497 write32(iirControl, tmp | FDI_RX_BIT_LOCK); 498 break; 499 } 500 } 501 502 if (tries == 5) { 503 ERROR("%s: FDI train 1 failure!\n", __func__); 504 return B_ERROR; 505 } 506 507 // Train 2 508 tmp = read32(txControl); 509 tmp &= ~FDI_LINK_TRAIN_NONE; 510 tmp |= FDI_LINK_TRAIN_PATTERN_2; 511 write32(txControl, tmp); 512 513 tmp = read32(rxControl); 514 tmp &= ~FDI_LINK_TRAIN_NONE; 515 tmp |= FDI_LINK_TRAIN_PATTERN_2; 516 write32(rxControl, tmp); 517 518 read32(rxControl); 519 spin(150); 520 521 for (tries = 0; tries < 5; tries++) { 522 tmp = read32(iirControl); 523 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 524 525 if (tmp & FDI_RX_SYMBOL_LOCK) { 526 TRACE("%s: FDI train 2 done\n", __func__); 527 write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); 528 break; 529 } 530 } 531 532 if (tries == 5) { 533 ERROR("%s: FDI train 2 failure!\n", __func__); 534 return B_ERROR; 535 } 536 537 return B_OK; 538 } 539 540 541 status_t 542 FDILink::_SnbTrain(uint32 lanes) 543 { 544 CALLED(); 545 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 546 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 547 548 // Train 1 549 uint32 imrControl = Receiver().Base() + PCH_FDI_RX_IMR; 550 uint32 tmp = read32(imrControl); 551 tmp &= ~FDI_RX_SYMBOL_LOCK; 552 tmp &= ~FDI_RX_BIT_LOCK; 553 write32(imrControl, tmp); 554 read32(imrControl); 555 spin(150); 556 557 tmp = read32(txControl); 558 tmp &= ~FDI_DP_PORT_WIDTH_MASK; 559 tmp |= FDI_DP_PORT_WIDTH(lanes); 560 tmp &= ~FDI_LINK_TRAIN_NONE; 561 tmp |= FDI_LINK_TRAIN_PATTERN_1; 562 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 563 564 tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; 565 write32(txControl, tmp); 566 567 write32(Receiver().Base() + PCH_FDI_RX_MISC, 568 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); 569 570 tmp = read32(rxControl); 571 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 572 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 573 tmp |= FDI_LINK_TRAIN_PATTERN_1_CPT; 574 } else { 575 tmp &= ~FDI_LINK_TRAIN_NONE; 576 tmp |= FDI_LINK_TRAIN_PATTERN_1; 577 } 578 write32(rxControl, tmp); 579 Receiver().Enable(); 580 581 uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; 582 TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); 583 584 int i = 0; 585 for (i = 0; i < 4; i++) { 586 tmp = read32(txControl); 587 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 588 tmp |= gSnbBFDITrainParam[i]; 589 write32(txControl, tmp); 590 591 read32(txControl); 592 spin(500); 593 594 int retry = 0; 595 for (retry = 0; retry < 5; retry++) { 596 tmp = read32(iirControl); 597 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 598 if (tmp & FDI_RX_BIT_LOCK) { 599 TRACE("%s: FDI train 1 done\n", __func__); 600 write32(iirControl, tmp | FDI_RX_BIT_LOCK); 601 break; 602 } 603 spin(50); 604 } 605 if (retry < 5) 606 break; 607 } 608 609 if (i == 4) { 610 ERROR("%s: FDI train 1 failure!\n", __func__); 611 return B_ERROR; 612 } 613 614 // Train 2 615 tmp = read32(txControl); 616 tmp &= ~FDI_LINK_TRAIN_NONE; 617 tmp |= FDI_LINK_TRAIN_PATTERN_2; 618 619 // if gen6? It's always gen6 620 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 621 tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; 622 write32(txControl, tmp); 623 624 tmp = read32(rxControl); 625 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 626 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 627 tmp |= FDI_LINK_TRAIN_PATTERN_2_CPT; 628 } else { 629 tmp &= ~FDI_LINK_TRAIN_NONE; 630 tmp |= FDI_LINK_TRAIN_PATTERN_2; 631 } 632 write32(rxControl, tmp); 633 634 read32(rxControl); 635 spin(150); 636 637 for (i = 0; i < 4; i++) { 638 tmp = read32(txControl); 639 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 640 tmp |= gSnbBFDITrainParam[i]; 641 write32(txControl, tmp); 642 643 read32(txControl); 644 spin(500); 645 646 int retry = 0; 647 for (retry = 0; retry < 5; retry++) { 648 tmp = read32(iirControl); 649 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 650 651 if (tmp & FDI_RX_SYMBOL_LOCK) { 652 TRACE("%s: FDI train 2 done\n", __func__); 653 write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); 654 break; 655 } 656 spin(50); 657 } 658 if (retry < 5) 659 break; 660 } 661 662 if (i == 4) { 663 ERROR("%s: FDI train 1 failure!\n", __func__); 664 return B_ERROR; 665 } 666 667 return B_OK; 668 } 669 670 671 status_t 672 FDILink::_ManualTrain(uint32 lanes) 673 { 674 CALLED(); 675 //uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 676 //uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 677 678 ERROR("%s: TODO\n", __func__); 679 680 return B_ERROR; 681 } 682 683 684 status_t 685 FDILink::_AutoTrain(uint32 lanes) 686 { 687 CALLED(); 688 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 689 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 690 691 uint32 buffer = read32(txControl); 692 693 // Clear port width selection and set number of lanes 694 // fixme: does not belong in the train routines (?), (now) sits in FDI EnablePLL() routines 695 buffer &= ~(7 << 19); 696 buffer |= (lanes - 1) << 19; 697 698 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) 699 buffer &= ~FDI_LINK_TRAIN_NONE_IVB; 700 else 701 buffer &= ~FDI_LINK_TRAIN_NONE; 702 write32(txControl, buffer); 703 704 write32(Receiver().Base() + PCH_FDI_RX_MISC, 705 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); 706 707 bool trained = false; 708 709 for (uint32 i = 0; i < (sizeof(gSnbBFDITrainParam) 710 / sizeof(gSnbBFDITrainParam[0])); i++) { 711 for (int j = 0; j < 2; j++) { 712 buffer = read32(txControl); 713 buffer |= FDI_AUTO_TRAINING; 714 buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 715 buffer |= gSnbBFDITrainParam[i]; 716 write32(txControl, buffer | FDI_TX_ENABLE); 717 read32(txControl); 718 write32(rxControl, read32(rxControl) | FDI_RX_ENABLE); 719 read32(rxControl); 720 721 spin(50);//looks like datasheet specified 5uS is not enough..? 722 723 buffer = read32(txControl); 724 if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) { 725 TRACE("%s: FDI auto train complete!\n", __func__); 726 trained = true; 727 break; 728 } 729 730 write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); 731 read32(txControl); 732 write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); 733 read32(rxControl); 734 735 spin(31); 736 } 737 738 // If Trained, we fall out of autotraining 739 if (trained) 740 break; 741 } 742 743 if (!trained) { 744 ERROR("%s: FDI auto train failed!\n", __func__); 745 return B_ERROR; 746 } 747 748 // Enable ecc on IVB (and disable test pattern at sending and receiving end) 749 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 750 write32(rxControl, read32(rxControl) 751 | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); 752 read32(rxControl); 753 //enable normal pixels (kill testpattern) 754 write32(txControl, read32(txControl) | (0x3 << 8)); 755 read32(txControl); 756 } 757 758 return B_OK; 759 } 760 761 762 FDILink::~FDILink() 763 { 764 } 765