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