1 /* 2 * Copyright 2011, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexander von Gluck IV, kallisti5@unixzen.com 7 */ 8 9 10 #include "displayport.h" 11 12 #include <Debug.h> 13 14 #include "accelerant_protos.h" 15 #include "connector.h" 16 #include "mode.h" 17 18 19 #undef TRACE 20 21 #define TRACE_DP 22 #ifdef TRACE_DP 23 # define TRACE(x...) _sPrintf("radeon_hd: " x) 24 #else 25 # define TRACE(x...) ; 26 #endif 27 28 #define ERROR(x...) _sPrintf("radeon_hd: " x) 29 30 31 static int 32 dp_aux_speak(uint32 hwPin, uint8* send, int sendBytes, 33 uint8* recv, int recvBytes, uint8 delay, uint8* ack) 34 { 35 if (hwPin == 0) { 36 ERROR("%s: cannot speak on invalid GPIO pin!\n", __func__); 37 return B_IO_ERROR; 38 } 39 40 int index = GetIndexIntoMasterTable(COMMAND, ProcessAuxChannelTransaction); 41 42 // Build AtomBIOS Transaction 43 union auxChannelTransaction { 44 PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1; 45 PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2; 46 }; 47 union auxChannelTransaction args; 48 memset(&args, 0, sizeof(args)); 49 50 args.v1.lpAuxRequest = 0; 51 args.v1.lpDataOut = 16; 52 args.v1.ucDataOutLen = 0; 53 args.v1.ucChannelID = hwPin; 54 args.v1.ucDelay = delay / 10; 55 56 //if (ASIC_IS_DCE4(rdev)) 57 // args.v2.ucHPD_ID = chan->rec.hpd; 58 59 unsigned char* base = (unsigned char*)gAtomContext->scratch; 60 memcpy(base, send, sendBytes); 61 62 atom_execute_table(gAtomContext, index, (uint32*)&args); 63 64 *ack = args.v1.ucReplyStatus; 65 66 switch (args.v1.ucReplyStatus) { 67 case 1: 68 ERROR("%s: dp_aux_ch timeout!\n", __func__); 69 return B_TIMED_OUT; 70 case 2: 71 ERROR("%s: dp_aux_ch flags not zero!\n", __func__); 72 return B_BUSY; 73 case 3: 74 ERROR("%s: dp_aux_ch error!\n", __func__); 75 return B_IO_ERROR; 76 } 77 78 int recvLength = args.v1.ucDataOutLen; 79 if (recvLength > recvBytes) 80 recvLength = recvBytes; 81 82 if (recv && recvBytes) 83 memcpy(recv, base + 16, recvLength); 84 85 return recvLength; 86 } 87 88 89 int 90 dp_aux_write(uint32 hwPin, uint16 address, 91 uint8* send, uint8 sendBytes, uint8 delay) 92 { 93 uint8 auxMessage[20]; 94 int auxMessageBytes = sendBytes + 4; 95 96 if (sendBytes > 16) 97 return -1; 98 99 auxMessage[0] = address; 100 auxMessage[1] = address >> 8; 101 auxMessage[2] = AUX_NATIVE_WRITE << 4; 102 auxMessage[3] = (auxMessageBytes << 4) | (sendBytes - 1); 103 memcpy(&auxMessage[4], send, sendBytes); 104 105 uint8 retry; 106 for (retry = 0; retry < 4; retry++) { 107 uint8 ack; 108 int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, 109 NULL, 0, delay, &ack); 110 111 if (result == B_BUSY) 112 continue; 113 else if (result < B_OK) 114 return result; 115 116 if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) 117 return sendBytes; 118 else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) 119 snooze(400); 120 else 121 return B_IO_ERROR; 122 } 123 124 return B_IO_ERROR; 125 } 126 127 128 int 129 dp_aux_read(uint32 hwPin, uint16 address, 130 uint8* recv, int recvBytes, uint8 delay) 131 { 132 uint8 auxMessage[4]; 133 int auxMessageBytes = 4; 134 135 auxMessage[0] = address; 136 auxMessage[1] = address >> 8; 137 auxMessage[2] = AUX_NATIVE_READ << 4; 138 auxMessage[3] = (auxMessageBytes << 4) | (recvBytes - 1); 139 140 uint8 retry; 141 for (retry = 0; retry < 4; retry++) { 142 uint8 ack; 143 int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, 144 recv, recvBytes, delay, &ack); 145 146 if (result == B_BUSY) 147 continue; 148 else if (result < B_OK) 149 return result; 150 151 if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) 152 return result; 153 else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER) 154 snooze(400); 155 else 156 return B_IO_ERROR; 157 } 158 159 return B_IO_ERROR; 160 } 161 162 163 void 164 dpcd_reg_write(uint32 hwPin, uint16 address, uint8 value) 165 { 166 dp_aux_write(hwPin, address, &value, 1, 0); 167 } 168 169 170 uint8 171 dpcd_reg_read(uint32 hwPin, uint16 address) 172 { 173 uint8 value = 0; 174 dp_aux_read(hwPin, address, &value, 1, 0); 175 176 return value; 177 } 178 179 180 status_t 181 dp_aux_get_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) 182 { 183 uint8 auxMessage[5]; 184 int auxMessageBytes = 4; // 4 for read 185 186 /* Set up the command byte */ 187 auxMessage[2] = AUX_I2C_READ << 4; 188 if (end == false) 189 auxMessage[2] |= AUX_I2C_MOT << 4; 190 191 auxMessage[0] = address; 192 auxMessage[1] = address >> 8; 193 194 auxMessage[3] = auxMessageBytes << 4; 195 196 int retry; 197 for (retry = 0; retry < 4; retry++) { 198 uint8 ack; 199 uint8 reply[2]; 200 int replyBytes = 1; 201 202 int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, 203 reply, replyBytes, 0, &ack); 204 if (result == B_BUSY) 205 continue; 206 else if (result < 0) { 207 ERROR("%s: aux_ch failed: %d\n", __func__, result); 208 return B_ERROR; 209 } 210 211 switch (ack & AUX_NATIVE_REPLY_MASK) { 212 case AUX_NATIVE_REPLY_ACK: 213 // I2C-over-AUX Reply field is only valid for AUX_ACK 214 break; 215 case AUX_NATIVE_REPLY_NACK: 216 TRACE("%s: aux_ch native nack\n", __func__); 217 return B_IO_ERROR; 218 case AUX_NATIVE_REPLY_DEFER: 219 TRACE("%s: aux_ch native defer\n", __func__); 220 snooze(400); 221 continue; 222 default: 223 TRACE("%s: aux_ch invalid native reply: 0x%02x\n", 224 __func__, ack); 225 return B_ERROR; 226 } 227 228 switch (ack & AUX_I2C_REPLY_MASK) { 229 case AUX_I2C_REPLY_ACK: 230 *data = reply[0]; 231 return B_OK; 232 case AUX_I2C_REPLY_NACK: 233 TRACE("%s: aux_i2c nack\n", __func__); 234 return B_IO_ERROR; 235 case AUX_I2C_REPLY_DEFER: 236 TRACE("%s: aux_i2c defer\n", __func__); 237 snooze(400); 238 break; 239 default: 240 TRACE("%s: aux_i2c invalid native reply: 0x%02x\n", 241 __func__, ack); 242 return B_ERROR; 243 } 244 } 245 246 TRACE("%s: aux i2c too many retries, giving up.\n", __func__); 247 return B_ERROR; 248 } 249 250 251 status_t 252 dp_aux_set_i2c_byte(uint32 hwPin, uint16 address, uint8* data, bool end) 253 { 254 uint8 auxMessage[5]; 255 int auxMessageBytes = 5; // 5 for write 256 257 /* Set up the command byte */ 258 auxMessage[2] = AUX_I2C_WRITE << 4; 259 if (end == false) 260 auxMessage[2] |= AUX_I2C_MOT << 4; 261 262 auxMessage[0] = address; 263 auxMessage[1] = address >> 8; 264 265 auxMessage[3] = auxMessageBytes << 4; 266 auxMessage[4] = *data; 267 268 int retry; 269 for (retry = 0; retry < 4; retry++) { 270 uint8 ack; 271 uint8 reply[2]; 272 int replyBytes = 1; 273 274 int result = dp_aux_speak(hwPin, auxMessage, auxMessageBytes, 275 reply, replyBytes, 0, &ack); 276 if (result == B_BUSY) 277 continue; 278 else if (result < 0) { 279 ERROR("%s: aux_ch failed: %d\n", __func__, result); 280 return B_ERROR; 281 } 282 283 switch (ack & AUX_NATIVE_REPLY_MASK) { 284 case AUX_NATIVE_REPLY_ACK: 285 // I2C-over-AUX Reply field is only valid for AUX_ACK 286 break; 287 case AUX_NATIVE_REPLY_NACK: 288 TRACE("%s: aux_ch native nack\n", __func__); 289 return B_IO_ERROR; 290 case AUX_NATIVE_REPLY_DEFER: 291 TRACE("%s: aux_ch native defer\n", __func__); 292 snooze(400); 293 continue; 294 default: 295 TRACE("%s: aux_ch invalid native reply: 0x%02x\n", 296 __func__, ack); 297 return B_ERROR; 298 } 299 300 switch (ack & AUX_I2C_REPLY_MASK) { 301 case AUX_I2C_REPLY_ACK: 302 // Success! 303 return B_OK; 304 case AUX_I2C_REPLY_NACK: 305 TRACE("%s: aux_i2c nack\n", __func__); 306 return B_IO_ERROR; 307 case AUX_I2C_REPLY_DEFER: 308 TRACE("%s: aux_i2c defer\n", __func__); 309 snooze(400); 310 break; 311 default: 312 TRACE("%s: aux_i2c invalid native reply: 0x%02x\n", 313 __func__, ack); 314 return B_ERROR; 315 } 316 } 317 318 TRACE("%s: aux i2c too many retries, giving up.\n", __func__); 319 return B_OK; 320 } 321 322 323 uint32 324 dp_get_lane_count(uint32 connectorIndex, display_mode* mode) 325 { 326 // Radeon specific 327 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; 328 329 size_t pixelChunk; 330 size_t pixelsPerChunk; 331 status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk, 332 NULL, &pixelsPerChunk); 333 334 if (result != B_OK) { 335 TRACE("%s: Invalid color space!\n", __func__); 336 return 0; 337 } 338 339 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8; 340 341 uint32 dpMaxLinkRate = dp_get_link_rate_max(dpInfo); 342 uint32 dpMaxLaneCount = dp_get_lane_count_max(dpInfo); 343 344 uint32 lane; 345 for (lane = 1; lane < dpMaxLaneCount; lane <<= 1) { 346 uint32 maxPixelClock = dp_get_pixel_clock_max(dpMaxLinkRate, lane, 347 bitsPerPixel); 348 if (mode->timing.pixel_clock <= maxPixelClock) 349 break; 350 } 351 352 TRACE("%s: Lanes: %" B_PRIu32 "\n", __func__, lane); 353 return lane; 354 } 355 356 357 uint32 358 dp_get_link_rate(uint32 connectorIndex, display_mode* mode) 359 { 360 uint16 encoderID = gConnector[connectorIndex]->encoderExternal.objectID; 361 362 if (encoderID == ENCODER_OBJECT_ID_NUTMEG) 363 return 270000; 364 365 dp_info* dpInfo = &gConnector[connectorIndex]->dpInfo; 366 uint32 laneCount = dp_get_lane_count(connectorIndex, mode); 367 368 size_t pixelChunk; 369 size_t pixelsPerChunk; 370 status_t result = get_pixel_size_for((color_space)mode->space, &pixelChunk, 371 NULL, &pixelsPerChunk); 372 373 if (result != B_OK) { 374 TRACE("%s: Invalid color space!\n", __func__); 375 return 0; 376 } 377 378 uint32 bitsPerPixel = (pixelChunk / pixelsPerChunk) * 8; 379 380 uint32 maxPixelClock 381 = dp_get_pixel_clock_max(162000, laneCount, bitsPerPixel); 382 if (mode->timing.pixel_clock <= maxPixelClock) 383 return 162000; 384 385 maxPixelClock = dp_get_pixel_clock_max(270000, laneCount, bitsPerPixel); 386 if (mode->timing.pixel_clock <= maxPixelClock) 387 return 270000; 388 389 // TODO: DisplayPort 1.2 390 #if 0 391 if (is_dp12_capable(connectorIndex)) { 392 maxPixelClock = dp_get_pixel_clock_max(540000, laneCount, bitsPerPixel); 393 if (mode->timing.pixel_clock <= maxPixelClock) 394 return 540000; 395 } 396 #endif 397 398 return dp_get_link_rate_max(dpInfo); 399 } 400 401 402 void 403 dp_setup_connectors() 404 { 405 TRACE("%s\n", __func__); 406 407 for (uint32 index = 0; index < ATOM_MAX_SUPPORTED_DEVICE; index++) { 408 dp_info* dpInfo = &gConnector[index]->dpInfo; 409 dpInfo->valid = false; 410 if (gConnector[index]->valid == false) { 411 dpInfo->config[0] = 0; 412 continue; 413 } 414 415 if (connector_is_dp(index) == false) { 416 dpInfo->config[0] = 0; 417 continue; 418 } 419 420 uint32 gpioID = gConnector[index]->gpioID; 421 422 uint32 auxPin = gGPIOInfo[gpioID]->hwPin; 423 dpInfo->auxPin = auxPin; 424 425 uint8 auxMessage[25]; 426 int result; 427 428 result = dp_aux_read(auxPin, DP_DPCD_REV, auxMessage, 8, 0); 429 if (result > 0) { 430 dpInfo->valid = true; 431 memcpy(dpInfo->config, auxMessage, 8); 432 } 433 } 434 } 435 436 437 static bool 438 dp_get_link_status(dp_info* dp) 439 { 440 int result = dp_aux_read(dp->auxPin, DP_LANE_STATUS_0_1, 441 dp->linkStatus, DP_LINK_STATUS_SIZE, 100); 442 443 if (result <= 0) { 444 ERROR("%s: DisplayPort link status failed\n", __func__); 445 return false; 446 } 447 448 return true; 449 } 450 451 452 static uint8 453 dp_get_lane_status(dp_info* dp, int lane) 454 { 455 int i = DP_LANE_STATUS_0_1 + (lane >> 1); 456 int s = (lane & 1) * 4; 457 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 458 return (l >> s) & 0xf; 459 } 460 461 462 static bool 463 dp_clock_recovery_ok(dp_info* dp) 464 { 465 int lane; 466 uint8 laneStatus; 467 468 for (lane = 0; lane < dp->laneCount; lane++) { 469 laneStatus = dp_get_lane_status(dp, lane); 470 if ((laneStatus & DP_LANE_STATUS_CR_DONE_A) == 0) 471 return false; 472 } 473 return true; 474 } 475 476 477 static bool 478 dp_clock_equalization_ok(dp_info* dp) 479 { 480 uint8 laneAlignment 481 = dp->linkStatus[DP_LANE_ALIGN - DP_LANE_STATUS_0_1]; 482 483 if ((laneAlignment & DP_LANE_ALIGN_DONE) == 0) 484 return false; 485 486 int lane; 487 for (lane = 0; lane < dp->laneCount; lane++) { 488 uint8 laneStatus = dp_get_lane_status(dp, lane); 489 if ((laneStatus & DP_LANE_STATUS_EQUALIZED_A) 490 != DP_LANE_STATUS_EQUALIZED_A) { 491 return false; 492 } 493 } 494 return true; 495 } 496 497 498 static void 499 dp_update_vs_emph(uint32 connectorIndex) 500 { 501 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 502 503 // Set initial vs and emph on source 504 transmitter_dig_setup(connectorIndex, dp->linkRate, 0, 505 dp->trainingSet[0], ATOM_TRANSMITTER_ACTION_SETUP_VSEMPH); 506 507 // Set vs and emph on the sink 508 dp_aux_write(dp->auxPin, DP_TRAIN_LANE0, 509 dp->trainingSet, dp->laneCount, 0); 510 } 511 512 513 static uint8 514 dp_get_adjust_request_voltage(dp_info* dp, int lane) 515 { 516 int i = DP_ADJ_REQUEST_0_1 + (lane >> 1); 517 int s = (((lane & 1) != 0) ? DP_ADJ_VCC_SWING_LANEB_SHIFT 518 : DP_ADJ_VCC_SWING_LANEA_SHIFT); 519 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 520 521 return ((l >> s) & 0x3) << DP_TRAIN_VCC_SWING_SHIFT; 522 } 523 524 525 static uint8 526 dp_get_adjust_request_pre_emphasis(dp_info* dp, int lane) 527 { 528 int i = DP_ADJ_REQUEST_0_1 + (lane >> 1); 529 int s = (((lane & 1) != 0) ? DP_ADJ_PRE_EMPHASIS_LANEB_SHIFT 530 : DP_ADJ_PRE_EMPHASIS_LANEA_SHIFT); 531 uint8 l = dp->linkStatus[i - DP_LANE_STATUS_0_1]; 532 533 return ((l >> s) & 0x3) << DP_TRAIN_PRE_EMPHASIS_SHIFT; 534 } 535 536 537 static void 538 dp_get_adjust_train(dp_info* dp) 539 { 540 TRACE("%s\n", __func__); 541 542 const char* voltageNames[] = { 543 "0.4V", "0.6V", "0.8V", "1.2V" 544 }; 545 const char* preEmphasisNames[] = { 546 "0dB", "3.5dB", "6dB", "9.5dB" 547 }; 548 549 uint8 voltage = 0; 550 uint8 preEmphasis = 0; 551 int lane; 552 553 for (lane = 0; lane < dp->laneCount; lane++) { 554 uint8 laneVoltage = dp_get_adjust_request_voltage(dp, lane); 555 uint8 lanePreEmphasis = dp_get_adjust_request_pre_emphasis(dp, lane); 556 557 TRACE("%s: Requested %s at %s for lane %d\n", __func__, 558 preEmphasisNames[lanePreEmphasis >> DP_TRAIN_PRE_EMPHASIS_SHIFT], 559 voltageNames[laneVoltage >> DP_TRAIN_VCC_SWING_SHIFT], 560 lane); 561 562 if (laneVoltage > voltage) 563 voltage = laneVoltage; 564 if (lanePreEmphasis > preEmphasis) 565 preEmphasis = lanePreEmphasis; 566 } 567 568 // Check for maximum voltage and toggle max if reached 569 if (voltage >= DP_TRAIN_VCC_SWING_1200) 570 voltage |= DP_TRAIN_MAX_SWING_EN; 571 572 // Check for maximum pre-emphasis and toggle max if reached 573 if (preEmphasis >= DP_TRAIN_PRE_EMPHASIS_9_5) 574 preEmphasis |= DP_TRAIN_MAX_EMPHASIS_EN; 575 576 for (lane = 0; lane < 4; lane++) 577 dp->trainingSet[lane] = voltage | preEmphasis; 578 } 579 580 581 static void 582 dp_set_tp(uint32 connectorIndex, int trainingPattern) 583 { 584 TRACE("%s\n", __func__); 585 586 radeon_shared_info &info = *gInfo->shared_info; 587 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 588 589 int rawTrainingPattern = 0; 590 591 /* set training pattern on the source */ 592 if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { 593 switch (trainingPattern) { 594 case DP_TRAIN_PATTERN_1: 595 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1; 596 break; 597 case DP_TRAIN_PATTERN_2: 598 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2; 599 break; 600 case DP_TRAIN_PATTERN_3: 601 rawTrainingPattern = ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3; 602 break; 603 } 604 // TODO: PixelClock 0 ok? 605 encoder_dig_setup(connectorIndex, 0, rawTrainingPattern); 606 } else { 607 ERROR("%s: TODO: dp_encoder_service\n", __func__); 608 return; 609 #if 0 610 switch (trainingPattern) { 611 case DP_TRAINING_PATTERN_1: 612 rawTrainingPattern = 0; 613 break; 614 case DP_TRAINING_PATTERN_2: 615 rawTrainingPattern = 1; 616 break; 617 } 618 radeon_dp_encoder_service(dp_info->rdev, 619 ATOM_DP_ACTION_TRAINING_PATTERN_SEL, dp_info->dp_clock, 620 dp_info->enc_id, rawTrainingPattern); 621 #endif 622 } 623 624 // Enable training pattern on the sink 625 dpcd_reg_write(dp->auxPin, DP_TRAIN, trainingPattern); 626 } 627 628 629 status_t 630 dp_link_train_cr(uint32 connectorIndex) 631 { 632 TRACE("%s\n", __func__); 633 634 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 635 636 // Display Port Clock Recovery Training 637 638 bool clockRecovery = false; 639 uint8 voltage = 0xff; 640 int lane; 641 642 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_1); 643 memset(dp->trainingSet, 0, 4); 644 dp_update_vs_emph(connectorIndex); 645 646 while (1) { 647 if (dp->trainingReadInterval == 0) 648 snooze(100); 649 else 650 snooze(1000 * 4 * dp->trainingReadInterval); 651 652 if (!dp_get_link_status(dp)) 653 break; 654 655 if (dp_clock_recovery_ok(dp)) { 656 clockRecovery = true; 657 break; 658 } 659 660 for (lane = 0; lane < dp->laneCount; lane++) { 661 if ((dp->trainingSet[lane] & DP_TRAIN_MAX_SWING_EN) == 0) 662 break; 663 } 664 665 if (lane == dp->laneCount) { 666 ERROR("%s: clock recovery reached max voltage\n", __func__); 667 break; 668 } 669 670 if ((dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK) == voltage) { 671 dp->trainingAttempts++; 672 if (dp->trainingAttempts >= 5) { 673 ERROR("%s: clock recovery tried 5 times\n", __func__); 674 break; 675 } 676 } else 677 dp->trainingAttempts = 0; 678 679 voltage = dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK; 680 681 // Compute new trainingSet as requested by sink 682 dp_get_adjust_train(dp); 683 684 dp_update_vs_emph(connectorIndex); 685 } 686 687 if (!clockRecovery) { 688 ERROR("%s: clock recovery failed\n", __func__); 689 return B_ERROR; 690 } 691 692 TRACE("%s: clock recovery at voltage %d pre-emphasis %d\n", 693 __func__, dp->trainingSet[0] & DP_TRAIN_VCC_SWING_MASK, 694 (dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK) 695 >> DP_TRAIN_PRE_EMPHASIS_SHIFT); 696 return B_OK; 697 } 698 699 700 status_t 701 dp_link_train_ce(uint32 connectorIndex) 702 { 703 TRACE("%s\n", __func__); 704 705 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 706 707 // TODO: DisplayPort: Supports TP3? 708 dp_set_tp(connectorIndex, DP_TRAIN_PATTERN_2); 709 710 dp->trainingAttempts = 0; 711 bool channelEqual = false; 712 713 while (1) { 714 if (dp->trainingReadInterval == 0) 715 snooze(100); 716 else 717 snooze(1000 * 4 * dp->trainingReadInterval); 718 719 if (!dp_get_link_status(dp)) 720 break; 721 722 if (dp_clock_equalization_ok(dp)) { 723 channelEqual = true; 724 break; 725 } 726 727 if (dp->trainingAttempts > 5) { 728 ERROR("%s: ERROR: failed > 5 times!\n", __func__); 729 break; 730 } 731 732 dp_get_adjust_train(dp); 733 734 dp_update_vs_emph(connectorIndex); 735 dp->trainingAttempts++; 736 } 737 738 if (!channelEqual) { 739 ERROR("%s: ERROR: failed\n", __func__); 740 return B_ERROR; 741 } 742 743 TRACE("%s: channels equalized at voltage %d pre-emphasis %d\n", 744 __func__, dp->trainingSet[0] & DP_ADJ_VCC_SWING_LANEA_MASK, 745 (dp->trainingSet[0] & DP_TRAIN_PRE_EMPHASIS_MASK) 746 >> DP_TRAIN_PRE_EMPHASIS_SHIFT); 747 748 return B_OK; 749 } 750 751 752 status_t 753 dp_link_train(uint32 connectorIndex, display_mode* mode) 754 { 755 TRACE("%s\n", __func__); 756 757 dp_info* dp = &gConnector[connectorIndex]->dpInfo; 758 759 if (dp->valid != true) { 760 ERROR("%s: started on invalid DisplayPort connector #%" B_PRIu32 "\n", 761 __func__, connectorIndex); 762 return B_ERROR; 763 } 764 765 int index = GetIndexIntoMasterTable(COMMAND, DPEncoderService); 766 // Table version 767 uint8 tableMajor; 768 uint8 tableMinor; 769 770 dp->trainingUseEncoder = true; 771 if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor) 772 == B_OK) { 773 if (tableMinor > 1) { 774 // The AtomBIOS DPEncoderService greater then 1.1 can't program the 775 // training pattern properly. 776 dp->trainingUseEncoder = false; 777 } 778 } 779 780 uint32 linkEnumeration 781 = gConnector[connectorIndex]->encoder.linkEnumeration; 782 uint32 gpioID = gConnector[connectorIndex]->gpioID; 783 uint32 hwPin = gGPIOInfo[gpioID]->hwPin; 784 785 uint32 dpEncoderID = 0; 786 if (encoder_pick_dig(connectorIndex) > 0) 787 dpEncoderID |= ATOM_DP_CONFIG_DIG2_ENCODER; 788 else 789 dpEncoderID |= ATOM_DP_CONFIG_DIG1_ENCODER; 790 if (linkEnumeration == GRAPH_OBJECT_ENUM_ID2) 791 dpEncoderID |= ATOM_DP_CONFIG_LINK_B; 792 else 793 dpEncoderID |= ATOM_DP_CONFIG_LINK_A; 794 795 dp->trainingReadInterval 796 = dpcd_reg_read(hwPin, DP_TRAINING_AUX_RD_INTERVAL); 797 798 uint8 sandbox = dpcd_reg_read(hwPin, DP_MAX_LANE_COUNT); 799 800 radeon_shared_info &info = *gInfo->shared_info; 801 //bool dpTPS3Supported = false; 802 //if (info.dceMajor >= 5 && (sandbox & DP_TPS3_SUPPORTED) != 0) 803 // dpTPS3Supported = true; 804 805 // *** DisplayPort link training initialization 806 807 // Power up the DP sink 808 if (dp->config[0] >= DP_DPCD_REV_11) 809 dpcd_reg_write(hwPin, DP_SET_POWER, DP_SET_POWER_D0); 810 811 // Possibly enable downspread on the sink 812 if ((dp->config[3] & 0x1) != 0) 813 dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, DP_DOWNSPREAD_CTRL_AMP_EN); 814 else 815 dpcd_reg_write(hwPin, DP_DOWNSPREAD_CTRL, 0); 816 817 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 818 ATOM_ENCODER_CMD_SETUP_PANEL_MODE); 819 820 if (dp->config[0] >= DP_DPCD_REV_11) 821 sandbox |= DP_ENHANCED_FRAME_EN; 822 dpcd_reg_write(hwPin, DP_LANE_COUNT, sandbox); 823 824 // Set the link rate on the DP sink 825 sandbox = dp_encode_link_rate(dp->linkRate); 826 dpcd_reg_write(hwPin, DP_LINK_RATE, sandbox); 827 828 // Start link training on source 829 if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { 830 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 831 ATOM_ENCODER_CMD_DP_LINK_TRAINING_START); 832 } else { 833 ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n", 834 __func__); 835 } 836 837 // Disable the training pattern on the sink 838 dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); 839 840 dp_link_train_cr(connectorIndex); 841 dp_link_train_ce(connectorIndex); 842 843 // *** DisplayPort link training finish 844 snooze(400); 845 846 // Disable the training pattern on the sink 847 dpcd_reg_write(hwPin, DP_TRAIN, DP_TRAIN_PATTERN_DISABLED); 848 849 // Disable the training pattern on the source 850 if (info.dceMajor >= 4 || !dp->trainingUseEncoder) { 851 encoder_dig_setup(connectorIndex, mode->timing.pixel_clock, 852 ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE); 853 } else { 854 ERROR("%s: TODO: cannot use AtomBIOS DPEncoderService on card!\n", 855 __func__); 856 } 857 858 return B_OK; 859 } 860 861 862 void 863 debug_dp_info() 864 { 865 ERROR("Current DisplayPort Info =================\n"); 866 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 867 if (gConnector[id]->valid == true) { 868 dp_info* dp = &gConnector[id]->dpInfo; 869 ERROR("Connector #%" B_PRIu32 ") DP: %s\n", id, 870 dp->valid ? "true" : "false"); 871 872 if (!dp->valid) 873 continue; 874 ERROR(" + DP Config Data\n"); 875 ERROR(" - max lane count: %d\n", 876 dp->config[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK); 877 ERROR(" - max link rate: %d\n", 878 dp->config[DP_MAX_LINK_RATE]); 879 ERROR(" - receiver port count: %d\n", 880 dp->config[DP_NORP] & DP_NORP_MASK); 881 ERROR(" - downstream port present: %s\n", 882 (dp->config[DP_DOWNSTREAMPORT] & DP_DOWNSTREAMPORT_EN) 883 ? "yes" : "no"); 884 ERROR(" - downstream port count: %d\n", 885 dp->config[DP_DOWNSTREAMPORT_COUNT] 886 & DP_DOWNSTREAMPORT_COUNT_MASK); 887 ERROR(" + Training\n"); 888 ERROR(" - use encoder: %s\n", 889 dp->trainingUseEncoder ? "true" : "false"); 890 ERROR(" - attempts: %" B_PRIu8 "\n", 891 dp->trainingAttempts); 892 ERROR(" - delay: %d\n", 893 dp->trainingReadInterval); 894 ERROR(" + Data\n"); 895 ERROR(" - auxPin: 0x%" B_PRIX32"\n", dp->auxPin); 896 ERROR(" + Video\n"); 897 ERROR(" - laneCount: %d\n", dp->laneCount); 898 ERROR(" - linkRate: %" B_PRIu32 "\n", 899 dp->linkRate); 900 } 901 } 902 ERROR("==========================================\n"); 903 } 904