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::PreTrain(display_timing* target, uint32* linkBandwidth, uint32* lanes, uint32* bitsPerPixel) 254 { 255 CALLED(); 256 257 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 258 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 259 260 //Link bit depth: this should be globally known per FDI link (i.e. laptop panel 3x6, rest 3x8) 261 *bitsPerPixel = ((read32(rxControl) & FDI_RX_LINK_BPC_MASK) >> FDI_RX_LINK_COLOR_SHIFT); 262 switch (*bitsPerPixel) { 263 case INTEL_PIPE_8BPC: 264 *bitsPerPixel = 24; 265 break; 266 case INTEL_PIPE_10BPC: 267 *bitsPerPixel = 30; 268 break; 269 case INTEL_PIPE_6BPC: 270 *bitsPerPixel = 18; 271 break; 272 case INTEL_PIPE_12BPC: 273 *bitsPerPixel = 36; 274 break; 275 default: 276 *bitsPerPixel = 0; 277 ERROR("%s: FDI illegal link colordepth set.\n", __func__); 278 return B_ERROR; 279 } 280 TRACE("%s: FDI Link %s:\n", __func__, (fPipeIndex == INTEL_PIPE_A) ? "A" : "B"); 281 TRACE("%s: FDI Link Colordepth: %" B_PRIu32 "\n", __func__, *bitsPerPixel); 282 283 // Khz / 10. ( each output octet encoded as 10 bits. 284 // note: if used for eDP (PORT_A) might be we should check reg. DP_CTL (0x64000), bit 16-17 (Ivy). 285 *linkBandwidth = gInfo->shared_info->fdi_link_frequency * 1000 / 10; 286 //Reserving 5% bandwidth for possible spread spectrum clock use 287 uint32 bps = target->pixel_clock * *bitsPerPixel * 21 / 20; 288 289 //use DIV_ROUND_UP: 290 *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 ERROR("%s: FDI not enough lanes in hardware.\n", __func__); 298 return B_ERROR; 299 } 300 301 TRACE("%s: FDI TX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); 302 TRACE("%s: FDI RX ctrl before: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); 303 304 #if 0 305 //when link training is to be done re-enable this code 306 307 //The order of handling things is important here.. 308 write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); 309 read32(txControl); 310 write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); 311 read32(rxControl); 312 313 write32(txControl, (read32(txControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); 314 read32(txControl); 315 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 316 write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_PATTERN_MASK_CPT) | FDI_LINK_TRAIN_PATTERN_1_CPT); 317 } else { 318 write32(rxControl, (read32(rxControl) & ~FDI_LINK_TRAIN_NONE) | FDI_LINK_TRAIN_PATTERN_1); 319 } 320 read32(rxControl); 321 spin(100); 322 323 // Disable FDI clocks 324 Receiver().SwitchClock(false); 325 Transmitter().DisablePLL(); 326 Receiver().DisablePLL(); 327 #endif 328 329 return B_OK; 330 } 331 332 333 status_t 334 FDILink::Train(display_timing* target, uint32 lanes) 335 { 336 CALLED(); 337 338 status_t result = B_OK; 339 340 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 341 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 342 343 //Set receiving end TU size bits to match sending end's setting 344 write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_1, FDI_RX_TRANS_UNIT_MASK); 345 write32(Receiver().Base() + PCH_FDI_RX_TRANS_UNIT_SIZE_2, FDI_RX_TRANS_UNIT_MASK); 346 347 #if 0 348 //when link training is to be done re-enable this code 349 // Enable FDI clocks 350 Receiver().EnablePLL(lanes); 351 Receiver().SwitchClock(true); 352 Transmitter().EnablePLL(lanes); 353 354 // TODO: Only _AutoTrain on IVYB Stepping B or later 355 // otherwise, _ManualTrain 356 if (gInfo->shared_info->device_type.Generation() >= 7) 357 result = _AutoTrain(lanes); 358 else if (gInfo->shared_info->device_type.Generation() == 6) 359 result = _SnbTrain(lanes); 360 else if (gInfo->shared_info->device_type.Generation() == 5) 361 result = _IlkTrain(lanes); 362 else 363 result = _NormalTrain(lanes); 364 #endif 365 366 TRACE("%s: FDI TX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(txControl)); 367 TRACE("%s: FDI RX ctrl after: 0x%" B_PRIx32 "\n", __func__, read32(rxControl)); 368 369 if (result != B_OK) 370 ERROR("%s: FDI training fault.\n", __func__); 371 372 return result; 373 } 374 375 376 status_t 377 FDILink::_NormalTrain(uint32 lanes) 378 { 379 CALLED(); 380 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 381 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 382 383 // Enable normal link training 384 uint32 tmp = read32(txControl); 385 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 386 tmp &= ~FDI_LINK_TRAIN_NONE_IVB; 387 tmp |= FDI_LINK_TRAIN_NONE_IVB | FDI_TX_ENHANCE_FRAME_ENABLE; 388 } else { 389 tmp &= ~FDI_LINK_TRAIN_NONE; 390 tmp |= FDI_LINK_TRAIN_NONE | FDI_TX_ENHANCE_FRAME_ENABLE; 391 } 392 write32(txControl, tmp); 393 394 tmp = read32(rxControl); 395 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 396 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 397 tmp |= FDI_LINK_TRAIN_NORMAL_CPT; 398 } else { 399 tmp &= ~FDI_LINK_TRAIN_NONE; 400 tmp |= FDI_LINK_TRAIN_NONE; 401 } 402 write32(rxControl, tmp | FDI_RX_ENHANCE_FRAME_ENABLE); 403 404 // Wait 1x idle pattern 405 read32(rxControl); 406 spin(1000); 407 408 // Enable ecc on IVB 409 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 410 write32(rxControl, read32(rxControl) 411 | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); 412 read32(rxControl); 413 } 414 415 return B_OK; 416 } 417 418 419 status_t 420 FDILink::_IlkTrain(uint32 lanes) 421 { 422 CALLED(); 423 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 424 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 425 426 // Train 1: unmask FDI RX Interrupt symbol_lock and bit_lock 427 uint32 tmp = read32(Receiver().Base() + PCH_FDI_RX_IMR); 428 tmp &= ~FDI_RX_SYMBOL_LOCK; 429 tmp &= ~FDI_RX_BIT_LOCK; 430 write32(Receiver().Base() + PCH_FDI_RX_IMR, tmp); 431 spin(150); 432 433 // Enable CPU FDI TX and RX 434 tmp = read32(txControl); 435 tmp &= ~FDI_DP_PORT_WIDTH_MASK; 436 tmp |= FDI_DP_PORT_WIDTH(lanes); 437 tmp &= ~FDI_LINK_TRAIN_NONE; 438 tmp |= FDI_LINK_TRAIN_PATTERN_1; 439 write32(txControl, tmp); 440 Transmitter().Enable(); 441 442 tmp = read32(rxControl); 443 tmp &= ~FDI_LINK_TRAIN_NONE; 444 tmp |= FDI_LINK_TRAIN_PATTERN_1; 445 write32(rxControl, tmp); 446 Receiver().Enable(); 447 448 // ILK Workaround, enable clk after FDI enable 449 if (fPipeIndex == INTEL_PIPE_B) { 450 write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); 451 write32(PCH_FDI_RXB_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR 452 | FDI_RX_PHASE_SYNC_POINTER_EN); 453 } else { 454 write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR); 455 write32(PCH_FDI_RXA_CHICKEN, FDI_RX_PHASE_SYNC_POINTER_OVR 456 | FDI_RX_PHASE_SYNC_POINTER_EN); 457 } 458 459 uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; 460 TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); 461 462 int tries = 0; 463 for (tries = 0; tries < 5; tries++) { 464 tmp = read32(iirControl); 465 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 466 467 if ((tmp & FDI_RX_BIT_LOCK)) { 468 TRACE("%s: FDI train 1 done\n", __func__); 469 write32(iirControl, tmp | FDI_RX_BIT_LOCK); 470 break; 471 } 472 } 473 474 if (tries == 5) { 475 ERROR("%s: FDI train 1 failure!\n", __func__); 476 return B_ERROR; 477 } 478 479 // Train 2 480 tmp = read32(txControl); 481 tmp &= ~FDI_LINK_TRAIN_NONE; 482 tmp |= FDI_LINK_TRAIN_PATTERN_2; 483 write32(txControl, tmp); 484 485 tmp = read32(rxControl); 486 tmp &= ~FDI_LINK_TRAIN_NONE; 487 tmp |= FDI_LINK_TRAIN_PATTERN_2; 488 write32(rxControl, tmp); 489 490 read32(rxControl); 491 spin(150); 492 493 for (tries = 0; tries < 5; tries++) { 494 tmp = read32(iirControl); 495 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 496 497 if (tmp & FDI_RX_SYMBOL_LOCK) { 498 TRACE("%s: FDI train 2 done\n", __func__); 499 write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); 500 break; 501 } 502 } 503 504 if (tries == 5) { 505 ERROR("%s: FDI train 2 failure!\n", __func__); 506 return B_ERROR; 507 } 508 509 return B_OK; 510 } 511 512 513 status_t 514 FDILink::_SnbTrain(uint32 lanes) 515 { 516 CALLED(); 517 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 518 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 519 520 // Train 1 521 uint32 imrControl = Receiver().Base() + PCH_FDI_RX_IMR; 522 uint32 tmp = read32(imrControl); 523 tmp &= ~FDI_RX_SYMBOL_LOCK; 524 tmp &= ~FDI_RX_BIT_LOCK; 525 write32(imrControl, tmp); 526 read32(imrControl); 527 spin(150); 528 529 tmp = read32(txControl); 530 tmp &= ~FDI_DP_PORT_WIDTH_MASK; 531 tmp |= FDI_DP_PORT_WIDTH(lanes); 532 tmp &= ~FDI_LINK_TRAIN_NONE; 533 tmp |= FDI_LINK_TRAIN_PATTERN_1; 534 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 535 536 tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; 537 write32(txControl, tmp); 538 539 write32(Receiver().Base() + PCH_FDI_RX_MISC, 540 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); 541 542 tmp = read32(rxControl); 543 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 544 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 545 tmp |= FDI_LINK_TRAIN_PATTERN_1_CPT; 546 } else { 547 tmp &= ~FDI_LINK_TRAIN_NONE; 548 tmp |= FDI_LINK_TRAIN_PATTERN_1; 549 } 550 write32(rxControl, tmp); 551 Receiver().Enable(); 552 553 uint32 iirControl = Receiver().Base() + PCH_FDI_RX_IIR; 554 TRACE("%s: FDI RX IIR Control @ 0x%" B_PRIx32 "\n", __func__, iirControl); 555 556 int i = 0; 557 for (i = 0; i < 4; i++) { 558 tmp = read32(txControl); 559 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 560 tmp |= gSnbBFDITrainParam[i]; 561 write32(txControl, tmp); 562 563 read32(txControl); 564 spin(500); 565 566 int retry = 0; 567 for (retry = 0; retry < 5; retry++) { 568 tmp = read32(iirControl); 569 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 570 if (tmp & FDI_RX_BIT_LOCK) { 571 TRACE("%s: FDI train 1 done\n", __func__); 572 write32(iirControl, tmp | FDI_RX_BIT_LOCK); 573 break; 574 } 575 spin(50); 576 } 577 if (retry < 5) 578 break; 579 } 580 581 if (i == 4) { 582 ERROR("%s: FDI train 1 failure!\n", __func__); 583 return B_ERROR; 584 } 585 586 // Train 2 587 tmp = read32(txControl); 588 tmp &= ~FDI_LINK_TRAIN_NONE; 589 tmp |= FDI_LINK_TRAIN_PATTERN_2; 590 591 // if gen6? It's always gen6 592 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 593 tmp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B; 594 write32(txControl, tmp); 595 596 tmp = read32(rxControl); 597 if (gInfo->shared_info->pch_info == INTEL_PCH_CPT) { 598 tmp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT; 599 tmp |= FDI_LINK_TRAIN_PATTERN_2_CPT; 600 } else { 601 tmp &= ~FDI_LINK_TRAIN_NONE; 602 tmp |= FDI_LINK_TRAIN_PATTERN_2; 603 } 604 write32(rxControl, tmp); 605 606 read32(rxControl); 607 spin(150); 608 609 for (i = 0; i < 4; i++) { 610 tmp = read32(txControl); 611 tmp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 612 tmp |= gSnbBFDITrainParam[i]; 613 write32(txControl, tmp); 614 615 read32(txControl); 616 spin(500); 617 618 int retry = 0; 619 for (retry = 0; retry < 5; retry++) { 620 tmp = read32(iirControl); 621 TRACE("%s: FDI RX IIR 0x%" B_PRIx32 "\n", __func__, tmp); 622 623 if (tmp & FDI_RX_SYMBOL_LOCK) { 624 TRACE("%s: FDI train 2 done\n", __func__); 625 write32(iirControl, tmp | FDI_RX_SYMBOL_LOCK); 626 break; 627 } 628 spin(50); 629 } 630 if (retry < 5) 631 break; 632 } 633 634 if (i == 4) { 635 ERROR("%s: FDI train 1 failure!\n", __func__); 636 return B_ERROR; 637 } 638 639 return B_OK; 640 } 641 642 643 status_t 644 FDILink::_ManualTrain(uint32 lanes) 645 { 646 CALLED(); 647 //uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 648 //uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 649 650 ERROR("%s: TODO\n", __func__); 651 652 return B_ERROR; 653 } 654 655 656 status_t 657 FDILink::_AutoTrain(uint32 lanes) 658 { 659 CALLED(); 660 uint32 txControl = Transmitter().Base() + PCH_FDI_TX_CONTROL; 661 uint32 rxControl = Receiver().Base() + PCH_FDI_RX_CONTROL; 662 663 uint32 buffer = read32(txControl); 664 665 // Clear port width selection and set number of lanes 666 // fixme: does not belong in the train routines (?), (now) sits in FDI EnablePLL() routines 667 buffer &= ~(7 << 19); 668 buffer |= (lanes - 1) << 19; 669 670 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) 671 buffer &= ~FDI_LINK_TRAIN_NONE_IVB; 672 else 673 buffer &= ~FDI_LINK_TRAIN_NONE; 674 write32(txControl, buffer); 675 676 write32(Receiver().Base() + PCH_FDI_RX_MISC, 677 FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90); 678 679 bool trained = false; 680 681 for (uint32 i = 0; i < (sizeof(gSnbBFDITrainParam) 682 / sizeof(gSnbBFDITrainParam[0])); i++) { 683 for (int j = 0; j < 2; j++) { 684 buffer = read32(txControl); 685 buffer |= FDI_AUTO_TRAINING; 686 buffer &= ~FDI_LINK_TRAIN_VOL_EMP_MASK; 687 buffer |= gSnbBFDITrainParam[i]; 688 write32(txControl, buffer | FDI_TX_ENABLE); 689 read32(txControl); 690 write32(rxControl, read32(rxControl) | FDI_RX_ENABLE); 691 read32(rxControl); 692 693 spin(50);//looks like datasheet specified 5uS is not enough..? 694 695 buffer = read32(txControl); 696 if ((buffer & FDI_AUTO_TRAIN_DONE) != 0) { 697 TRACE("%s: FDI auto train complete!\n", __func__); 698 trained = true; 699 break; 700 } 701 702 write32(txControl, read32(txControl) & ~FDI_TX_ENABLE); 703 read32(txControl); 704 write32(rxControl, read32(rxControl) & ~FDI_RX_ENABLE); 705 read32(rxControl); 706 707 spin(31); 708 } 709 710 // If Trained, we fall out of autotraining 711 if (trained) 712 break; 713 } 714 715 if (!trained) { 716 ERROR("%s: FDI auto train failed!\n", __func__); 717 return B_ERROR; 718 } 719 720 // Enable ecc on IVB (and disable test pattern at sending and receiving end) 721 if (gInfo->shared_info->device_type.InGroup(INTEL_GROUP_IVB)) { 722 write32(rxControl, read32(rxControl) 723 | FDI_FS_ERRC_ENABLE | FDI_FE_ERRC_ENABLE); 724 read32(rxControl); 725 //enable normal pixels (kill testpattern) 726 write32(txControl, read32(txControl) | (0x3 << 8)); 727 read32(txControl); 728 } 729 730 return B_OK; 731 } 732 733 734 FDILink::~FDILink() 735 { 736 } 737