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